Monday 1 December 2014

Week 13

In the past week, we learned more about countability and a little bit about induction, which will be taught more in depth in CSC236 next semester. The last assignment really helped my understanding for the asymptotic proofs. The halting problem was something I had trouble understanding at first after the lectures but after seeing the example in the notes and completing the assignment, I think I am confident that I understand the problem.

Sadly, the term is nearing an end. Is it only me that gets a little bittersweet feeling at the end of every semester? I get used to the classroom and professor and all that so it is kind of sad to have it end after you've spent so many hours together.

On a brighter note, I think I have learned the most in this course out of all of my courses this semester. I have done well so far, so hopefully I will be able to carry this momentum into the exam. The course logs at first sounded like a hassle to me, but I realized that they helped me improve my understanding and were also great for keeping up with the material. It is also the only component of any of my courses this semester that requires me to write in English (not proofs or code), so it was definitely refreshing and helped me improve my writing skills and I learned how to better express myself in words. Thank you for reading. Good luck to anyone reading who has exams and happy holidays!

Friday 28 November 2014

The Penultimate Post - A Paper Puzzle

My SLOG entry this will be my problem-solving entry. I am going to be writing about the paper folding problem we talked about back in week 3. I will try my best to follow George Pólya's steps to problem solving.

The problem statement:

Grasp one end of a strip of paper between the thumb and index finger of your right hand, and grasp the other end between the thumb and index finger of your left hand. Fold the strip of paper once, so that the end of the strip that was in your left hand now is on top of the end that was in your right hand, and the thumb and finger of your left hand now grips the fold at what was the middle. If you were to unfold the strip of paper now, it would have a single crease in a direction you might want to call "down."

If you carry out the fold several times, always folding the strip so that the end of the strip that is in the left hand is placed over the end that is in the right hand, what pattern of "up" and "down" folds do you get? For example, if I make two folds, I get a left-to-right pattern of "up," "down," "down."

Step 1: Understand the problem
The problem is to try and predict the sequence of ups and downs for a given number of times you fold a strip of paper in half. The paper should always be folded so that the end that was in your left hand is now on top of the end that was in your right hand because this will affect the results.

Step 2: Plan a solution
To solve this problem I folded the paper and wrote down the sequence for the first few folds. I then tried to see if there was a pattern in the sequence.

Step 3: Carry out your plan
Below are the sequences for the first 4 folds.

Folds Sequence
1 D
2 UDD
3 UUDDUDD
4 UUDUUDDDUUDDUDD

Using 1 fold as our base case, the formula for this sequence would be to first take the previous sequence and mirror and flip it (the sequence backwards and D's become U's and vice-versa) and then append a 'D', and then append the previous sequence to the end.

The following is my implementation using recursion in Python.

def fold_sequence(folds):
    """ (int) -> str

    Return the sequence of the folds for a number of folds.

    Parameters:
    - folds: the number of times the paper is folded in half
    """

    if folds == 1:
        return 'D'
    else:
        prev_seq = fold_sequence(folds - 1)

        # reverse the previous sequence
        prev_seq_rev = prev_seq[::-1]
        prev_seq_rev = prev_seq_rev.replace("U", "d")
        prev_seq_rev = prev_seq_rev.replace("D", "U")

        # change the U's into D's and D's into U's
        prev_seq_rev = prev_seq_rev.replace("d", "D")
        return prev_seq_rev + 'D' + prev_seq


if __name__ == '__main__':

    while True:
        num_folds = input('Enter number of folds: ')

        # Convert into int
        num_int = int(num_folds)

        if num_int >= 1:
            print(fold_sequence(num_int))

You can test out the code at the following link: http://repl.it/1nu/4

Step 4: Review any solution you achieve
I think my solution is a correct one and the program I wrote should be able to convince someone that it gives the correct output.

To further extend this problem and further convince any more skeptics, I wrote a program in Python utilizing the ImageDraw module that takes an input for the number of folds and outputs the visual representation of the folds. The following are a few examples of the outputs from the program.

1 fold

4 folds
6 folds

8 folds (Dropbox link)
10 folds (Dropbox link) Note: the original image is over 40,000 pixels long

To see the source code click here: https://pastee.org/k222h

Thank you for reading.

EDIT: I had a look around at a few other SLOGs to find some posts that others had made on this puzzle. I found a few posts here and here, and these posts all made the same solution I made so it is good to see that my solution seems to be the correct one.

Friday 21 November 2014

Week 11

So this weekend CDF was down so the course website and MarkUs could not be accessed which was inconvenient. We also got a break from classes on Monday and Tuesday which was a pleasant surprise. It was back to lectures on Wednesday where learned about the halting problem as well as countability.

I think the halting problem is the one of the most interesting topics we have learned so far. The halting problem is the problem of determining whether given a function and an input, will the function halt or continue to run forever. One would think to just run the function and if it halts then you know it will halt. The problem is that if it doesn't halt, you cannot tell if it will eventually halt or continue running forever.

I think this post here http://soohamrafizslog165.blogspot.ca/2014/11/week-11-halting-problem-and.html gave an interesting explanation and visualization for the halting problem.

Countability was also an interesting topic. A set is countable if it has a one-to-one correspondence with the set of natural numbers and it is onto the natural numbers, which means every number in that set can be reached from at least one natural number. We used this to show that the size of the set of even natural numbers is equal to the size of the set of natural numbers, which is not very intuitive. There are also some sets that are not countable. Cantor used diagonalization to show that there are infinite sets such as the set of rational numbers that are not countable.

Friday 14 November 2014

Week 10

So this week we got our second midterm back. I managed to get perfect once again so I am happy about that. In class this week, we looked at proving big O for non-polynomial functions. We used L'Hôpital's rule to help prove that 2^n was in big O of n^2. L'Hôpital's rule uses derivatives to evaluate limits and is defined as:

Two other bounds we talked about were big Omega and big theta. A function f is in big Omega of function g  (f(x) = Ω(g(x))) if it is bounded below by function g. A function f is in big theta of function g (f(x) = Θ(g(x))) if it is bounded both above and below by function g.

Another interesting thing I learned this week were some of the properties of big O.

The reflexivity property says that a function is in big O of itself, which makes sense since we can easily see that if we multiply a function by a constant, then the original function will always be less than the new function. Reflexivity also means that a function is in big Omega, as well as big theta of itself.
The transitivity property says that if function f is in big O of g and function g is in big O if h, then function f is in big O of h. We can prove this by choosing the constant to be the product of the two constants for the first two functions and the breakpoint to be the maximum of the two breakpoints for the first two functions.
That's it for this week. I have one midterm left for one of my courses and so far I have done well on them. After that it will be on to exams, something I am definitely looking forward to!

Friday 7 November 2014

Week 9

So this week we had our second midterm. I found it to be average in terms of difficulty. The last two questions were very similar to the assignment questions, (the last one was near identical), so I think as long as you went over the solutions, it was very easy to prepare and do well on this midterm. Again, I ended up using very little of what I put on my cheat sheet but I guess it served its purpose of helping me get prepared.

This week's tutorial was very helpful in clearing up some of the problems I had with counting the number of steps for the sorting algorithms. I think the way our TA explained it was easier to understand than the way explained during lecture. With the midterm over, we only have one more assignment and the final exam left, but so far I think I have learned the most from this course out of all of my courses and the methods of problem solving I learned from this course can be carried over into my future courses.

One of the more interesting SLOGs I have found so far is here http://www.reddit.com/r/journeythrough165/. I think I find blogs that aren't hosted on blogspot (who even does that?) are easier to read just because of the change in layout.

Friday 31 October 2014

Week 8

This week, we started looking at algorithm analysis and asymptotic notation. We looked at big O, which provides the upper bound for the growth rate of a function, as well as big Ω, which provides the lower bound for the growth rate of a function. It was interesting to learn that in terms of complexity, constants are ignored.

A function with a constant time complexity that doesn't depend on the size of the input is O(1). One example if this is the average time complexity for search, insertion, and deletion for a hash table data structure. Hash tables are used because they are very efficient in that keys are mapped to a value so that only one key has to be looked up. This is the reason why they are used very commonly. We can compare this to the linked list data structure, which takes O(n) on average for searching, since it has to go through each item sequentially until it finds the item it is looking for.

Another interesting thing I learned this week was the formula for summing up the integers from 1 to n. The story of Gauss coming up with this solution when he was young also makes this easier to come up with.

This is sort of unrelated, but I came across a very interesting video of the visualization and "audibilization" of 15 sorting algorithms. I think it is a great introduction to sorting algorithms you may not have seen before. Perhaps the most beautiful is the bogo sort.


The second assignment was harder than expected but I eventually figured them out and next week is the second midterm but I am not as worried as the first midterm since I did well on the first one but hopefully this one goes just as well!

An interesting SLOG post I found is here: http://csc165.peet.io/big-o-notation/ (this blog also has a very nice, responsive design). This student writes about the penny puzzle that I previously also wrote about and gives an analysis of the algorithm in big O notation. I think this a very good post because it brings up the importance of run-time when writing programs. When I usually write a program, there is very little thought that goes into thinking about the program's running time but this is something that can have a large effect on your program depending on size of your inputs.

Friday 24 October 2014

Week 7

This week we finished proofs and started learning about algorithm analysis and asymptotic notation. In computer science, big O notation is used for classifying algorithms and is one of the most important topics in computer science so I am very excited to learn about this topic. We also looked at a few different sorting algorithms. Another sorting algorithm that I found quite interesting is bogosort. According to Wikipedia, "if bogosort were used to sort a deck of cards, it would consist of checking if the deck were in order, and if it were not, throwing the deck into the air, picking the cards up at random, and repeating the process until the deck is sorted." This algorithm has an average time complexity of O((n+1)!).

Penny Piles Puzzle

We were also given another puzzle to solve in class this week.

Given two drawers, with the left containing 64 pennies and the right containing none, can you arrange things so that one of the drawers has 48 pennies using the following operation on the two drawers:

If a drawer has an even number of pennies, you can transfer half of them to the other drawer. If the drawer has an odd number of pennies, you may not perform this operation.

Let's see what the steps you would have to take to get 48 pennies.

(64,0) # Starting off with 64 and 0 pennies
(32,32) # Move half (32) from left to right
(48,16) # Move half (16) from right to left

That was easy enough. Let's try it with an odd number. Say 25. It looks difficult to get from 64 to 25 so lets try working backwards.

(25, 39) # Starting off with 25 and 39
(50, 14) # Try performing the reverse action, double the left drawer
(36, 28) # Since we can't double the left drawer, double the right drawer
(8, 56) # Double the lower number (28) to get 56
(16, 48) # Double the lower number (28) to get 56
(32, 32) # Double the lower number (16) to get 32
(64, 0) # Finally, double the lower number (32) to get 64

So it seems that by working backwards, we can see that the pattern to get to 64 is to double the lower number between the two drawers and take the pennies from the other drawer, and keep performing this until you get back to 64 pennies in a drawer.

The following is my general solution written in Python. It takes two parameters, the first is the starting number of pennies in a drawer, which has to be a power of 2, and the second is the desired number of pennies to end up in a drawer, which has to be between 0 and the first number.

def penny_piles(pennies, number):
    """ (int, int) -> NoneType

    Prints the sequence of moves to get to desired number of pennies.

    Parameters:
    - pennies: the starting number of pennies in one drawer, must be a power of
    2
    - number: the number of pennies to end up with in one drawer
    """
    left = number
    right = pennies - number
    sequence = []

    # Check that the number of pennies is a power of 2
    if not (pennies != 0 and ((pennies & (pennies - 1)) == 0)):
        print("Number of pennies must be a power of 2.")
    elif number > pennies or number < 0:
        print("Number of pennies in one drawer cannot be larger than initial "
              "number of pennies or less than 0.")
    else:
        sequence.append('[' + str(left) + ',' + str(right) + ']')
        while left != pennies and right != pennies:
            if left < right:
                right -= left
                left *= 2
            else:
                left -= right
                right *= 2
            sequence.append('[' + str(left) + ',' + str(right) + ']')

        for step in reversed(sequence):
            print(step)

You can try it out here: http://repl.it/2St/1

This week we received the second assignment and it is all proofs and some of them look difficult so I have some work to do. We also received our Assignment 1 marks back and I got perfect on that so hopefully I can do the same with this assignment. Thanks for reading.