Progress is never fast enough but a new side job makes the time I do have all the more valuable. I had a quick succession of good things happen, and if anything the path ahead's clearer now. It's a bit obvious I'm not hitting that 9-week deadline - nor was it ever physically possible - if it takes 10, so be it, once I'm done I assess how much time things take, what I did right, wrong, and wait for my ego to resurrect itself (doesn't take long).
SICP/CS61A - Structure & Interpretation of Computer Programs is at Lecture 23/44 & p341 (ch 3.4) - past the halfway point; and CS106A Programming Methodology is Lec 19/28, PSET 6 of 7, Assignment 6 of 7 - so.. getting there. I'm making sure I don't fall behind on 6.00.1x - so that I can get the certificate; Circuits & Electronics is the next priority and Calc I at the end.
Unfortunately I'm not quite philosophical right now - though I'm writing thoughts down for future posts, but today's part of that report-every-3-days commitment. And I figure I should wait more than 1 day of training to complain and wax-philosophic about low-tier work in America. It's more motivation to be serious w/ the study and get into intellectual work.
Some notes from Problem Set 1 of 6.00.1x - Introduction to Computer Science & Programming with Python:
I'm learning some differences between Python and Java. My approach to studying CS & Programming is to not shy away from dealing with multiple languages at once. After all: the real part should be learning to build algorithms, solve problems, and get comfortable with multiple layers of abstraction. The syntax of different programming languages should be the easy part.
That said a few beginner notes on Python and Java. In Java you have something very close to C. Code blocks inside braces, lines ending with semicolons, explicit type setting of variables. Python looks like it's more streamlined, but I suspect a bit of a learning curve after the first stage. No explicit type setting, which makes coding faster but can bring headaches if you don't pay attention, no semicolons - instead a strict indentation regime, and a simple colon beginning a code block instead of the braces. Edit: semicolons optional
6.00.1x PSet 1.2: Counting bobs
Figuring out how to count the number of times the name "bob" comes up in a string took a lot longer than my pride allows me to say. After seeing the difference between Java and Python syntax, there were 2 issues I had to figure out: firstly how to use the range() function. You can't just write:
for i in range(s): ... because range() wants a number but s here is a string of letters. No bueno. So use len() to find the integer value of the length of s, and pass that as an argument to range() like so:
for i in range(len(s)): ---
The second issue was remembering that moving through an array, you start at the first value and end just before the last. So writing: if "bob" in s[i:i+2]: is going to bring you bad times, and is why my code kept saying zero.
6.00.1x Pset 1.3: Counting and Grouping
There were two hurdles with this problem. First was figuring out how to pass integer variables into a string in Python, and I think I found a more-complicated-than-necessary way of doing it, and the other was making sure the variable I wanted to return was defined after the for-loop was completed. I also forgot some colons in there. Odd to me that Python won't update variables within another variable (say integer values within a string) but.. hmm perhaps because it's defined as a string then it stays that way? Idk.
Note: copypasting from Evernote lets you keep formatting? sweet
Last night I took an inventory of where I stood with my work. I'm 7 weeks into the CS Course, and I'm very far behind where I want to be. The point was to take the same courses EE/CS majors do at an accelerated pace to give myself a several-month crash-course in Computer Science. If I'm taking as long or longer than the courses themselves I'm doing something wrong.
Current standing:
SICP/CS61A: p218/833 - week 5 of 14
CS106A; week 5 of 11
6.002.1x: week 2 of 4
18.01sc: section 27 of 101
So I'm giving myself 12 days to get this all done. That's my objective, and outcome I want is to build my CS fundamentals but really it's discipline. The stakes will be a lot higher in the future, so if I can prove to myself this can get done, then that's good.
I'm stacking on an extra course, MITx's 6.00.1x course on edx, Intro to CS & Programming w/ Python - because it's time dependent (so do it now or not) and I want to get a certificate in the thing (got 53/55% last time). It's not hard.
I can say that, oh when I started 48 days ago, I started from zero - and while that's true it also doesn't matter. It gets done or it doesn't. So:
In order to achieve my objective I'll need to keep up the following minimum pace:
51 pages of SICP /day
.75 weeks of CS61A / day --or-- 3 weeks every 2 days
6.002.1x is fine
7 sections (roughly 2 lectures) of 18.01sc every day
6.00.1x at normal pace.
Why do I believe I can do this? I've been able to finish an entire week of 6.002.1x Circuit Analysis in a day, and roughly the same in CS61A & CS106A. So it's not a capability issue. It's a discipline issue.
The stuff isn't extremely difficult, and I'm not looking to be a world-class expert; just to be competent & get it done. I'll be posting regular updates every 3 days until I start the 2nd set.
To meet the 9-week mark, I actually have 15 days, but I'm pretending those extra 3 don't exist. You should focus on not getting cut, not asking if you can keep the arm.
Tuesday, January 5, 2016
CS Course Day 36
Yesterday I finally started 6.002x Circuits and Electronics. I have until May to complete the 3 modules. My motivation is: it's not enough to learn programming skills; if I want to build integrated hardware systems... well I better know which wire goes where eh? I like the course. Worked on it yesterday from 1800 to 23:40 with some breaks. It feels good to work on things from a coding side, and from a physical and math pencil & paper side.
I worked on some very basic circuit analysis. The course at this stage is a review. KCL, KVL, element relationships, and node-method analysis. I first tried this course maybe 10 months ago and where everything seemed like impossible black-magic it's now pretty simple and intuitive. You stay consistent in how you assign [$+$/$-$] and math + principles basically takes care of it all for you.
For example, down below at S2E2 your asked to find the branch variables of the two circuits. The only difference between the two is that the sign convention (which way is [$+$] or [$-$]) on the voltages is switched. As you'd expect, the measured voltages and currents are the opposite signs of one another, but the power being supplied by the voltage source and dissipated by the resistor is the same.
These in-lecture exercises served as a warm-up for me: remembering the mental habits that make you efficient; but in the beginning you grind through it all so it takes some time. S2E3 at bottom was a more involved application of everything.
S2E2 & S2E3:
I got as far last night as dealing with the Node method. The other methods (KCL/KVL and element relationships) balloon in complexity and number of equations with number of elements. The node method is what's used. The way it works is you pick a node (a juncture between branch elements) and set that as your ground. You're measuring voltage which is a potential difference, so it doesn't matter so long as you're consistent. After that you write your KCL (Kirchoff's Current Law) equations for each node summed to zero. The convention I'm using is: current out = [$+$], current in = [$-$]. You then solve for the node and once you know your node voltages, calculating the remaining branch elements is easy: just a case of $V = IR$
I have SICP work to get to now so I'll cut this short and pick up another time. I'll have to make pictures of the notes clearer.
Structure and Interpretation of Computer Programs (which is a full course, not just a book) has gotten a lot easier after I decided to follow the exercise assignments in Professor Brian Harvey's Spring 2011 syllabus. Even if I am running on an accelerated pace, I think I'm fine if I do the same work that Berkeley and Stanford students do.
I feel hesitant every time I say this, but the level of relative ease when I follow the structure of university programs is pretty noticeable. But I think it also has to do with me being able to better understand the material in more manageable chunks. Hey how about that, you gotta train smart in academics too, not just athletics.
On New Year's Day I got started on the 2nd assignment of Mehran Sehami's CS106A course. The course is Stanford's introduction to Computer Science for EE & CS majors. I took 2.5 hours to finish the first problem in the assignment, and got done right before going to a New Year's get together. I finished the rest of the assignment today. The first 2 hours and 10 minutes were spent trying to unknot myself and making things worse, and below is the result 15 minutes after throwing out all the code and starting fresh. I got the pyramid right side up a couple minutes later.
The big lesson is thought structure. The way these problems work is there's a way to pay 20 hours and maximal effort with mediocre results, or 10 minutes and no effort with full return. This extreme curve for problems in Informatics makes me think people like Nick Bostrom are definitely on to something in their view of the nature of intelligence. Maybe. I feel as though life is more linear, or maybe we're just used to seeing it that way. The world is pretty unforgiving in favor of who has the advantage.. so jury's out.
The mistake I made was not understanding the nature of the problem exactly. I had an approximate grasp of what I had to solve and what I had to do to solve it, but without the necessary tools of experience and brain-wiring to rely on.There is no winging new things unless you're interested in what not to do (which at an early stage is important). I wasn't sure to use a while or a for loop (hint: use for's when your iteration is definite, while when it's indefinite) and, here's the big part: didn't understand how my for-loops were iterating. That's kinda important. Anyway the result was a mess.
When I started over, I decided not to do it the way I thought others would have me do. I'm not a professional yet so how can I know? All I'd get is a crude approximation without any knowledge of the whys/ So I started building the algorithm the way it made sense to me: you have a number of bases and you have a rank number, both of which count down to 1. Vertical position is uses rank as a parameter, and horizontal position uses the formula: center position $-$ base number $*$ the width of the bricks, $+$ rank $*$ half the brick width. What that gives you is a value that starts out less than center, and eventually passes it. Rank starts equal to the number of bricks at base (this number is passed into the method) and counts down. The base number starts equal to Rank at each rank iteration and counts down to 1. So at Rank = 14: Base = 14,13,12,... etc. This means the program draws bricks at the widest level first, which is why I got the pyramid upside down: wrong vertical parameter. Easy fix.
The rest of the assignment went smoothly. It took me 2.5 hours to finish the remaining 5 problems.
Not much else to say at the moment. I think things are going smoothly. They can be faster and I need to make that happen. I get closer to getting my full list of work done each day. When I get to that point I'll add more. Now that we're at the start of the month - I want to have SICP and CS106A completely finished by February. I'm just about starting Calculus again and Electronic Circuits. I have an EC reading from months ago that I'll do, and then go back and apply my work style from CS to it. If you can do the exercises you don't really know the material. If you don't know the material you can't be nimble and inventive, and perform to your potential when you set out to build something. It all comes back to the same thing: it's on you to put in the work. I really look forward to burning through the EE work.
I started surveying MIT's 6.01 Intro to EECS I. I'm not an MIT student so I don't have access to the labs & etcetera, but I want a better picture of the path ahead. I'm just doing all the readings and watching all the lectures and recitations. I don't count it as taking a course but there's a use anyway. I think I'll survey 6.02 Intro to EECS II, which focuses on digital communication systems, afterwards. I just checked and the lectures and readings are all there so we're good. It's like sparknotes for independent study. I have a whole curated reading list cut out for me :). 6.002x, the Circuits and Electronics course I do take very seriously and I will get a certificate in all 3 modules on edX.
First work: I've done every exercise in the first chapter of SICP, a few in the second, I'm finishing the last exercises in the 4th chapter of Art and Science of Java, I finished lecture 2B of SICP, I am up to lecture 8 of CS61A Spring 2011, lecture 7 of CS106A. Today is Christmas, Day 25. GitHub repositories will be posted. OK.
I am not going to do every single exercise in SICP. That is crazy. I spent 4 hours yesterday trying to build a midpoint calculator for line segments out of constructors and selectors. Half of you reading will think that's baby stuff, the other half black-magic. I have to remember I have a timeline and I'm not doing anyone any favors by spending 95% of my energy trying to squeeze out the last 5% of understanding of CS theory - forget the 80-20 rule.
Two things that really made me think it's time to shift gears; I finally found the homework and problem sets for the Berkeley CS61A course: [here]. In fact it's a guys GitHub where he laid everything out. Thank you very much kind sir. Looking through the assignments I noticed.. UC Berkeley's famous EECS department is not making its students do every exercise in the book (maybe because they're not crazy). In fact, it's just a handful from each chapter. Well this was a welcome shock to me. The second thing is I took a look at the posting dates on that BilltheLizard guy's blog. I've been using his posts to help get me through when I'm stuck. His first post is in 2009. His last post, which is only 2/3 the way through the 2nd chapter, is in 2013. I'm a fucking idiot. But there are some things it's good to be wrong on, and answering diminishing returns with stubbornness is one of them.
So with that said, my work in the SICP book is going to be limited to the Berkeley homeworks + whatever I feel like doing. This should free up enough time for me to work on Electronic Circuits, Calculus, and maybe cure cancer.
On another note I had to get creative for a CS106A assignment. I'm not at Stanford so I don't have the little 'world' they want you to write the program for. So I went to YouTube, found a guy who explained how to use the editor, then I made a world that matched what was in the handout, did the programming assignment and it worked. Yay. Here's the handout: https://see.stanford.edu/materials/icspmcs106a/10-section-handout-1.pdf
I also cleared up the whole mess with Seton Hall, and now my transcripts are ordered for Stanford. It's a good thing they're lenient with extra materials, and it's completely understandable that, while they'll review an application without official transcripts, they will only make a final decision once they've got them. Anyway, even though the timing is off with the holiday season, they'll get there and worry on that front is over.
I decided on a final project for myself. A way of proving to myself that I've learned anything and moreso that I can actually do things. I want to do things with aerospace and technology... so.. okay simple. Build a drone. If I can put together pieces of metal and silicon and literally breathe life into the damn thing, then I don't need any more proof of what can be done.
The drone project also grounds my CS study, and gives a very real and immediate purpose to studying EE. It actually ties in a lot of things, but anyway.
So I'll be ramping up towards it. It's going to be some sort of arduino-controlled quadcopter. It's going to be fun putting together the mini-projects before hand where I teach myself the little skills I'll need to tie together later. Hey look, a crash course in Systems Engineering. So that's that.
I also haphazardly added another course to the work I'm doing. Since I cut out Codecademy as my lab (it's really on such a simple level that if I do it, I shouldn't really bother to count it) I have an extra slot. MIT OCW has this cool Intro to EECS course. I won't have access to the hands-on labs they'll do (but to be fair, I'm more than making up for that later so no complaints), but MIT put all their reading assignments online. I'm watching the lectures and doing the readings now.
I find it important because they emphasize getting different systems to work together and understanding that from its parts and as a whole. That was really the catch for me. That's about it for now. back to work, and happy holidays.
I got into a bit of a working groove and kept putting off a new blog post. Now I got quite a bit to put down here. Before we go in, a note: I need to start making small notes as I write. I often realize something, the feel of creating an algorithm, or how the work seems to be getting easier, or any one of a number of things - but those are the types of thoughts that flash for a few minutes before getting absorbed into your subconsciousness; small steps on the path of development, but very hard to identify explicitly until long after. Noted. So anyway..
What I've done in the last 7 days (I'm writing this in the morning of the 18th, so I haven't started working today yet).
SICP, Structure & Interpretation of Computer Programs:
Split up between work in two classes of the same name: MIT's 6.001 (original lectures & readings) and CS61A spring 2011 (Berkeley's class, with extra readings). The exercises are feeling a lot easier than they did at first. SICP is also starting to take less of my time than it used to. (I'm noticing a feedback loop---)
Exercise 1.14 asks to sketch the tree of the recursive count change procedure. This was the first time I really got an appreciation of recursion. I also had to specify its time and spacial complexity. Here's my sketch below:
1.15 quickly shattered the feeling of comfort I got from 1.14, and really drove home the difference between Normal and Applicative order evaluation. I'm still not 100% on it, but I turned what was a linear-recursive process into a tree-recursive one because I expanded it wrong on paper.
1.16 involved writing an iterative exponentiation procedure through successive squares using the identity: $(b^{n/2})^2 = (b^2)^{n/2}$
1.17 asked to define a multiplication procedure similar to the <<fast-expt>> procedure in the book, that uses a logarithmic number of steps. Think of a logarithmic progression as the inverse of exponential (but in the same direction). Whereas with exponential increase additional inputs are magnified, in a logarithmic increase additional inputs give rise to diminishing returns. This is why in orders of growth, Log(n) < n < n$^k$. Figuring out how to write the procedure also helped me unpack some important concepts in the book. Not 100%, I still had to use BilltheLizard's blog for help (I now use that blog as a kind of minimum-speed governor: when I'm stuck after a set time of struggling, or I need to check my answers I go there).
1.18 I liked a lot. In this exercise you have to take the русский крестьянский способ, Russian peasant method, of multiplication and turn it into code. The method is iterative, and to me says something about human development: it's an iterative algorithm for multiplying numbers that requires very little thought; like the finger counting games your uncle showed you when you were little. Why and how did this come about? Well this algorithm is just a version of one invented (for all we know) in ancient Egypt. So what's up? Well us humans needed a way to perform multiplication... now how does any sentient animal with no prior knowledge of mathematics do accounting? For all intents and purposes we at that stage were very similar to computers: we only know how to do very simple operations. So the algorithm is a way to accomplish a more complex task using very rudimentary tools to get the job done. Tricks. But useful tricks. And without understanding the nature underlying what you're doing. I think that makes sense of much of human history, and perhaps provides context for understanding the growth of calculation ability in a more universal frame. What. Anyway. If it works for ancient Egyptians and Russian peasants, it'll work for my computer.
I managed to solve this algorithm on my own, only using Wikipedia to see the actual algorithm. That's practice I need: take a concept and algorithm, and convert that into code. It's a great feeling when it works. The algorithm works thusly: take two numbers being multiplied, X and Y. Halve X and double Y to form a pair, and do it again until X = 1 (ignore remainders). The product of X and Y is the sum of all sub X & Y pairs, ignoring pairs where X is even. Example:
13 * 238:
13 238
6 476
3 952
1 1904 +
= 3094
Exercise 1.19 was harder and I had to look online to walk myself through the solution. Again, I'm always wary when I do this, but I'm counting on me having the judgement to decide when to let myself struggle and when the point of diminishing returns and inefficient use of time has been reached. This one was a case of using a mathematical proof and some math-jiujitsu to turn a recursive algorithm into an iterative one with a logarithmic number of steps. It involved showing that the Fibonacci sequence could be represented as a transformation function, which itself could be represented as a special case of a more general function $\rightarrow$ which it is your job to prove by showing that the special case can be written in terms of the general case, then turn it into a procedure. Notes in GitHub link above.
Exercise 1.20 stumped me one night, then I worked through it in 2 hours in the main library of Rutgers U. It asks you to write out the entire process taken by the <<gcd>> procedure evaluated in Normal and Applicative order. Applicative was straight-forward, Normal not so. I took a brute force method to get through this one: I put up a solution online, and started walking myself through it line by line until I understood what was going on. Then I started writing the entire evaluation process, checking my work at the end with the solution. This taught my the usefulness of indenting in Scheme, and some of the logic of Normal-Order evaluation.
For 1.21 and 1.22 were made more challenging because a necessary procedure, <<runtime>> was not available on the interpreter I use. I tried setting up the SISC interpreter which would use the <<current-inexact-milliseconds>> workaround, but after setting up Java to not block it on Firefox, no luck. I just did my best writing the procedures (timed tests for determining & finding prime numbers), and checking with results online.
Skipping through a bit, the rest was just work. I learned about how you can write a series-summation procedure and convert it into a product one; and for both define them either iteratively or recursively. This was further reinforced in Exercise 1.31 where I had to take the Wallis Formula for approximating Pi [See: Wolfram Mathworld, line (3)]. It was cool to see how surprisingly easy it was to take this big complicated formula, and just break it down into code; especially the series terms and how they progress.
The ease of 1.31 was probably made possible by the 5 hours I spent working on 1.29 where I took the Simpson Formula for approximating an integral and turned it into code. My mistake (though a useful mistake) was spending 4 hours working at the problem without looking at the help in the book. I was trying to reinvent the wheel by finding a way to capture the terms in the series and how they progress into sub-procedures; and for syntax I managed to confuse myself with how to define a variable in Scheme. Long story short, I learned a bit more on how to use summation for a series.
CS106A: Programming Methodology
After the pain of SICP, Stanford's intro CS course is like a gently breeze. I may be further along than I think, because, to my surprise, I find myself surprised by just how easy this class is. I'm also building better study/work habits, because a course is a totally different (and much more docile) animal when you do the readings and exercises before the lecture. This is my first time touching Java, and norms from SICP are spilling over. Finishing the Karel reader, I'm into the Art and Science of Java book and doing every exercise. I'm glad I took the time to figure out how to start a new Java project (wow is this language convoluted...too much overhead). I did the first assignment in the course, programming the little robot Karel to do a few tasks. Here I took what was theoretical in SICP and really reinforced and put it into practice; namely breaking problems down into smaller parts. There were 4 problems in the assignment. The first two were easy: pick up a marker on a tile, and write an algorithm to repair columns. The third: an algorithm to create a checkerboard, took me 10 hours. The biggest problem I had with that one was getting disorganized. There were too many branches in the algorithms logic, and my mind couldn't hold them all in at once, and it turned into a mess. Finally made it all work though. Because of the work on that problem, the 4th which was even more challenging, only took me 1 hour. It was simple: design an algorithm, map it out into its sub-procedures, write it. Fucker worked on the first run. That problem was designing and implementing an algorithm to find the midpoint of any line, without being able to count. I liked it a lot; it was using logic to solve a math problem. Cases like these make your eyes open to the possibilities of computation and what crazy stuff may lie ahead in the future. I like it.
I made a short video demonstrating a few of the programs, and a snapshot of the code as well. Also included is a snowman from a book exercise.
I'm noticing a kind of feedback-loop in my work. What I learn in SICP - whether it be technical, habitual, or conceptual - comes back and reinforces my work in CS106A. Then what I've put together in CS106A, a much easier and forgiving environment, comes back and strengthens my ability to understand and solve problems in SICP. And this process becomes more powerful and accelerates with each completion of the loop. It's interesting and we'll see where it goes.
Still, it may seem great, but it's necessary. Maybe another way of looking at things is to be grateful that they're actually working. Computer Science & Programming for me is a sideshow. After I get through this, it's back to Physics and then on back to Engineering. By that time I should be either in school or a company (my own or someone else's), so I'll have to make time.
As a side note, it was interesting to hear Elon Musk at a talk at Stanford Futurefest note that the logic behind CS is that it isn't capital intensive. While it's nice to hear what I've thought for about a year being spoken back to me from the ether, it also makes me wonder if I'm being too slow.
Gur du way, eh? That's the update for Day 18, now back to work.