Wednesday, 12 March 2014

Brian's CSC148 SLOG # 9

Hello and welcome to my 9th SLOG post!

I hope you all are doing well, this week has been havoc for me! I caught the flu, there was a snowstorm out this morning so imagine having a headache, sore throat, cough and runny nose while traversing through a flurry of snow blowing into your face. Nevertheless, I am still alive after gruesomely long commutes to and from school :P.

This week's topic will be about Assignment 2 Part 1 and a little rare surprise I had in my 8th CSC148 LAB.

Assignment 2 Part 1

Part 1 of Assignment 2 was a really unique opportunity for us students to design a RegexTree and represent it the way we wanted to. At first I thought there had to be only 1 absolute way to approach the task but we were actually given nearly boundless freedom to create the program. The only restriction that I am aware of is that we had to use inheritance and have a class hierarchy for our classes. Thus we couldn't create 1 single class to handle all the nodes.

So what knowledge was gained from completing this assignment?

Here is what I think:
  • Class hierarchy
  • Inheritance:
  • Reduction of duplicate code
  • An introduction to regular expressions used in various programming languages and utilities.

All of the above points work in tandem. Class hierarchy meant using inheritance and when calling functions from the classes, namespace would determine which function takes precedence over duplicate function names. For example: If I have a __repr__ method in my super class that calls on the __repr__ method of my Node classes, the __repr__ method of the Node classes will take precedence over the super class's __repr__ method even if we call it using the a RegexTree object.

Secondly, we can also easily reduce code by using inheritance and class heirarchy. I have actually completed two different designs of Assignment 2 Part 1 and have reviewed them with Professors Danny and Dustin. In one of my designs, I created an individual __repr__ method for every class which repeated code but on the other hand, showed how class hierarchy works. In the second design, I created a __repr__ class in the superclass RegexTree which would properly present a representation of all the different types of Regexes and since I have only 1 __repr__ method, there is less repetition of code in the program.

Another way to reduce code is in the __eq__ method. By writing a single __eq__ method in the superclass, we have reduced redundant code by rewriting one for every class. This method in particular could have been approached two ways. The first method is to simply compare the __repr__() methods of two different RegexTrees which meant that they had to have the exact same string to resolve to True.
The second method, which I think we could learn more from uses recursion. By simply checking if the symbol and children of a regex expression was equivalent, we could easily recurse over the children until both regular expressions had no children left and finally, return our desired bool.

Overall, Assignment 2 Part 1 was definitely a fun assignment to tackle given the freedom to design!

Lab 8

In this week's lab I had a rare opportunity to partner up with another friend of mine. He is a really crafty guy when it comes to programming and has knowledge of Java and uses comprehensions with ease.

His SLOG is here for those who are interested:
www.yanqilee.blogspot.ca

What made this an interesting experience is because we managed to solve the very last lab question in an interesting way. Apparently we were hinted to use the Stack class to solve BST's count_less method without using recursion. We struggled in trying to solve it using Stack but couldn't find an answer.
HOWEVER! We found a backdoor trick to solving it without using the Stack class at all!

The answer? BST's __str__ method. 

Our task was to count all the integers in a binary search tree lower than a given number for count_less method so we utilized __str__ instead. BST's __str__ method returned a representation of all the integers in a string that looked like a binary search tree. We simply split the string and removed all the newline characters. Afterwards, we looped over the integers and if it was lower than the number argument for count_less, we simply added one to count and returned count after the loop iteration.

Even the TA had a good laugh at how we accomplished the task!

That's all for this week so please check back soon for another SLOG installment!

All the best,
Brian

Wednesday, 5 March 2014

Brian's CSC148 SLOG # 8

Hello! How is everyone doing?
Welcome to my eight SLOG post.

This week has been quite alright! Term papers have been given back and I achieved 77.5% (B+) which is wonderful. I was expecting a grade in the B range but on the next test and the final exam I will be working harder to achieve even higher!

What's new in this SLOG post? 

This time I will be discussing:
  • A little bit of assignment 2 
  • Challenging concepts I am facing in CSC148
Without further ado, let's begin!

Assignment 2

Assignment 2 is all about creating Regexes and parsing Regexes and matching them with strings. As of now, we are only responsible for part 1: creating Regexes and part 2: parsing Regexes while matching them with strings will come later.

So what are Regexes? Regex is an abbreviation of regular expression which is used in different programming languages and other utilities to match entire classes of strings. For this assignment we will only be dealing with  regexes over the ternary alphabet {0, 1, 2} which is a non-empty string that consists of the symbols '0', '1', '2', 'e', '|', '.', '*', ')' and '('.

I managed to get insight for A2 by first creating a master class and subclasses that will later handle the creation of a regex such as ('2'|'3'). What information about regexes can we use to start coding our classes? By looking closely, we can tell that it has similar properties to a how trees are constructed. The nodes '0', '1', '2' and 'e' are the leaves and have no children and by knowing this, we can consider the bar '|' as the parent node. Comparing to a tree example such as: Tree(1, Tree(2), Tree(3)), we know 1 is the parent node, or root and 2 and 3 are the leaves that have no children. A regex can be represented similarly like so: Regex('|', [Regex(1), Regex(2)]).

With the insight that regexes can be expressed similarly like trees can in programming, I have managed to finish part 1 of assignment 2 which I will discuss in more detail next week. The deadline has been extended this week so I don't think I am able to share my full solutions just yet but look forward to my next post as I will explain be explaining it with great detail!

Challenges

University has been challenging for computer science courses. Very often I have had to take lots of time to consider how to approach new concepts and sometimes I feel that I am in the midst of somewhat understanding the new concepts but not yet fully. Comprehensions and recursion are the challenges for me right now. Comprehensions are very difficult for me because they are written quite differently from how I'm used to coding. Recursion is somewhat difficult for me. For easy problems I have no problem using recursion to solve them but for more complex ones, I struggle for long periods of time. The tough problems for me are usually a mix of comprehension and recursion in a single function. Asides from this, I can handle recursive functions at a good level. The only question is, whether or not I can understand comprehensions + recursion together before the end of the semester. I certainly hope so!

Thanks for reading my eight SLOG post! 
Have a wonderful week.

Wednesday, 26 February 2014

Brian's CSC148 SLOG # 7

Hey, how's it going!?

So this week, I had completed 148's FIRST TEST and I'm feeling quite good.

Sadly, after the test, I realized I made two small mistakes on two questions but I don't think I can provide precise details here but I can say that I have already looked into them and have learned from my errors :]. It's one of those computer science moments where you have a trick question and you know the answer is either Zero, None or Error.
My reasoning led me to the wrong answer (Doh!) but it was a good attempt and at least I was right about it being one of the three!

So what'll this week's SLOG be about? 

Hm... since I have been talking a lot about course material lately and I recently talked in-depth about OOP and recursion, I figured this week would be a good chance to talk about non-material course related things. Let's get started!

Piazza

At the start of 148, I didn't think much of Piazza and thought I could learn the course materials without relying on it. I was totally mistaken and my perspective of Piazza flipped right around at the beginning of exercise # 1.
It's an incredible experience when classmates, professors and TA's take time to discuss course concepts with you and try to hint you in the right direction if you're ever stuck on a submission. By discussing course concepts, or hinting someone who is stuck, everyone who is involved refines their knowledge of the computer science topic and even when we're mistaken, I noticed that the instructors will usually step in and correct our assumptions.
Without Piazza, I honestly think that most students in the program would have a lesser level of knowledge than they do now. That being said, I also hope that Piazza is included in future CSC courses.

Office Hours and Help Center

These two places are the place to be. Sometimes it's difficult to discuss a complicated code on Piazza so if further help is required, I would personally recommend one of the two. During assignment 1, I could not debug my code for TOAHModel.py. In fact, everything looked perfect but the default doctest would keep failing 3 out of 20 tests. After trying on my own for hours, I decided that I needed to discuss the code with someone who was well-versed in programming. I went to the Help Center and the friendly TA went over my code with me. We worked together and tracked down the error, which turned out to be a big issue but very easy to fix!
The issue? I wasn't creating Cheese objects when filling the first stool, just using regular integers for the cheeses which was why the doctest was failing. So the fix was quite simple: fill the first stool with Cheese objects instead!

I have been to office hours a few times this semester and I can't be thankful enough to Prof. Danny and Prof .Dustin for clarifying course material for me and showing me useful tricks to handle difficult problems such as recursive problems.
On another note, they have been replying to all of my e-mails within a day (Even on weekends!) and I am also thankful for that.

Office hours, Piazza, and the Help Center are truly indispensable resources for computer science learning.

Thoughts on Group Work

Let me first state that I strongly believe the current labs have been indubitably helpful to my own understanding of computer science. Nearly every school week there is a group lab where my partner (Ben) and I work through the challenging problems together. We discuss, brainstorm ideas and try them out until our answers are correct. We do try to get the code right the first time, but if it's inevitable we have multiple attempts until we arrive at the correct answer.
Personally, I enjoy the group work with Ben. We help point out each others mistakes and help each other understand things that we're unsure of. In fact, the labs have been so influential for us that we even discuss course concepts outside of school via Skype, phone and e-mail!
For those who are interested, please check out my partner's SLOG: http://mycsc148experience.blogspot.ca/

However, this is where I think a line must be drawn for group work. Although we are allowed to have groups for assignments, I also strongly believe that these should be done alone. By working alone, more students will develop their problem solving abilities but by working together, one group member may understand the solution whereas the others do not. If these students don't understand the concepts then they are at risk of doing poorly on the tests and perhaps in future courses as well.
I realize that in the real world we will be working with other peers but I think it would be meaningless if us students do not have a solid foundation on computer science concepts in the first place.

This is why I believe the perfect balance is to have groups for labs but not for assignments!


Thanks for reading my SLOG.
I will be finishing up assignment 2 this week so I'll make sure to discuss it in next week's entry.

Have a great week and see you again soon!



Monday, 17 February 2014

Assigned SLOG Topic # 2 - RECURSION! SLOG # 6

Wow! It's already the seventh week of the winter term.. how is everyone?

I have midterms in the coming week so I am hard at work. Writing tests are personally not my forte so I tend to double up the effort on assignments and even more so for test preparation.

Before I start this week's SLOG off, I have written a mid-week post on Object Oriented Programming (OOP) to discuss it in more detail since I had mistakenly not done so for the first assigned topic. Please give that a read if you have the time to and share your thoughts.

Seven weeks into the course, I'm finally comfortable with recursion to talk about it in depth, so let's get started!

How do we use recursion?

When solving a problem by repetitively using the same trick to get closer and closer to the final answer, we are using recursion.

Here is a real-life example of where recursion can be seen:

Imagine you've discovered a small diamond at the beach while going for a walk. Being the super clever person you are, you wonder if there are more undiscovered diamonds around this area. Using a metal detector and a shovel, you dig around the area, trying to uncover more. If there are no diamonds, you look around with the metal detector again and try the next spot. THIS is the example of recursion! You are repetitively doing the same task (shoveling and using the metal detector) in an attempt to get closer to the answer (the precious diamonds). Congratulations if this real-life recursion actually works out for you!

Programming example of recursion:

Perhaps you have a program that runs at different speeds depending on variable X and you'd like your program to run more efficiently. By using different cases of value X and running your program, you could deduce which case will be the most efficient. To do this, simply observe the amount of time it took each case to complete and trace the X value that completed your program in the shortest time. Although this sounds simple on paper, you are recursively calling your program for these different cases until you find the most optimal solution.

Here is a related example of another 148 student testing his functions for different run times:
http://berkeycolortran.wordpress.com/2014/02/15/week-6/
We should do so similarly as we want our program to run optimally by recursively testing various cases of X.

Define a stopping point!

When it comes to coding recursion, it's important to let our program know - "OK, that's enough!". It is super important to find a point where the program will finally stop recursively calling itself, otherwise it will continue on until our computers are out of memory. Some simple stopping points come from using for-loops over an iterable object such as lists, dictionaries and tuples or using conditions such that when the recursive function reaches the condition, it will stop rather than trying to call itself until our computers are out of memory.

A little technical example

As always, it's important to share some code as well. Simply talking about recursion without code isn't very helpful, especially to people who are new to it.

Let's define a function that will count the number of alphabetical objects in a nested list and let's define our list to be:
nested_list = [ 'race', 1, 'car', 2, 3, '4', ['hello!'], [1, ['ace', ['diamonds', 5]]]]

This should return a count of 4. Note that 'hello!' is not an alphabetical object since it has an exclamation mark (!) within the string. 'race', 'car', 'ace', 'diamonds' are all alphabetical.

def count_alpha(x: list) -> int:
    """
    Precondition: Items in x must be nested lists or string, integer and float objects.
 
    Returns the number of alphabetical objects inside a list.
    """
    count = [ ]
    def helper(x: list):
        for items in x:
            if isinstance(items, list):
                helper(items)
            else:
                if str(items).isalpha():
                    count.append(1)
    helper(x)
    return len(count)

Here is what this example does:
  • First we defined an empty list count as part of the outer function. 
  • We have defined an inner function 'helper(x)' so that when we recall our function, count does not get reset to an empty list.
  • For the body of helper(x), we utilize a for-loop so the program will stop after it iterates over all the items in list x; as stated above, it's important to define a stopping point for recursive functions.
  • The for-loop then iterates over x and if the items inside x happen to be a list, helper(items) is called which will loop through the items within the nested list.
  • Finally, if the for-loop happens to iterate through an object that is not a list, it will check if the object is alphabetical with the built-in isalpha().
    If this returns True, 1 is appended to count and the function will continue this pattern until the for-loop is completed.
  • len(count) is then returned, giving us our final answer.
Let's check our answer in Python Shell!

>>> nested_list = [ 'race', 1, 'car', 2, 3, '4', ['hello!'], [1, ['ace', ['diamonds', 5]]]]
>>> count_alpha(nested_list)
4

Voila!

Learning Recursion

Lastly but most importantly, I wanted to mention that learning recursion can be made MANY times easier by tracing your program on pencil and paper! I have done this for my labs, my assignments and for study material which helped me more than just reading about recursion or playing with recursive functions in Python. Tracing will provide tons of insight and is priceless for anyone interested in recursive functions. Using a visualizer helps as well but pencil and paper has personally been my saving grace.


Thanks for reading my lengthy but hopefully interesting SLOG post on recursion.

I have midterms to study for but do not fret, for I will be back with another post soon! :)
Wish me luck and see you readers later.








Sunday, 16 February 2014

Mid-Week Post on OOP (Object Oriented Programming) SLOG # 5

Hello! This is just a Mid-Week post on a subject I wanted to talk more about: Object Oriented Programming.

I actually didn't realize that for one of our 148 assigned SLOG topics, we were supposed to talk IN-DEPTH about OOP so I wanted to address it at least once. Oops!

Just to recap from my first SLOG, OOP is completely oriented on the creation and manipulation of objects as opposed to Procedural Programming which is oriented on the creation of functions with how they manipulate data.

Our starting point is the creation of a class which is like a blueprint to help us with the creation and usage of objects.

Afterwards, we can start defining methods of the class, which are functions that work specifically for the class's objects. With our newly defined methods we can now alter our objects in however we please or retrieve specific information about the object.

To clarify things, here's one example I recall from our 148 lab:

We can create a vehicle object that travels from place to place as long as it has enough fuel. How do we make Python do this?

Step 1: Create our vehicle class. (For example: class PublicBus)

Step 2: Initialize the vehicle class with default settings you would like to give it. Current fuel, fuel efficiency and current position are good examples of how vehicles are like in real world situations.

Step 3: Create our methods to make changes to our objects. Perhaps we'd like to fill up on gas, so how about a fill_up_gas method? Also we'd like to go from point A to point B, so how about a travel_to method? Of course our vehicle will need to meet the gas requirement so we can also add this in our travel_to method or create a helper method to check it for us.

Finally, we have done all we needed to and can start creating the actual object. It's quite simple actually. Just create an object using your blueprint (the vehicle class) like this: new_vehicle = PublicBus(100, 5).
100 here stands for the fuel, 5 stands for the fuel efficiency. These are the user-defined attributes of your new Public Bus object.

To get a bit technical, here is how it looks in Python code:

class PublicBus:
    """A PublicBus object. """

    def __init__(self, current_fuel, fuel_efficiency):
        """ Initializes PublicBus objects. """
        # Note: self refers to the object, it is named self by convention and is always         the first parameter for class methods.
        self.current_fuel = current_fuel
        self.fuel_efficiency = fuel_efficiency
        self.max_tank_capcity = 100
        self.current_pos = (0, 0)
        # Notice how current_pos isn't in the __init__ parameter? This is because             current_pos will ALWAYS start at (0, 0) coordinates when creating a new                 PublicBus object.

    def fill_up(self):
        """ Fills up the current fuel to the tank's max capacity. """
        self.current_fuel = self.max_tank_capacity  #  This is one of the class methods that will alter your object's attributes!

    def travel_to...
    def ....... so on, so forth. Keep defining methods until the object can meet all your requirements.

Now we can actually start using our object. Here is an arbitrary example that demonstrates how objects are created, used and how their attributes are changed.
NOTE: We use new_vehicle. (dot) in the code to call on the methods or check the class variables of the object's class. In this case, new_vehicle is the object and it's class is PublicBus.

>>> new_vehicle = PublicBus(100, 5)  # creating new object!
>>> new_vehicle.current_fuel  # checking object variable
100  # variable value
>>> new_vehicle.current_pos
(0, 0)
>>> new_vehicle.travel_to(5, 10)  # class method!
>>> new_vehicle.current_pos
(5, 10)
>>> new_vehicle.current_fuel
73  # new variable value!
>>> new_vehicle.fill_up()  # class method!
>>> new_vehicle.current_fuel
100  # class method fill_up() working properly.

This concludes the demonstration of how objects are interacted with and created in Python.

As you can see, OOP is totally emphasized on manipulating and creating objects. We have created an object, checked its' attributes, defined methods for it, initialized it and manipulated it all under one class.
Of course this is only one little object though. If we actually created a class for every type of  real-life vehicle, imagine all the knowledge we would have of them defined within our code. This is why OOP is important, it allows us to keep track of tons of information and change them as they are required; whether it be for games, medical, vehicles or any other purpose you can think of.

I hope this has been a good read for everyone.
Come back soon for more!

Tuesday, 11 February 2014

Brian's CSC148 SLOG # 4

Hello! How is everyone? This week has been a treat for me unlike the week before.

    If you recall, I was stuck on CSC148 assignment 1 last weekend on step 5 because I couldn't figure out what was wrong with my code. Then, on Monday's office hours, Prof. Danny pointed out the SLIGHTEST mistake in my code that completely flew over my head.

I was trying return a tuple and had forgotten to index the value I needed inside the tuple. When my function recursively recalled itself, it was trying to use the tuple instead of the value for simple calculations and thus was returning a TypeError. Bah! Still can't believe I couldn't find this error on my own. After this, I had finished A1 within a few hours. Asides from this, my midterms have been going really well.. I can feel it! So yup, good week!

OK. Pleasantries aside, I want to discuss a couple topics this week so here we go!

Topics:

Trees
Examples of copy.copy and copy.deepcopy

Trees

This is a totally new concept to me but I think it's very interesting with what you can do with trees. Perhaps the most interesting thing for me was learning how to traverse them, and using the data at these nodes with the used traversal method. Currently we learned of three: Post-Order Traversal, In-Order Traversal and Pre-Order Traversal. These three tree traversing methods allows us to manipulate our data in different ways. One example is an expression 1 + 2 * 3 expressed as a Tree.

Think of it like this:

+ is the root.
1 is the leaf child of the root.
* is the node child of the root.
2 and 3 are the leaf children of the * node.

If we use Pre-Order Traversal, we get the expression returned as + 1 * 2 3 which is the pre-fix expression of 1 + 2 * 3.
If we use Post-Order Traversal, we get the expression returned as  1 2 3 * + which is the post-fix expression of 1 + 2 * 3.
Lastly, using the In-Order Traversal, we simply get 1 + 2 * 3 which is an in-fix expression.

Although the expression example is trivial, I learned that we have many different ways of evaluating or storing expressions/data and I think this will become helpful once we have hundreds of different nodes and leaves to keep track of as opposed to just 1, 2 and 3!.

I came across one very helpful video that shows step-by-step binary tree traversals, have a look if you're interested! I especially recommend it if you're having a hard time understanding the concepts.

In-Order Traversals (Binary Tree): http://www.youtube.com/watch?v=gvPOTGGnn8k
Pre-Order Traversals (Binary Tree): http://www.youtube.com/watch?v=S5emQOEMiqc
Post-Order Traversals (Binary Tree): http://www.youtube.com/watch?v=X0pA5JOyI90

copy.copy, copy.deepcopy, assigning variables to values

Here's a tidbit of code that should explain this very well.

If we set x = [1, 2, 3]
and then set y = x
y and x will ALWAYS refer to the same object as long as we don't reassign y or x to new objects. This means, we can APPEND to the list object. So what happens when we do that? Have a look.

>>> x.append(4)
>>> x
[1, 2, 3, 4]
>>> y
[1, 2, 3, 4]

As you can see, there is no mistake, x and y will always be the same until a new value is assigned.

Now then.. rewind a little and we're back to:
x = [1, 2, 3]

Rather than assigning this time, we will import copy and use copy.copy.
>>> y = copy.copy(x)
>>> y
y = [1, 2, 3]

Nothing unusual yet.. but wait!
>>> x.append(4)
>>> x
[1, 2, 3, 4]
>>> y
[1, 2, 3]

Magic. No, just kidding. Now that we use copy.copy, y and x no longer refer to the same object and can be altered without causing an effect on each other. Note: copy.copy is also known as shallow copy.

copy.deepcopy is a little stronger. It actually goes through all the contents of your objects and recreates them individually at different memory addresses. It has a similar effect to copy.copy but goes that extra mile to keep them totally different. I hope this helps!

Check back soon for a another update! I'll be discussing a bit more about OOP (Object Oriented Programming) and for the coming week, recursion.

As always, thanks for reading my SLOG.
Brian


Tuesday, 4 February 2014

Brian's CSC148 SLOG # 3

Hello and how is everyone?

Boy, has this week has been rough!
Learned a lot in the 148 labs but the assignment is kicking my behind!

The first assignment was going swell until the 5th part, Tour.py.
I am unsure how to optimally make my program solve the problem. We are supposed to use recursion but my experience with it isn't sufficient.

I have tried a number of things through-out the entire day and I can't seem to find the root of the issue. For example, my code is supposed to solve the game with 4 stools and 5 cheeses in 13 moves but it has been giving me different values of moves like 21 or 7. I traced my program and realized there was an issue but it's a strange one due to the conditions of the formula for the minimum amount of moves.

Basically, when the formula calls on itself again, it uses a value that is not specified in the formula, so it has been returning a NoneType + an int. What happens when you add a NoneType and int? TypeError! Still working feverishly on this issue, trying to figure out where I'm going wrong.

Oh yes! There was a very interesting concept we learned this week in the labs.

  • copy.copy
  • copy.deepcopy
  • assigning values to variables

Basically, when you assign a value to something in python, it will be stored in memory address.
If you assign another variable equal to that value, and equate them with '==', this will return True.

copy.copy and copy.deepcopy will create a copy of the variable, BUT they will be assigned at different memory addresses.

EDIT: Oops! I made a mistake in my last post about these built-ins. Please disregard them and read here.
.
copy.copy and copy.deepcopy will both change the memory addresses of the variables! Equating them as they are will still be return True. However, recall what happens if these variables are both assigned to a number and you add to one of them. If copy.copy or copy.deepcopy is not used, adding to this number will change both variables and they can be equated to return True.

Now try it again with these two copy functions and add to one of the variables and what happens?
The answer: The number with the variable you have added to will be assigned the new value and the other variable will remain unchanged. Interesting stuff!

Thanks for reading my SLOG again.
Back to the assignment for me!