Monday, 6 April 2015

Last impressions

It's the end of the term and the end of classes in my first year of university. It has been quite challenging for me, although the experience wasn't the worst. I'm glad I took computer science, as I have learnt and will continue to learn a lot in the field. Slowly and slowly, I've begun to see how it relates to real-life situations and problems.

As a continuation of CSC108, I feel like I began this course as if I had no background for it. We just happened to leap from 108 to 148, all of a sudden! I felt this way after seeing the first assignment and having no clue how to start it at first. Later, I started to see how it could be done. 

Overall, CSC148 has been very challenging for me, but it was worthwhile to learn. However, I didn't do as well as I had expected as I didn't ask for help enough from friends, professors, and TAs, and I feel like I didn't spend enough time practicing concepts learnt. Additionally, the TA strike proved to be a detriment to my learning experience, even though it gave me more time to complete work and review concepts. This is why I really struggled during the midterm tests and assignments, and even the labs that I'd done, as I didn't know how to apply the theoretical concepts. Hopefully, I will be able to do so in the final exam, and I plan to do all the labs, review course notes and other work, do past exam questions, and seek necessary help in order to prepare myself. I aim to do very well on the final exam, and also avoid silly mistakes, which I made on both of my midterm tests.

Despite the struggles, I really enjoyed going to lecture and learning the material. As well, the professor was very friendly, helpful and knowledgeable. He was also very funny, sometimes using humour to convey his message or to point out something. He explained the concepts very well, even using code and diagrams to demonstrate them where appropriate. He also gave his time, along with other professors, during office hours to help us with assignments and supervise our second midterm. As well, thanks to the professors, we were able to continue the course quite normally and not have any major disruptions in our schedule. The TA's were very helpful as well, they tried to use their knowledge inside and outside tutorials to help us understand concepts.

In second year, I will be doing Java instead of Python, so I think the experience may be a little different. But since I have programming knowledge in Java, I should be able to manage. I'm anticipating to use my Python knowledge as well in second year, but I am apprehensive of it. This is because the courses will only get more and more difficult, and more time and work will be needed in order to succeed in them. Hopefully though, I will be able to use my knowledge gained this year, along with additional resources, to succeed. 

Overall, I feel that our time in first year passed by so fast, and I wish I could go back and fix whatever mistakes I made in CSC108 and 148. But if I learn from my mistakes, that will be beneficial for me as well, given the fact that we can't go back in time.

Sunday, 5 April 2015

Week 11 - My first 4 weeks of CSC148 (Post 2)

In this post, I mentioned that the concepts that I learnt in these weeks weren't that difficult, but they weren't too simple either. I somewhat agree with this statement, as this is the case even now; the course concepts aren't too simple. In fact, the concepts have become more and more difficult to internalize, absorb, and above all, apply. The basic theory and code is quite easy to understand, but the application is the difficult part.

"The concepts are [relatively] easy to understand, but applying them requires a lot of thinking and can be difficult."

The world "relatively" is included here; it wasn't included in the original post, because now, I've realized that the course concepts have become more and more challenging to understand, despite being relatively easier than to apply. Because of this, I really struggled with the labs and the resulting quizzes, and even the assignments and midterm tests. 

I also mentioned that I planned to ask for help from various people, including TA's. I had planned to do this, but I haven't really been able to do it. This was because of other work that I had to do, and that I didn't really know what questions to ask them and how to. To be honest, I wasn't really sure of what I wasn't sure about, and also I didn't know how to verbally express what I didn't know. Additionally, the long TA strike had further limited my opportunities to seek help from TA's. So, I practically tried to figure out everything myself, with limited help from friends and TA's.

However, I do agree that I had looked forward to learning more advanced programming. This is true, because I tried to browse through the weekly lecture slides and code before every lecture, anticipating more new material. I really wanted to know what I would learn in lecture, and I wanted to be well-prepared. 

My situation is similar to this blogger, Niyant Hathi, in some ways: He mentioned that the course got difficult very quickly, and that things would get tough for him starting with recursion. However, he mentioned that he put in time and effort to understand the new topics. And even though marks are very important in the course, I completely agree with him on what he said about valuing what he learnt in the course than what some number says about his efforts in the course.

This is his blog post: http://niyantcsc148.blogspot.ca/2015/03/revisit-previous-slog.html

As well, I agree with Fahim Lallani, another blogger and my CSC148 classmate, about the importance of attending lectures. I feel that attending lectures in person are much more effective, than watching online lectures or listening to recorded lectures. He also mentioned that going to lectures would drastically improve his mark. My marks haven't improved drastically simply because of how much I struggled, but the lectures provided the foundations for my understanding of this course. Also, the professor explains concepts very well, and even outlines what needs to be done in assignments. Personally, I think that everyone should try to attend as many lectures as they can.

Fahim's comment about lecture attendance is in his most recent blog post: http://fahimscourse.blogspot.ca/2015/04/week-11-revisiting-earlier-blog-post.html

Friday, 3 April 2015

Week 10 - Mutating BSTs in Week 9

In week 9, we learnt how to mutate BSTs. Basically, mutating a BST involves adding nodes to a BST. To do this, we were shown a class BTNode and initialization of three variables: data, left and right. And then, the professor showed us some code that basically inserted nodal values to form a tree. This was done using the insert function. This code shows the implementation of the insert function:

return_node = node

if not node:
        return_node = BTNode(data)
elif data < node.data:
        node.left = insert(node.left, data)
elif data > node.data:
        node.right = insert(node.right, data)
else:
        pass
return return_node

At first, I found this code confusing to understand as I didn't understand why an initial variable was created. But I read it over and over again and I even drew diagrams to try and understand it. Finally, I understood the code and realized that it was just recursion that was "appointed" once again to insert nodes to the left or right of data.

                14
        12
                10
8
                 6
         4
                 
For example, if we were to insert a 2 into this tree, we would have to see if it passed certain conditions to determine where it should be situated. Firstly, there is a node here, so the base case is ignored. Then, we have to see if the data passed is less than node.data. In this case, is 2 less than 8? Yes, so we move it down the left side. Then, is 2 less than 4? Yes, so we situate 2 to the bottom left of 4. 

                14
        12
                10
8
                 6
         4
                 2

The same thing can be done for values larger than node.data, except then, the values would be shifted right in the tree. As for the deletion of data from a BST, we have to check for certain conditions to see where to delete data and shift previously attached data. 

This slog explain 3 cases encountered when deleting data from a BST. I found this explanation very helpful to understand on deleting data. It mentions about the base case, where only one node has to be deleted, a case where a node with only one child has to be deleted, and where recursion needs to be used in order to determine which data needs to be deleted. The person who wrote this slog also mentioned that this may not work when there are duplicate nodes. But one way to solve this is by passing the address of the node to be deleted, as the address of each node is unique. It was interesting to learn this important tip from this slog, and this is why I have included the link for it as well.

http://theremustbe.blogspot.ca/2015/03/week-9-mutating-bst.html

Thursday, 2 April 2015

Week 9 - Linked lists, iteration, mutation in Week 8

This week, we had our 2nd midterm test. It was actually not difficult, but I struggled with it as it required applying my knowledge of code for recursion. I don't think I did well in the test as I know that I didn't know how to implement the body of the classes given. This is because I found it difficult to apply my knowledge from lecture. It is easy to read code and a little tough to understand it, but it is a lot tougher to apply the knowledge.

After, the professor covered linked lists even further and showed us some code on how to "walk through" the linked list. I learnt two ways of thinking of linked list structures: as lists made up of an item (value) and a sub-list (rest), and as objects (nodes) with a value and a reference to other similar objects. 

To make a reference to other objects, the professor showed us two initialized variable in class LLNode, value and nxt. We were also shown how a wrapper class for a list is made, by initializing variables front, back and size

To walk through a list, we were shown that we had make a reference to at least one node, and move it along the way. I found the code relatively simple to understand, as it just involved initializing the variable as the front of the list, and while there were elements behind, the variable kept referring to the element behind the current one. The general outline of the code for this is as follows:

cur_node = self.front
while <some condition here...>:
       # do something here...
       cur_node = cur_node.nxt

We were also taught a few more methods associated with linked lists, such as implementing __contains__, __getitem__, and delete_back briefly. Overall, this was a relatively easy lecture to understand, but this is just the theory. The practical applications is where I will really need to apply and hone my knowledge in.

Saturday, 28 March 2015

Week 8 - Linked structures in Week 7

In week 7, the professor covered the concept of linked lists. A linked list is a recursive data structure that is made up of connecting nodes. Each node contains a reference to the next node in the list. As usual, when I was first introduced to this concept in class, I found it quite confusing and hard to understand. But after reading over it again and visualizing it in my mind and on paper, I was able to make sense of how it worked. Asking the professor also helped. 

To teach this concept, the professor created a class called BTNode, which had 3 attributes: data, left, and right. Data is the root node, and left and right represent the children of data. He then showed us some methods that used these attributes along with some additional ones to create representations of this class. Again, this was confusing for me at first, as the code seemed complicated and odd to be able to create some form of a visual representation of the nodes in the class. An example of this is the __str__ method. It involved indenting in order to distinguish the children and space them out. I wonder how people can figure out how to code this, as it seems so complicated for me to code. I can visualize it and draw it on paper easily, but when I have to translate it into code, it seems like a burden.

The professor also showed us how arithmetic expression trees are represented. The values in nodes don't necessarily have to be numbers. They can even be operators, such as the ones in the tree below(a representation):
       7.0
+           4.0  
       *
             3.0
The professor also showed us how to evaluate a binary expression tree, using the eval() function. I found this particularly interesting and useful as it simplifies the job of evaluation by combining the values in the nodes into one single string expression and evaluating that expression. 

Furthermore, we were shown how to evaluate a binary search tree inorder, preorder and postorder. Additionally, our professor showed us added ordering conditions to a binary tree, and were taught how to check if a value was in a tree by calling a recursive function on the tree. Overall, I found this lecture interesting, but I do find the course becoming progressively more challenging. However, I try to curb this challenge by reading over concepts again and again and practicing them, and aim to continue to seek help when necessary.

Sunday, 1 March 2015

Week 7 - Recursion

For me, tracing recursion is not really a difficult concept, as it involves going into a list and just using a function on the various elements in the list. It basically involves a function calling itself, as mentioned previously. An example of recursion on a list can be:
L = [[1, 5], [9, 8], [1, 2, 3, 4]]
sum([sum_list(x) for x in L]) - this takes the sum of elements at each index position in L, or just x if x is an integer

To trace this, just do:

>>> sum_list[[1, 5], [9, 8], [1, 2, 3, 4]]
>>> sum([sum_list[1, 5], sum_list[9, 8], sum_list[1, 2, 3, 4]])
>>> sum([6, 17, 10])
33

Tracing inside lists more complicated than this one can be confusing, but if one just traces simpler examples first, he/she can automatically write the result of the nested list in upcoming examples of lists of increasing complexity. They will not need to trace through individual elements in the nested lists again, such as [sum_list(9), sum_list(8)]. In fact, when one moves on to tracing more and more complicated list calls, they must not do this. This is because they would have already traced through like this in previous simpler examples.

The depth of the list is also not that difficult to understand. It took me some time, however, to understand how the code for determining the maximum depth of a list made sense and worked. This is the code for determining the depth for the list:

if instance(L, list):
     return 1 + max([depth(x) for x in L])
else:   # L is not a list
     return 0

At first, I was confused as to how this function was able to determine the depth of a nested list with just the word depth(x) in its code. Before finding out the solution, I thought about it to myself and got the correct answer just by seeing the number of lists and nested lists. A simple example of this is:

>>> depth(17)
0
>>> depth([1, 2, 3])
1                   # because there is only one list
>>> depth([3, 4, [2, 5], 9])
2                   # because there is a list and nested list

Later, I figured out how the code worked, just by remembering that it was nothing but recursion at action! Since it called itself, depth(x) works on a nested list, such as [2, 5], just like it would work on a list without a nested list, such as [1, 2, 3]. 

Furthermore, the professor also covered how to find the maximum number in a simple list, lists that are one deep, two deep and etc. For example, this is a call to a simple/flat list:

>>> rec_max([2, 5, 1, 3])
>>> max([rec_max(2), rec_max(5), rec_max(1), rec_max(3)])
>>> max(2, 5, 1, 3)
5

When the list increases in complexity, it must be evaluated in the same way as the sum_list() and depth() functions. One thing that I found particularly fascinating was recursion in a file named tree_burst.py. This gave a visual application of recursion and I found this particularly interesting, as it involved red, blue and green arrows branching out in 3 different directions. These arrows formed a ternary tree. I didn't fully understand how this implementation of recursion worked, but I enjoyed it as I like learning through visuals.

By far, this course continues to become more and more interesting, and challenging as well. I look forward to upcoming material and am a bit apprehensive of their level of difficulty.

Sunday, 22 February 2015

Object-oriented Programming (OOP)

In object-oriented programming, creating objects containing both data and functionality is the focus. The definition of OOP is that it is a model for writing computer programs, modeled around the interactions between objects. It involves writing classes that generate objects and define their structure. Object-oriented programming involves working with ADTs, or abstract data types.

For example, you can define a class Point, and give it the attributes x and y, as mentioned previously. Now that the class is defined, objects of this type Point can be created. When this class was created, a type of this class was also created. Point objects can also be called instances of type Point

class Point:
    """
    """
    def __init__(self, x, y):
        """ (Point, int, int) -> NoneType

        """
        self.x = x
        self.y = y

Objects of this instance can be generated like this:

>>> p = Point(3, 4)
>>> p.x   # p.x and p.y just accesses the values for this instance 
3
>>> p.y
4

You can even write methods in classes, which look like functions but are a part of objects. As mentioned before, a method for this class could be distance_from_origin. It can be called like this on an object:

>>> p.distance_from_origin()

This way, the object p has data in the form of x and y, and functionality in the form of the method, distance_from_origin. Another excellent, existing example of object-creating ADTs are stacks. Stack is a class and type, which has data and also functions in terms of push(), pop() and is_empty(). In conclusion, object-oriented programming involves creating objects through classes, with data in the form of attributes and functions in the form of methods.

Monday, 16 February 2015

Tracing recursion in Week 4

For me, tracing recursion is not really a difficult concept, as it involves going into a list and just using a function on the various elements in the list. It basically involves a function calling itself, as mentioned previously. An example of recursion on a list can be:
L = [[1, 5], [9, 8], [1, 2, 3, 4]]
sum([sum_list(x) for x in L]) - this takes the sum of elements at each index position in L, or just x if x is an integer

To trace this, just do:

>>> sum_list[[1, 5], [9, 8], [1, 2, 3, 4]]
>>> sum([sum_list[1, 5], sum_list[9, 8], sum_list[1, 2, 3, 4]])
>>> sum([6, 17, 10])
33

Tracing inside lists more complicated than this one can be confusing, but if one just traces simpler examples first, he/she can automatically write the result of the nested list in upcoming examples of lists of increasing complexity. They will not need to trace through individual elements in the nested lists again, such as [sum_list(9), sum_list(8)]. In fact, when one moves on to tracing more and more complicated list calls, they must not do this. This is because they would have already traced through like this in previous simpler examples.

The depth of the list is also not that difficult to understand. It took me some time, however, to understand how the code for determining the maximum depth of a list made sense and worked. This is the code for determining the depth for the list:

if instance(L, list):
     return 1 + max([depth(x) for x in L])
else:   # L is not a list
     return 0

At first, I was confused as to how this function was able to determine the depth of a nested list with just the word depth(x) in its code. Before finding out the solution, I thought about it to myself and got the correct answer just by seeing the number of lists and nested lists. A simple example of this is:

>>> depth(17)
0
>>> depth([1, 2, 3])
1                   # because there is only one list
>>> depth([3, 4, [2, 5], 9])
2                   # because there is a list and nested list

Later, I figured out how the code worked, just by remembering that it was nothing but recursion at action! Since it called itself, depth(x) works on a nested list, such as [2, 5], just like it would work on a list without a nested list, such as [1, 2, 3]. 

Furthermore, the professor also covered how to find the maximum number in a simple list, lists that are one deep, two deep and etc. For example, this is a call to a simple/flat list:

>>> rec_max([2, 5, 1, 3])
>>> max([rec_max(2), rec_max(5), rec_max(1), rec_max(3)])
>>> max(2, 5, 1, 3)
5

When the list increases in complexity, it must be evaluated in the same way as the sum_list() and depth() functions. One thing that I found particularly fascinating was recursion in a file named tree_burst.py. This gave a visual application of recursion and I found this particularly interesting, as it involved red, blue and green arrows branching out in 3 different directions. These arrows formed a ternary tree. I didn't fully understand how this implementation of recursion worked, but I enjoyed it as I like learning through visuals.

By far, this course continues to become more and more interesting, and challenging as well. I look forward to upcoming material and am a bit apprehensive of their level of difficulty.

Friday, 6 February 2015

My first four weeks in CSC148

In my first four weeks in this course, I have learnt quite a lot, especially about classes and recursion. To me, the concepts are not too difficult, but they are not too simple either. The first thing that I learnt is to look for a few key things in a class description to design a class. I found this particularly useful. These things are: an important noun (for the class name), attributes, and necessary operations. For example, for a class Point, its attributes are the x and y coordinates, and its necessary operations can be calculating the distance between a point and the origin, distance between two points and the midpoint between the two points. I also learnt how to implement an __eq__, __str__ and __repr__ method. Interestingly, the concept of controlling access to attributes and classes was also taught. Because of this, I now know that _attribute represent an attribute that can be controlled by the creator. Additionally, I also learnt how a stack is designed, and the three main functions associated with this class, push()pop() and is_empty().

As well, the professor covered how to extend a class's (superclass) characteristics in a subclass. Also, for methods in a superclass that are supposed to be in a subclass, all one has to do is raise an exception (ex. raise Exception("This cannot be done.")). One can raise existing Exceptions, or make up his or her own Exceptions. Furthermore, I learnt how to trace through a list to add items up in a process known as recursion. Recursion is a very interesting and unique concept as it involves a function calling itself. One can use this method to trace lists of varying depths, like this:

sum_list[1, 2, 3, 4, 5, 6] or sum_list [1, [2, 3], 4, 5, 6] or even sum_list[1, 2, [3, 4, [5, 6], 7], 8]

We were given weekly lab exercises based on what we were taught, and quizzes in our tutorials. I found the quizzes quite tough, actually. I was confused about how to answer the questions, so I didn't end up doing well on them. The concepts are easy to understand, but applying them requires a lot of thinking and can be difficult for me. This is why I plan to ask for help from various people, including TA's at the help centre. Despite the challenges, this course has been interesting so far, and I am looking forward to learning more about advanced programming.

Sunday, 25 January 2015

CSC148 - Why geeks should write

I am a first-year student in CSC148, which is a course that teaches students how to write solutions for advanced problems, a continuation of the CSC108 course. It also covers concepts from abstract data types to recursion. Some people have also told me that I will be learning about data trees and algorithms, including that for sorting. Overall, this course aims to expand our knowledge in systematic and efficient programming as well as foster good programming skills.

This is just a brief introduction to the course that I will learn a lot in. Now, why should computer scientists write about computer science? This is a good question, as many would expect a computer scientist to program a lot and spend his or her time in front of a computer, not writing blogs. However, I do feel that computer scientists need to keep in touch with concepts that they have learned in their field and also maintain good writing habits. Writing about concepts learnt helps a computer scientist by reminding him/her about what certain aspects of computer science are or how they are supposed to be understood and applied. For example, if there is a definition of a computer science term, such as abstract data type, reading about it will help to understand the concept, but writing down its definition and other notes about it will help a computer scientist better absorb and retain this concept. Similarly, I will now define abstract data type in order to help me remember what it is.

Abstract data type - a data type that specifies a set of operations (or methods) and semantics of the operations (what they do), but it does not specify the implementation of the operations. 
http://openbookproject.net/thinkcs/python/english3e/stacks.html

Basically, it is a data type that specifies a set of methods and what they do, but it doesn't specify how they do what they do. This is an example of my own annotations to make sense of this term. In this, writing helps as well as computer scientists will better understand concepts, especially when they put it in their own words. Furthermore, whenever they are doing a project, assignment, or anything related to computer science, computer geeks can look back at blogs they have written about a particular concept or term if they don't remember it. This way, blogs about computer science will serve computer scientists well in the future. They can serve as an aid to understanding and refreshing one's memory about certain concepts previously learned. As well, they serve as an excellent tool to write about new concepts learnt each time. 

Additionally, computer scientists should write blogs so that others will benefit from their knowledge as well. By reading these blogs, other aspiring computer scientists or people will understand and enjoy the concepts of computer science. As well, if they don't understand a concept or term, they can just refer to these blogs to help understand concepts and in turn, this will help them apply their newly learnt concepts to their existing knowledge of computer science. This way, writing about computer science will not only benefit the computer geek writing it, but also its readers who wish to learn and gain knowledge.