Thursday, February 5, 2015

Week 5: Tracing Recursion

Fortunately, I find tracing recursion (relatively) straightforward to parse. Unfortunately, I find recursive functions extremely difficult to write. In last week's lab, we were introduced to tracing recursive functions in Python. Tracing recursion mentally is a bit of a mess at times, when you're trying to determine the output of a function call. 

For example:

def nested_concat(L):
    """(list or str) -> str
    Return L if it’s a str, if L is a (possibly-nested) str return
    concatenation of str elements of L and (possibly-nested) sublists of L.
    Assume: Elements of L are either str or lists with elements that
            satisfy this same assumption.
    # examples omitted!
    """
    if isinstance(L, str):
        return L
    else: # L is a possibly-nested list of str
        return ’’.join([nested_concat(x) for x in L])

In this function, we pass an argument that can either be a list or a string. If the argument is a string, then then argument is
returned. Else, the join function is used to concatenate all of the elements in the argument. The tricky part is realizing the
recursive bit: essentially, the base case is that the argument should be a single, concatenated string. The function will mutate all of the elements, sub-elements, sub-sub-elements (and so on), until it meets this condition. I've commented the tracing of
two of the example calls posted in the lab below. 
    1) nested concat([’how’, [’now’, ’brown’], ’cow’]) # To trace this call: nested_concat([[’how’, [’now’, ’brown’], ’cow’]]) # We notice that L is a list: thus the else condition is reached --> ’’.join([nested_concat(x) for x in [’how’, [’now’, ’brown’], ’cow’]) #We notice that there is a sublist in L, so we concatenate the elements in that list --> ’’.join([’how’, ’nowbrown’, ’cow’]) #Now L is a list of str. Let's concatenate! --> ’hownowbrowncow’ 2) nested_concat([[’how’, [’now’, ’brown’, [’cow’]], ’eh?’]]) # First, we notice that there are multiple sub-lists --> ’’.join([nested_concat(x) for x in [[’how’, [’now’, ’brown’, [’cow’]], ’eh?’]]# We identify that ['cow'] is the innermost list, and concatenate each element in that list (only 1)# The list containing ['cow'] is ['now, 'brown', ['cow']] # so we would end up with 'nowbrowncow' # The list containing 'nowbrowncow' is [['how', 'nowbrowncow', 'eh?']] --> ’’.join([’how’, ’nowbrowncow', 'eh?’] --> ’hownowbrowncoweh?’

Thursday, January 29, 2015

Week 4 : Recursion

In week 4 of CSC148, we have broached the topic of recursion. Recursive functions are functions that call themselves. They have a conditional structure that specifies a base case (or cases): a condition (or conditions) that will stop the function from making calls to itself.  The also have a general case, which specifies the method in which recursive sub-calls will be combined. Essentially, the general case is the part where the function calls itself. It is important that you designate a base case, or the function call will reach a maximum recursion depth, and result in a stack overflow.

What is this legendary stack you speak of? Recursion is actually a method of using stacks to achieve a task. However, call stacks are stored in a computer's memory, and these stacks cannot become infinitely large, as computers do not have an indefinite amount of memory space. Thus, when a recursive function has a bug, and never reaches a base case, or the computer will eventually runs out of memory and crashes the program. This is called a "stack overflow".

If a task can be divided into identical, smaller sub-tasks, this is a good indication that you can perform this task by recursion.

Although I understand the concept of recursion, I am finding it difficult to actually put it into practice. Specifically, I have difficulties selecting and coding the base case and the general case of a recursive function. Parsing and developing recursive functions is something that will take some time to get the hang of. Hopefully I will be able to wrap my head recursion and get a strong handle of this very essential concept.

Also, whimsies left me a nice comment on my last post. I decided to return the favour and leave a comment on her page as well.





Tuesday, January 20, 2015

Week 3: Why Geeks Need to Write

For week three of CSC148 SLOGs, we have been assigned the topic of "Why Geeks Need to Write". This presents an important topic in computing, as it articulates the necessity of writing and written correspondence.  Writing is a means of delivering information to others, and analyzing your own understanding of a topic.

Knowing is not enough. Communicating what you know is a necessity of life, and english is a medium through which we can deliver this information to others. Whether it be filling out a document, writing a paper for a class, or reporting on a work project; writing never truly disappears from our lives.

Much like syntax is important in our coding, it is also important in our writing. In fact, coding and english are both languages in which we can convey information. Sufficient context, eloquence, and precision are required in both of these languages.

Written information is easily revisited and a great means of recording facts and opinions. The brain is notorious for overwriting and misplacing information that we learn. Graphite, digitized text, and ink are excellent mediums for preserving information that could otherwise be lost. Recording the facts we learn, the concepts we find difficult, and the new information we derived from our learning processes, are methods that can be used to harness our minds.

Often, when attempting to convey information to others, we are able to identify any gaps in our understanding of a topic, or inconsistencies in our theoretical knowledge. Additionally, by conveying information, we are often forced to summarize information in a concise but informative way, thereby helping us to distinguish important information. Learning, and sharing what we have learned, can often be one and the same thing.

Saturday, January 10, 2015

A miracle!

I went into the CSC165 exam with a mark in the high 90s, and left the exam completely convinced that I had not managed to achieve a 40% on the exam. Since the course requires you to achieve a grade of 40% on the exam in order to pass the course, I was convinced that I had failed and would be doomed to failure. After an excruciating month of waiting, I received my final grade. An A. I don't think words can describe the simultaneous feelings of relief and inadequacy that flooded over me. Relief, as I had, through some miracle of God, passed. Inadequacy, as I feel that it was most probably a huge fluke. Regardless, I will take what I can get. A new semester has begun. I wish everyone luck =).

Friday, December 12, 2014

I'm back from the dead! But I'm still dead!

Hello, world. I'm posting this blog post after exams, so this post is not really an entry for the course SLOGs.... it's more like a Dear Diary entry where I pour out the contents of my aching heart. A soliloquy of my despair.

I'm currently in a state of panic. I went into the exam feeling fairly confident. I mean, I was able to answer all of the questions from the 2010/2013 exams, how bad could it possibly be? As long as I got  over 40%, I'd still end up with a mark in the 70s. I prepared so much for it. My cheat sheet was crammed full of all of the possible questions from the assignments, tests, and lecture notes.

*echoing* Prepared so much for it. Prepared so much for it. Prepared so much for it *echoing*

On a scale of 1-10, I bombed that exam with a 100. I don't think I could have possibly messed up more than I did on that exam, besides like.... not showing up for the exam at all. All of the questions I thought would be on the exam, all of the questions that I prepared for.... were not on the exam. No halt (!!) , no generic big-Oh, no conversion of statements (Not all, Any). Nope. Nope. Nope.

 I pretty much threw a course worth of achievements (I was so, so proud of my grade in the course... a mark in the high 90s) into a pile of feces.

 I was expecting delta-epsilons to be on the exam, but I wasn't expecting TWO such questions to be on the exam. And they weren't ones I was familiar with. As soon as I saw the two, my mind went blank. Then I realized I couldn't solve both. I entered this state of complete and utter panic. I started sweating. My mind went blank. I'm actually fairly certain I was shaking at one point.

All of the questions I successfully answered, I somehow managed to misread the questions, and actually answer the wrong question. You're not reading that wrong. All of the questions that I SHOULD have gotten right, I somehow managed to  prove something... that didn't even answer the question they asked. So I bombed the exam. Thoroughly.

 How does one do this? How does one throw away a semester's worth of efforts in the matter of 3 hours. I failed that exam, without a matter of a doubt. We will be receiving our marks before Christmas, but I already know the result.

I went into the exam with high 90s, and now I'm not going to meet the minimum requirement for passing the course. I am going to have to repeat this course. I don't think words exist to describe how sad I am right now.

What is life.


Tuesday, December 2, 2014

That last minute struggle

After creeping and commenting on people's SLOGs over the course of this semester, I have to say that it's remarkable how people have gone from 2 posts all semester long (and this was the case for most people's SLOGs even 2 weeks ago!!!), to walls of texts. Oh, University, how is it that you are able to bring out the procrastinator that lies deep within all of our hearts.

 Overall, I feel that the SLOGs are an excellent way of proving to yourself that you know what you're talking about. It's one thing to understand a concept, and another to demonstrate that you actually do understand the concept that you claim to understand. Was that statement extremely convoluted? Yes. But you know what I mean.


 Throughout this semester, I've often gone from assuming that I understood a concept-- to realizing that I didn't. This was helped in part by reading SLOGs. I found it helpful to utilize other student's SLOGs to gain a better understanding of certain concepts. You often learn more from people who are also learning the material themselves. Good times.

Another thing that I have noticed is that I have spent a disproportionate amount of time in this course convincing others to realize why their proofs are insufficient or wrong. I'm not normally a confrontational person, but it can be a little exasperating at times when you're arguing with group members. You cannot prove a statement by restating it -- and you also cannot prove a statement by cleverly manipulating your proof so that it proves your statement, but only in certain cases. I'm not telling you that my answer is correct, but I'm most certainly pointing out why your proof cannot be correct.






After spending a semester taking CSC165, I have come to the realization that, although I have difficulty actually proving proofs, I have a strong foundation -- I can almost always tell when a proof is insufficient or wrong. I have also done enough practice proofs and studying to ensure that I am able to write proofs for the vast majority of proofs I should encounter in the exam. Hopefully this statement holds true for the actual exam. I also hope that, in the future, I will be able to devise proofs to problems with which I have not had prior experience with. Perhaps hone my intuition and induction skills?

Overall, it's been a great run. I can honestly say that this is most probably the only kind of course in which I would hear two students arguing over office hours with interjections of "BUT MY PROOF IS MORE ELEGANT" <-- legitimately, this was screamed aloud during Larry's office hours. Oh, UofT, you really, truly amaze me sometimes.

Anyways, I would 10/10 take this course again, and I would highly recommend it to any student - regardless of their major. Informative, educational, and enjoyable. Unfortunately, this SLOG will be seeing its imminent demise after the due date tomorrow, but it's been a great run.

 Adieu!


Computability

I promised, and I shall deliver.

When we disprove the existence of a working halt function, what we are doing is claiming that not only has a working function not been written, but that a halt function cannot possibly exist. The disproof outlined in the coursenotes uses proof by contradiction.



First, assume that the halt function exists.











In this example, the author has cleverly constructed a function, confused, where if confused is passed itself as an argument, one can deduce that there will be two cases here: that the function confused(), when passed itself as an argument confused(confused) will either halt, or it will not halt. Now, this is where things were a little confusing. To completely the paradox, one must pass confused as an argument on itself. Not just any two functions will do. By doing so, we arrive at a contradiction.

Case 1: Assume confused(confused) halts:
     Then halt(confused,confused) returns True.
     Then confused(confused) goes into an infinite loop.
So, confused(confused) halts ==> confused(confused) does not halt.

Case 2: Assume confused(confused) does not halt:
    Then halt(confused, confused) returns False.
    Then confused(confused) halts.
So, confused(confused) does not halt ==> confused(confused) halts.

From this, we can conclude that confused(confused) halts <==> confused(confused) does not halt.
Thus P <==> not P. This is a contradiction. Therefore, the halt function is non-computable.

_________________________________________________________________________________

Reductions are a way to prove the non-computability of a function.
















In a reduction, we first assume that our function is computable, and derive a proof by contradiction. By doing so, we prove that if our function is computable, then the halt function is computable. Since we have already proven that the halt function is not computable, we arrive at the contrapositive of our derived implication: that our function must be non-computable. The trick is to create a function f_prime() that utilizes the function f(i) within its body in a cleverly constructed way. If we are able to reduce halt to the meaning of life, we have produced a valid implementation of the halt function using our function. i.e we are able to utilize our function with arguments f_prime and i to determine whether or not a function halts on an input i. We know that this is not possible.

A function f is computable iff it is well-defined and we can tell how to compute f(x) for every x in the domain. In general, a function that remarks on the behaviour of another function will be non-computable.