Intro to tmux

Here’s rapid-fire part two of what I was working on!


Why tmux

Before beginning to use a new program, it’s good to keep in mind why it’s useful, or why one would want to switch to it from an older program.

The main point of using a program like tmux the ability to have a persistant session that we can attach to when needed, or use to run background processes. For example, if someone is trying to figure out a password, or factor large numbers, we wouldn’t want to occupy our whole terminal session with this. Generally, tasks that need to be run in the background or have states that we’d like to check regularly (such as a chat client) are reasons people create and use screens.
Since we have a good use case, this raises the question of why onw would use tmux over older terminal management tools (such as GNU screen). The two most commonly cited reasons are more control over the settings within windows and the ability to easily share windows with other users.
GNU screen has a couple strange quirks, particularly with its naming of windows within a screen. For example, if you open a window within a screen, the name of the window becomes the name of the first command used. This might be useful when you first run a command, but when you have several windows that say ‘sudo,’ the naming becomes less useful. tmux listens to the commands being issued and updates the name dynamically. A very good example of this usefulness is a long-term process that occassionally requires prompting. While it is open in another window, the long running process will be the name of the window. Then, when the user needs to respond to a promt, the window will change names to ‘dialogue,’ thus allowing the user to only check and switch windows when necessary (as opposed to disrupting workflow to tab to the window randomly). There are other more convenient UI aspects to tmux, but for brevity we’ll keep examinition of UI features limited to this case.
The primary advantage of tmux, though, is the ability to easily and conveniently share terminal screens to pair program. This allows two or more users to look at the same terminal and learn how to use commands, or review code. This is convenient because sharing a view this way requires much less bandwidth than using a program like an online shared document, or a screen sharing program. Additionally, even over good connections, it allows many people to look at the same code without having to crowd over someone’s shoulder.
We can see that using tmux is well motivated, and so we can proceed to set up and share a tmux window with another user.
Creating a tmux Session

In order to create a tmux session, we first need to install the program. The method of actually installing varies by the specific operating system and package manager. You can find installations on the website, or on the github. It’s good practice to make sure the most recent version is properly installed on the computer using `tmux -V`. If it is not, you may need to install tmux from source.

Creating a tmux session is a simple as typing the command `tmux`. This will open another view, which will work just like a normal terminal. You can edit files, run code, issue terminal commands, etc. When you are finished with this session, you just need to type `exit`. This closes tmux and returns to the normal terminal. If we type `tmux` again, we will get an entirely new, blank session. This underutalizes the main functionality of tmux: persistant workspaces we can detach from and return to later. We can have persistance if we create named sessions.
We can create a named session by writing
$ tmux new-session -s test
which can then be shortened to
$ tmux new -s test
This creates a new session with the name “test.” When we open this session, instead of exiting when we are finished, we use the command `Ctrl-b d`, (meaning we type Ctrl and b together, release these, then hit d). This command tells tmux to detach from this session. Then, we can reattach by using the command
$ tmux attach
 in the terminal. We may want to create multiple named tmux sessions. When we do this, simply writing `tmux attach` will not put us in the correct session. And so we now need an argument:
$ tmux attach -t session_name
We can keep multiple sessions running in the background, and attach/detach as we like. We can see which sessions are open by using the command `tmux ls`.
While within the session, we can create windows. Windows are similar to tabs in a browser: they allow for independent actions and processes to occur in parallel. We can move within windows by using `Ctrl-b n` to move to the next window, and `Ctrl-b p` to move to the previous window. Additionally, all windows are numbered and can be moved to directly by typing `Ctrl-b number`, where “number” is the window number. There are many other ways to interact with and optimize the workstation, but that is outside the scope of this document.
If we no longer want a session to exist we should either exit or kill it. While in the session, we type the command
$ exit
This will remove the session. Sometimes, one of our sessions will have a process that becomes unresponsive. We won’t be able to exit the session, but we instead need to kill the session. This can be done with the command

$ tmux kill-session -t session-name

Sharing a tmux Session

We have three options for sharing. One option is to create a new account on a server, and then have all participatnts log in or SSH into this account, and use an identical paired session. We could also create a new account, and allow all users to log onto it to access a grouped session. Finally, we can use tmux’s socket infastructure in order to allow users from different accounts to access the same session. We will be examining all of them to understand how they work and are used.

Before creating any kind of shared tmux session, we need a way to safely (ie, without compromising our account) allow others to join a session. It is optimal to set up a virtual machine (using something like VirtualBox) and then create an account that users can ssh into. It is also possible to create another user on your computer, and create a shared tmux session there.
The Unix command for creating a new user is:
$ sudo adduser user_name
It’s important to note that “adduser“ and “useradd“ are not the same commands. “useradd“ is much more low-level, and users are discouraged from this command ( for more explanation, see $ man useradd ). We’ll then be asked for and set a password. It’ll also ask for a name, room number, phone number, etc. These can be ignored, and it’s fine to initialize the user without them.
With that, we have the infrastructure to properly share screens.
Pairing with a Shared Account
After creating a new user on the server, we send the login information and IP address that other individual(s) can SSH into. We, too, log into this account (either physically or by SSH). Then, we create a tmux session, and name it appropriately. We send the session name so that the other individual can attach to it using the name.
[other_user]$ ssh user_name@ip_address
[user_name]$ tmux -t session_name attach
When we are done with this, we can exit the session (or detach, if we wish to collaborate with this person on more than one occassion) It’s worth noting that because we have shared the login information with someone else, they could potentially log in and change settings (including the password to this account). Changing the password or removing this account from the network are recommended.
Grouped sessions with Shared Accounts
As with the previous method of sharing accounts, both we and the other individual will log into the same account. However, our method of attachment will be slightly different. In this case, we will create a session by the command “tmux new -s session_name“. Then, when the other individual wants to join the session, instead of attaching, they will create a new session by specifying the target of the session as the name we chose, and then specifying their own name in this form: “tmux new -t session_name -s new_name“.
This will then allow us to share sessions with another person. The difference between this and the previous method is that users can independently create new windows. When the other user creates a new window, they will move into that view, but we will remain in the original view. Thus, we can act independently in different windows. This is really useful if we want to try something in another window without potentially confusing another person, or if there are very different preferences in some program that would be useful (ie, if one person uses Emacs and the other Vim).
The user who created the new session using “tmux new -t session_name -s new_name“ can then kill their session, and the original will still exist. If all windows are closed, both sessions will be killed.
Paring with Separate Accounts
In this method, we will create a new account (or as many new accounts are needed) and will use groups to share this session. We will then create a group using “sudo addgroup tmux“. We add each user to the group (including ourself) with the command “sudo usermod -aG tmux user_name“. We will then create a folder that will hold the shared sessions, and give our group access to it as follows:
[]$ sudo mkdir /var/tmux
[]$ sudo chgrp tmux /var/tmux
[]$ sudo chmod g+ws /var/tmux
We log into our account, and create a new session using sockets, “tmux -S /var/tmux/session_tmux“, note that while we had been using “s” previously, to specify a tmux socket, we use “S”. The other users in our group can attach to this session using the command “tmux -S /var/tmux/session_tmux attach“. This has about the same effect as pairing with a shared account, but allows users to log in with seperate accounts.
Summary
tmux is a powerful tool that allows for more control over terminal settings that the popular GNU screen. The most clear advantage, though, is the ability to share terminal sessions with another user, which allows for easier collaboration and instruction than the popular method of shoulder-surfing, or trying to use high-bandwidth websites to share screens. There are many ways to accomplish this sharing, each with their unique strengths.
Tagged with:
Posted in Personal Projects

Mobile Shell

Hello, all! I occasionally do this thing where I disappear from the face of the blogosphere for school, and then resurface with things I have written. This IAP I was working at an exciting startup, and I spent time writing up some of the things I learned.

Overview
Mobile Shell, Mosh, is a remote terminal application that works under shoddy connections. The current standard for remote terminal applications is Secure Shell (SSH). SSH is conducted by secure communication using a protocol called the Transmission Control Protocol (TCP). This protocol operates by sending steams streams of reliable, ordered, and error-checked octets, similar to “bytes”, over an Internet Protocol (IP) network. There are several issues that come about with the use of SSH that Mosh hopes to address.
The main challenges with SSH come when we are operating or trying to connect to a remote server via a slow network. Because SSH uses TCP, we know that any information sent to the server (or received from the server) will be accurate and ordered. Because the octects are checked during each information transfer, we know this will naturally be slower. With SSH, every single keystroke is sent to the server, confirmed, and information is sent back. Over a slow connection, this can take up to a second per character. Given that the average user will type faster than one character per second, the delay between characters being typed, acknowledged, and then displayed on the terminal. This frustrating delay renders the connection effectively useless. Another challenge that Mosh hopes to address comes from havign connections over mobile networks. Because SSH operates over an IP network, the connection to the server only persists when the IP address is static. This means that if a person is connected to SSH over WiFi, they could lose their connection as they walk through the building and switch IP addresses without realizing it.
While SSH might be a reliable and useful tool when stationary, many users are connecting wirelessly and would prefer to not have to deal with these issues. Mosh hopes to address these problems in two ways. First, Mosh uses a protocol called State Sychronication Protocol (SSP) that sychronizes the terminal with the server and addresses the fact that mobile users will want to stay connected even when they switch networks. Additionally, Mosh employs a predictive algorithm to guess the effect of the keystroke on the server, allowing users to type without slow connections significantly affecting their workflow.
Theoretical Basis
TCP relies on a static IP address to send data back an forth. As a result, the connection relies on this IP address being unchanging. Instead, Mosh is built on top of a different protocol called the User Datagram Protocol (UDP). This protocol allows communication over an IP network, even with no prior connection or authentication. Additionally, it does not not error-check datagrams during transmission, and instead relies on the application for this process. It also does not make guarentees that the data is received in order. Because of this, the connection is faster, and communication can continue over new IP addresses. This is incorporated into SSP.
Not all of the communication is done over UDP. For the initial connection to the server, Mosh uses the same protocol as SSH. It first authenticates the client with TCP. As soon as this connection is made, a randomly-generated, shared encryption key is passed over a UDP channel. All messages sent between the client and the server are encrypted using this key and AES-128. When both the server and the client have this key, the TCP connection is closed, and all communication is done over UDP. SSP is instantiatied in both directions instantiated on two different “objects”: the object represents the history of the user’s input when sent from the client to the server, and the contents of the terminal window when from the server to the client. When we discuss objects, we are referring to these two
This protocol has two main layers that have related but different functions. The first is called the datagram layer, and is responsible for relaying packets over the network. The transport layer relays the current object state to a remote host.
Datagram Layer
The datagram layer is responsible for encrypting the datagrams sent between the server and the client, informing the server of the current IP address, and estimating round-trip time (RTT) of datagrams.
The datagram layer accepts something called “opaque payloads” (roughtly “encrypted datagrams”) from the transport layer. It then prepends these datagrams with an incrementing sequence number. Using AES-128 and the shared key, the packet is encrypted. Then it is sent back to the server as a UDP datagram. Each time an authentic datagram from the client with a larger prepended sequence, it sents the source IP address and UDP port as the new target. The fact that the sequence is increasing is important — since the the server only updates the IP address and port when the sequence is larger, implying that it is the most recent datagram received. This removes the possibility of receiving packets out of order, and setting the target of future datagrams to an IP address that no longer points to the user. This system allows the user to roam, often unaware their IP address has even changes.
In order to properly deal with the reordering or loss of datagrams, we rely on an idea called idempotency, which means that we an apply an operation multiple times, and only the first applictation will change the value or state. A simple example of this is the absolute value operator. Each datagram sent to the server represents an identempotent operation, called a “diff,”” which is a change between the current state and the target state. Because diffs give the change explicitly, we no longer need to keep a replay cache (unlike Kerberos).
This layer also manages to capture information about the speed of the network, which then influences the frame rate of the session. They use the basic algorithm of TCP and make three changes:
  1. Each datagram has a unique sequence number, as discussed above. Thus, if a datagram is retransmitted, there is no ambiguity about which is first.
  2. Datagrams have millisecond timestamps. This protocol automatically adjusts the timestep reply by a simple subtraction of when the packet was sent vs received.
  3. The time of retransmission in SSP 50ms instead of TCP’s standard 1s, meaning that if we manage to lose a packet, the server will ask for it quicker. This helps reduce delay in typing and commands being displayed.
We then have an understanding of the datagram layer of the protocol, and can consider the second piece of the protocol.
Transport layer
The transport layer synchronizes the contents of the local state to the remote host. It is agnostic to the types of objects being sent back and forth, meaning it has the same behavior if it is sending user commands or the terminal window. It manages both the behaviour of the sender and the timing of the sender.
The sender updates the reciever to the current state of the object, typically either new commands or the terminal window’s date. It does this by sending something called an Instruction: a message listing the source and the target state, and a binary diff between them. The behaviour of this action depends on the object being sent, not the protocol itself. Specifically, when considering the user object diffs, we have differences in the form of keystrokes. From the terminal window (sent by the server) we get a message that tells us how to change the client’s screen appropriately.
Because SSP works by creating diffs, it’s not necessary to send every octect recieved from the server (though every octect the client sends must be relayed to the server). Thus, SSP adjusts how often the server sends information based on the RTT estimate calculated by the datagram layer. This frequency is called the frame rate. The minimum interval between two frames is half of the RTT estimate, so there is about one Instruction being sent at a time. The sender does not immediately send an acknowledgement (ack) of the message, but instead uses a delay of 100ms, and this reduces excess packets by allowing the ack to be sent with host data. The server also has a delay when the object it needs to sends first changes to avoid sending many partial updates (and waiting the frame rate each time). And so the server pauses for 8 ms to allow changes to be sent together.
Besides transporting datagrams, SSP sends out a “heartbeat” every 3 seconds. This heartbeat is sent to the server to alert it of an IP address change, and to allow the user to know if the client has not heard from the server recently. The heartbeat also keeps a connection open when the client is on a network address translator (NAT).
This layer is the second piece of SSP. The other key piece of Mosh is the predictive aspect of the terminal
Speculative Echo
Many commands have a very predictable behaviour. One clear example of this is ^C, which kills a runaway process. In a traditional SSH session, this process would continue until the client could communicate with the server, the server processed this command, and the server can send back the current terminal window the the client. In Mosh, however, we know the result that this will have on the window and can apply this effect immediately. More generally, when there is a task being done, the client can guess the effect that this will have on the terminal. When there is a large delay, Mosh will underline unconfirmed predictions so the user is aware that the changes have not yet been processed by the server. When there are mistakes, these can be correected within the RTT, which is on the order of milliseconds. This allows a greater functionality of the terminal, since the view on the screen will closely match the user’s typing speeds.
Speculative echo is only feasible in instances when the behaviour is easy to predict, such as typing long strings in a file. Less predictable operations, such as hitting the up and down keys, occur at approximately the same speed as an SSH connection.
Conclusion
Mosh is an incredibly useful protocol that makes SSH usable in many situations. I’ve begun using Mosh on my own computer, and you can find the Chrome extension here. Additionally, I would highly recommend listening to keithw’s presentation on the paper. It’s very imformation packed, so don’t be worried if you need to listen to it a time or two.
Tagged with:
Posted in Personal Projects

Teacher Observations

Sorry that all I’ve been posting lately is things I’ve been writing for my teaching class. My next big software project is in the works and I’ll write about it when I have something non-trivial. For now, though, I offer up my experiences in observing a teacher in a Boston public high school for about 20 hours this semester.

Speaking of teaching, I’m also doing a bunch of Splash classes this weekend, and a sample lesson for 11.124 tomorrow! I’ll keep a record of how each of these classes went, and what I noticed about my teaching (plus links to any lecture notes or slides I use).


Cyber Security – October 8th

The first day was a whirlwind. I met Mr. Teacher Man early in the morning before the morning announcements. It was very strange to be back in a high school, sitting in a desk and listening to the teacher while taking notes. Besides the strange familiarity and confusion as I navigated the new school, I was able to see how to address computer science concepts without using any programming or even a great deal of technical terminology.

Class began with a slow, slow start. The school itself has no bells that ring when classes end, so students trickled in and out of their classes. To compete with this problem, though, classes begin with something called a “Do Now,” where the stduents work on some type of activity that allows them to explore a concept or practice solving particular problems. Here, they were considering the question “what is computer intelligence”? After thinking and writing for a few minutes, the class came together for a guided discussion about what it meant to solve problems and think. Mr.  Teacher did a great job at introducing complex ideas like the Turing Test, by explaining a simpler and condensed main idea, and not giving it a name (which I believe makes students worry about memorization). Overall, this seemed to get the students thinking about what problems are important to address without being distracted by technical details.

The class then moved onto discuss topics in cyber security, and what it meant to have security. This involved two useful components. The first component was a set of definitions the students needed to learn. The definitions we done first by students, and each student defined a word (like “hacker”) using only 3 words. They would do this for each word. After some set amount of time, students were asked to offer up their definitions to be used as the class definition. After this, Mr. Teacher would write the definition he used. This was an interesting method, as it gave students the chance to think about the words as opposed to blindly copying what the teacher had written. This allowed students to work through ideas, and then discuss as a group, and thus allowing more connection to the material. Unfortunately, having student discussion meant the class was slowed, which means a teacher needs to be careful evaluating and moderating commentary.

Once definitions were taking, students watched a video made by PBS about the challenges that occur with having everyone connected via the internet (and how vulnerabilities in computers can effect a greater network). I noticed that students seemed very disengaged and many did not even appear to be paying attention to the video. While it is important to show clips and have different perspectives, I wonder if there is a way to have video and also have students interact and engage with it. The students then got laptops in order to work with a web-based programming challenge (similar to Scratch) that allowed them to see how they can write instructions in a systematic way. This was loosely based on security concepts, but this seemed lost on students. I believe this could have been remedied with a bit clearer explanation of the task (ie, think about a program like this, and the interface works in this way). Additionally, many of the students failed to even start the assignment, and instead turn their computer screens away from Mr. Teacher.

It’s unclear how to make students accountable for these actions. Both of these materials are excellent tools for learning, but students lack the interest to follow through. One option that my high school teachers used was to give worksheets in which we answered questions about the video or activity as we went along. This can’t always work, however, as stuents should also be able to learn skills of responsibility and autonomy in learning. I think another possible solution is to have a post-assessment quiz, but that can lead to a stresfful activity as opposed to exploratory.

Regardless, I think that Mr. Teacher did his best to vary the activities in the classroom and have interesting activities that guide students through the material. Monitoring a classroom is certainly a challenge I do not know how to address.

Inverses of Functions – October 15th

One of Mr. Teacher’s greatest strengths in the classroom is creating worksheets that lead the students through the material while still allowing them to make guesses about how something will work. Class began with another Do No, where students were given about 5 minutes to work through a couple problems. Mr. Teacher reviewed the homework with the students, and afterward they called out their score (for accuracy and completion), and I immediately noticed bias in student answers, and a student near me had a blank paper, but called out a perfect score. There certainly should be a better way to collect and score these homework assignments.

After this, students used their understanding of composition of functions to examine compositions of functions, like f(g(x)) and g(f(x)) where f(x) = 3x and g(x) = \frac{x}{3}. Students wrote down what they noticed about these functions, and saw that when they were told that two functions were inverses of each other, the compositions just equaled x. They then moved into an activity where they sketched graphs, and made tables of inputs and outputs. Because of this, they were able to observe patterns before being told how to rotely find the inverse function. (I can’t recall my own education, maybe I should ask Mrs. O about this)

Outcry came from the class when Mr. Teacher tried to formalize the idea of a function, and introduced the symbols \forall  and \exists. This raises the question of how to introduce mathematical notation, and the idea that we can generalize statements to be true for all numbers. It’s also interesting to watch Mr. Teacher explain these concepts — he falls into mathematical language and sentence structures rather easily (as he was a math major in college) which I think confuses the students. Fortunately, they are quick to call out and complain about the issue.

Mr. Teacher is very big on the idea of guiding students through concepts, and explaining after they have intuition. This is also how I tend to teach, so I note the bias in my recollection of the class. It also possible that it is not entirely his decision — the school appears to encourage (or maybe require) teachers to follow the form of Do Now/work/Exit Ticket. Though the class went rather slowly, due to student tardiness and talking during class, the material was presented clearly and concisely.

Student Interactions – October 22nd

This day I spent a great deal of time working individually with a student, and then listening in and participating in a discussion during “academic advisory.” Instead of observing the computer science class in the morning, I working with a struggling student who was in Mr. Teacher’s Pre-calc class. This student was preparing a cheat sheet for an upcoming exam. This was to be a double sided sheet to review material from the first quarter of the year. (Ironically, I was also working on making my own cheat sheet for my algorithms class). In this, I tried to both explain the concept of making a condensed sheet of notes that have things you don’t remember and also teach this student concepts they didn’t quite understand.

This resulted in me being very confused about how to explain limits. It’s difficult to come up with an easy example while not glossing over important details (such as the fact that the limit of a function as it approaches a point is not necessarily the value of the function at that point). Additionally, it’s hard to keep coming up with different phrases for the same concept in order to ensure that I’m not repeating myself over and over again with the student becoming more frustrated. I think the maor problem was that limits are so engrained in my academic life, and I work wih the concepts so often that I can no longer remember how to intuitively explain them. I had the same problem while trying to algebraically find the minimum or maximum of a function (I could only remember how to use calculus).

Something I noticed from this hour-long review was that it is incredibly difficult to assess when a student actually understands a topic, or if they are trying to hide the fact that they are confused. As a result, I started making examples on the fly (which occassionally failed). If there are any suggestions about how to better engage and assess student understanding, I would greatly appreciate pointers.

Academic advisory also allowed me to gain a glimpse into how teachers can interact with students. In this class, seniors were discussing their future plans and anxieties about college. This started by addressing study skills, and recognizing that going to college would be harder and that they were unsure if they would be prepared for the challenge. Mr. Teacher discussed how he had a difficult time adjusting, and when one of the students said “But you went to (prestigious university) of course you had a hard time,” he snapped back about how the student didn’t understand. Something I am never sure about is, in an educational situation, how much do you allow the students to see and how much do you hide. For example, students might benefit from knowing that I have failed in college over and over. But that might come at the cost of respect. The balance is unclear.

This also brings the point of discipline, where it’s unclear how to draw a line between allowing students to engage with you and have a closer relationship, and where student behavior becomes distracting or takes away from the educational environment. I’m sure that people have thought hard about this problem, and there are certainly papers about the topic. I think that, while discussing how to educate is important, teachers should also be taught about how to be a mentor.

Subtle Graph Theory – November 5th

The day of my 6.042 exam, of course the computer science class is covering graph theory. Of course, it was not explicitly called graph theory. This is what I love most about Mr. Teacher’s style of instruction: students are solving problems and learning strategies without being scared by the fact that they are doing a somewhat complicated problem.

Here the class was started by considering the concept of efficiency, and looking at how students define good problem solving. This also included the equation “efficient = smart + lazy” which I found amusing. Anyway, after the students were given a problem about handshakes: if everyone in a group of 10 people shakes hands with one another exactly once, how many hand shakes occur? I personally solved this problem by looking at the degree of the edges in a graph (where edges represented handshakes and nodes represented people). Mr. Teacher and I walked around the room and talked with students about their solutions.

Unfortunately, almost all of the students thought about the problem that they had previously done, where everyone goes down a line shaking hands, meaning their solution was 90 instead of 45. As I walked around, I noticed that most students did not care about this problem, did not listen when asked to work on the problem, and instead talked about random events and gossip with their groups.  This class seemed to be the least efficient of all the classes I have observed. Students wee distracted and didn’t solve the problems with extra time, and had difficulty explaining how to generalize their solutions.

I’m curious if the class would have gone over better if the idea of graphs were discussed  or if they were given a smaller number (say, 3, 4, or 5) to think about and work through completely. I think that this is one instance in which the method of introducing the problem before the tools was ineffective in the classroom. This makes me wonder if there is something fundamentally different about this, perhaps related to the fact that students were given a very open-ended problem with little instruction or direction.


Overall, I have enjoyed working with the students and Mr. Teacher, and I look forward to continuing my math/science education licensure.

 

Tagged with: ,
Posted in Teaching

Structure and Innovation in American School Reform

Hi, all! I wrote another essay! I have many essays to write, and soon I will also be publishing blog posts from my obeservations. Hopefully I’ll also get around to writing up some of the data science-y things that I’ve been working on. For now, though, I offer another essay about how many feelings I have about education.


Regardless of how the school is physically built, or what bell schedule is used, or what teachers discuss on their in-service days, I came out of high school feeling that strictly regimenting students and forcing them to conform to specific standard significantly decreased student’s desire to learn, and made them overall less cooperative. Student individuality is a very important value in a school that I would want to teach in — from their dress code to the rules governing behavior to how they graduate. As an extension of this student independence and individuality, teacher individuality and autonomy should be respected and encouraged.

I went to high school in a rural town in Pennsylvania. Our teaching staff was entirely white, almost all had grown up in the area (many even graduated from my high school). The school board had only one woman, and the board was made of almost entirely Catholics. This seems like it would not have significant consequences, but the merging of Catholic school values with my public school became more clear over time. It began with complaints in elementary school classrooms, “Kids at Saint Joe’s [the local Catholic school] have so much neater handwriting! They are so much better behaved and more respectful.” The Freedom from Religion Foundation threatened to file a lawsuit when they were informed that my school had a chaplain say a school-wide prayer for Veterans’ and Memorial days. We had a “strict dress code policy” that meant students needed to wear solid black, blue, red, or white collared shirts, and khakis of specific colors. This happened during my time as a student, and I was able to watch students react to the various policy changes, and saw how it affected their attitudes about the school, and their desire to work.

The student motivation and anger with policy changes was not just something that could be noticed by talking to students. One of my teachers plotted test scores by year, for both the spring and the fall. There was a small dip the fall of my 7th grade year when students were no longer allowed to carry backpacks. Scores went up slightly over the next exam cycle, and dropped dramatically when my school banned hoodies my freshman fall. Scores crept back up, and then, when I hit sophomore year and the uniform dress code was enacted, we became a failing school. Whenever the administration would take away student autonomy by enforcing more rules, students lost motivation and felt their performance didn’t matter.

When we became a failing school, I felt the impact of the No Child Left Behind every day. My mornings at school started with two questions pulled from state-issued practice tests, and homeroom scores were aggregated and the winning homeroom from the quarter was given a dressdown day, were the students were able to wear jeans and a tee-shirt (as opposed to our usual khakis and polos). My American English class made about ten percent of the final grade dependent on passing practice versions of the state standardized tests. My physics class was required to spend time going over biology because it was addressed on the state test.

In addition to making all of these additional practice questions required and having additional instruction on test-taking and exam specific information, my high school changed its graduation requirements. Previous to becoming a failing school, my high school had fairly basic requirements: 4 years of science, math, social studies, and English; a computer class and a language class. The idea with this meant that students would become well-rounded, while in actuality there was so little variation in the curriculum that all students were forced into the same boxes. Classes that were considered non-standard, like “Physics and Engineering” (our attempt at Electricity and Magnetism)  or Ecology, were seen as classes for students who weren’t motivated, and so they moved slowly and taught relatively little. And so all the differently shaped students were forced to fit in the same round hole. We also had something called a “graduation project” which was supposed to be a community service project, but certain students could substitute for a science projects, generally the model student type. This community service project was to be completed outside of school. As a rural school, it was difficult for students to get places to volunteer. As a school with 50% of students on free and reduced lunches, many needed their time outside of school to work, or did not have the means to volunteer (for need of work, babysitting siblings, etc). This was a difficult requirement to meet.

After we became a failing school, on top of these requirements, students needed to score Proficient on state standardized tests. Since our school only had twenty-three required classes, students could graduate in three years. But with the standardized test requirements, students had to wait until their senior year, since they needed to take the exams, or needed to score better than they did junior year. Students who did pass during their junior year felts as though they no longer had a reason to be in school, but couldn’t graduate, since graduation projects were presented at the end of a student’s fourth year. As a result of these attitudes, the classes I took with seniors were the least productive and most sluggish classes I took. Students and teachers both felt that these classes were a waste of time.

I believe that portfolio based assessment is going to be the next way that teachers assess students. These portfolios allow students the freedom to create their own presentations, defend their ideas, and take responsibility for working on a large project. There are many studies which link student autonomy (and teachers who promote student autonomy) with success in the classroom and with the development of positive character traits.

The culture of a school stems from the administration of the school, and the policies in place can significantly affect the motivation of students, as I have shown by example above. By having such strict rules, schools either need to hire an additional staff member (or members) to enforce them, or require teachers to monitor students closely. This monitoring detracts from the ability to teach, and puts the burden of writing up students and filing reports on the teachers. These reports often are filed during preps, meaning that they are less prepared during the lessons.

When teachers feel that they do not have control of their classroom, the overall amount of effort and enthusiasm decreases. I saw this with two different teachers: my English teacher mother, and my high school Spanish teacher. My mother started out her teaching career able to design her own material, modify the texts as she wanted to suit different student abilities, and was able to create candid projects for her students to connect to the stories they were reading. Over the next 5 years, standards for English state assessments changed, and her time preparing for classes became devoted to meetings about these standards and she lost autonomy in the classroom as she was pushed to use specific review material and have oversight by the reading coordinator for the elementary school. This oversight came from the reading coordinator, as well as instructional assistants (who are not certified to teacher), being in the classroom and interrupting lessons to talk to students about class material or their behavior, and trying to steer my mother’s classroom in directions they felt fit. As there was more oversight, interruption, and when her ability as a teacher became based on performance of her students two years after teaching them, she stopped being as excited about teaching. Now she can’t wait to leave the profession (despite loving her students and enjoying teaching them and facilitating learning and discussion) all because she lost her autonomy. One of the teachers in my high school also felt this pressure of having to monitor students dress, and eventually gave up, or would offer snarky comments about a student’s “illegal pants.” Though this is a frustrating topic, he still feels as though he has control over his material, (note that the Spanish department is not accountable for any state standards). I wrote to him and asked about the autonomy he has in the classroom and offered this explanation, “Our department does not force teachers to present their information in any specific way, provided that all topics addressed in the curriculum are presented. In my past district, all teachers were required to give the same final exam, which I found constraining. Complete instructional freedom is paramount to good teaching, in my opinion.”

I don’t believe that my situation is particularly unique. Throughout the history of education, it seems that teachers have not had complete control over how they operate their classroom, or the material and skills they are supposed to be teaching. Through reading Schooling America: How the Public Schools Meet the Nation’s Changing Needs, we see that policy and public opinion determines what goals education has, and that teachers are expected to follow these expectations. At the turn of the century, teachers worked hard to assimilate immigrant children into American life. Philosophers and thinkers talked about how important it was to democracy to have educated American children, and so common schools put up flyers to advertise this, and the educators adopted this principle. (p 8-18).

When that was no longer sufficient, teachers needed to adapt to teaching trades, which came about by the Smith-Hughes Act of 1917. This provided public funds to teachers who were willing to teach students “workplace skills.” (p. 44) Here we see an instance of the concept of allocating money to schools willing to operate under specific standards, much like Race to the Top.  When the public believed that scientific management (and effectively treating students as components on an assembly line) was the correct way to view education, teachers in teaching colleges were taught how to make tests to “scientifically measure intelligence” and schools grouped students by grade, meaning that a teacher would see sixty-six students in the morning, and sixty-nine students in the evening. And so teachers needed to adapt to large classes of students all learning the same thing. (p. 30-32)

IQ tests were created by a team of psychologists in the 1920s, and this was seen as an objective way to assess a student’s intelligence and learning abilities. These tests were brought into schools, at a very high expense, and was used as a metric for student success and knowledge (p. 72-73). In this section, there is not a single mention of teachers being able to choose to use these tests, and it seemed to be entirely left up to the administration.

This pattern repeats over and over through the next hundred years, up to the present date. Despite how people have viewed the goals of education over time, a constant is that the voices of the students and teachers are lost, and that teachers are at the whim of these forces that they can neither affect nor control. Teachers lose control over what they teach, and what their focus should be, and need to adapt to the new standards and desires of the public.

We can contrast this with the schools that we learned about. A particularly good example of this came from watching A Year in Mission Hill. It starts with the freedom of the teachers. They are not being held to specific measurable standards, and we see this very clearly when the principal refuses to give into pressure of teaching to standardized tests. The teachers have clear control over their classroom, and structure it in ways that are most beneficial to the needs of their students and their subject. In addition to teacher autonomy, we also see that the students have autonomy as well. They help create the rules, work on classroom activities how they see fit (like the bake sale), and choose their own final project in subjects (from dance to African history).

I saw my high school become more stringent and more strict during my middle and high school years. As student and teacher autonomy were taken away, the overall morale of the school community dramatically dropped. While there seems to have always been a culture of ignoring teachers and students when deciding education policy, I truly believe that a successful educational system hinges on giving these people decision making power while they are in the classroom.


For additional reading, see

Autonomy Supportive Teachers: How they Teach and Motivate Students; Reeve, Bolt, Cai; 1999

What’s Decentralization Got To Do With Learning: School Autonomy and Student Performance; King and Ozler; 2005

Learning as a Dialogue: The Dependence of Learner Autonomy on Teacher Autonomy; Little; 1995

Tagged with:
Posted in Teaching

Learning Science, Making Pulleys

Hi, all! Some of you may (or may not) know that besides studying computer science, I am also pursuing a liscense in secondary science/math education in Massachusetts. Education is definitely a passoin of mine, and I am always interested in sharing what I have learned in these endeavors. Soon I plan to write blog posts about my experiences doing observations in a classroom in a charter school in the area.

The following post is an essay that I wrote for class about an assignment where we tried to lift a 75 pound weight (75 pennies, in the model) with a 50 pound weight (50 pennies) and using as many pulleys and as much string as we desired.


 

What happens when you ask 4 MIT students to recall content from a class they took their freshman fall? Overall, we weren’t really able to remember the equations and concepts used. We took pulleys, and stared at them confused wondering what to do. With a little bit more thinking, though, we were able to use problem solving skills developed over time. In one way, we could view this as our education failing us: we weren’t able to recall a simple concept like torque or force on a pulley. But I view it more as what the education system has been able to provide me with, namely the tools to effectively communicate a problem, a set of problem solving skills, and a rigid thought process to fall back upon.

In class, we read Chapter Two of the book How People Learn. Here it addressed the concept of how experts think about problems different than novices. Experts are more likely to recognize underlying concepts than novices, meaning that they have developed a sufficient pattern-matching mechanism to see how specific problems are related. Novices, however, are more likely to find superficial details about a problem which they focus on. They also are more likely to blindly apply concepts they have learned, without considering how this related to the problem. The most poignant example of this was students asked the nonsensical question, “There are 26 sheep and 10 goats on a ship. How old is the captain?” While we recognize this is nonsense, children tried to blindly add and subtract because that was what they did when they saw two numbers together in a question.

Our group fell quite close to the novice category. We did have one physics major among us, but he focuses on space and not on small physical systems. The rest of us had just really taken 8.01 (or in my case, 8.011). Because of this lack of experience with solving these types of problems, we thought of this more as a “problem about pulleys” as opposed to a “problem where we needed to balance tensions.” We also stumbled along through this problem, randomly trying one thing after another, trying to rely on our memory of using multiple pulleys to solve this problem.

Our group first created a one pulley system, where we simply tied a string to the two weights, put the string over the pulley, and dropped it. Though we knew that this wouldn’t work, we wanted to confirm our intuition about the problem, and see any other factors that would occur with a real system instead of just something we imagined. Once we confirmed that there was some variance from ideal, and that we could work past it, we started thinking of other solutions. Because we had all done introductory physics, we had a basic idea of a solution that we vaguely remembered. Something along the lines of the phrase “more pulleys is more better.” We decided to put three pulleys onto the Lego building we constructed.

While this is in part because of our lack of understanding and acting as novices, I believe that we also tried this first because of our science education. Most of our science classes from elementary to high school stressed that the scientific method was a rigorous set of steps which allowed us to understand and discover things about how the world works. The first step in this process is collecting observations about the world and using that to develop understanding about the problem. And here, the first thing we tried was collecting observations and information.

To understand how ingrained the process of the scientific method could be, I offer my educational experience as an example. Through elementary and middle school, teachers did science projects, and presented the act of doing science in a very rote, mechanical way. The exploration and idea generation was lacking. We did not develop most of our experiments or labs that we did. Those which were created by us were very trivial and obvious. For example, when I was in 4th grade, we needed to write up an “experiment” in which chickens hatched after being incubated. The first step was reading about chickens and incubators. We then developed a hypothesis, “If we keep the chicken eggs at the correct settings (like temperature), then most of them will hatch.” We carried out an experiment of keeping chicken eggs warm, and then, for our conclusion wrote, “Our hypothesis was supported. We kept the chicken eggs at the right settings and they hatched.”

That style of learning worked against students in one way; it was terribly uninteresting. But, on the other hand, it helped us by providing a very rigid framework to fall back on while trying to solve other problems. It might not have gotten us all the way to the solution, and in my opinion could not get us to the correct solution, but it did at least give us enough to know irritating quirks about the system, and allowed us to know what we should consider as we tried to come up with more reasonable attempts at solving the problem.

Though this type of education helped in a minor way, I believe that it hurt more than it helped. We had a framework for where to start, which was definitely useful, but we also had a certain set of expectations: if we figured out what information we had, we could figure out what we have seen with this, and apply a previous concept directly. For this line of thinking, I find the very clear and relevant example of my high school physics teacher. My senior year of high school, he told me, “If I can’t plug my guitar into it, I don’t really care” in response to a general question about electricity and magnetism. My two years with him, in both classical mechanics and “Physics and Engineering” emphasized memorizing equations and a generic “plug and chug” approach to solving physics problems. We never really did any work with designing systems, or trying to look at more abstract ideas and build upon them. We were given numbers, an equation sheet, and that was really all. Here this class taught us to be novices: if it were a projectile problem, we knew which equations to use, looked to see what variables we were given, and then plugged these numbers into the equation. I often think in terms of this class: if I figure out what I have, I need to look for the correct equation, and then plug it in.

What came next was truly novice: we thought there were multiple pulleys needed for a solution, so we kept randomly looping the string around the pulleys in different directions and orientations.  We wrapped the string around one pulley completely, and then draped one end over a second pulley that was higher up. We switched this around and draped over the lower pulley and wrapped around the higher pulley. We put three pulleys in a vertical row, and weaved the string in a zig-zag. We mirrored this set-up by making the string zag-zig. After a couple tries of this, we decided that this was not going to work, and that we should consider a different approach. We sat staring at the pulleys and weights, and fiddled with the string. Someone went to get another wheel, a little one with a string tied tightly around it. We then attached this to the heavier of the two weights.

I started playing around with this wheel. I started winding it up and complained about how I wish we could apply an outside force like this, and how nice it would be if we could simply wind it up with a crank by hand. Suddenly it clicked for someone else. We simply needed to use torque, which was a basic property we all understood. We then created the following system:

The string was wound around the larger pulley, and when we released the lighter weight, the heavier weight rose as the string wrapped around the pulley. This worked because of balancing torques. Torque is equal to the radius times the force. In this case, we were able to compensate by the lighter weight by having a big radius, making the torque larger than that from the small pulley. And so we solved the problem, by taking the unknowns and turning the problem into something that we understood.

The point could be made that we weren’t entirely prepared for this problem despite all having learned about pulleys in our introductory physics class.  We all had seen problems like this during our freshman year, spent many hours tooling on problem sets, and went to lecture where we watched demos. Beyond just not being able to solve the problem, we were unable to recall the overall roadmap of the standard way to solve pulley problems: list tensions, balance forces, et cetera. One could argue that our education wasn’t good enough for us to remember these things which would spend so much time learning.

I would argue that our education at MIT has prepared us very well for this. An MIT education stresses the ability to make us into thinkers and problem solvers. We are given difficult things to solve, and have to apply principles we have learned to new and novel situations. Additionally, MIT has a lab requirement, meaning that we have experience working with physical systems. Because we are encouraged to learn both how to engineer and work with the real world, and develop problem solving skills, we overall came prepared with the tools we needed.

Another consequence of the MIT workload being so difficult is that students work together to solve problem sets, or learn how to ask for help when they don’t understand. Because of this emphasis on collaboration, MIT students learn to communicate in a way that high school students do not. We are in an environment that is high pressure with a constant stream of work. It’s almost a necessity to be able to efficiently debate ideas and give reasoning for why a particular solution is correct or incorrect.

I would argue that education systems should strive to promote critical thinking and understanding of general problems and techniques. While studying a given subject it is important to know specific details, but in the long run, students should be learning processes and techniques to apply to future (potentially unrelated) problems. I believe it is more important to know how to problem solve than to know specific equations, and that a quality education attempts to achieve this ideal.

Tagged with:
Posted in Personal Projects

A Little Climbing Script

Hello, all!

I’ve been missing out on climbing because I’m bad at remembering to check the MIT climbing wall site to see if it’s open. Instead, I decided to learn a little bit about Python’s web scraping, how cron works, and how to set up a scripts page through MIT. All code can be found here.

Python Scraping and Emailing

To actually figure out how to scrape the page to see if the wall is open, we first need to realize which packages we should be using. The answer to that is urllib2 and BeautifulSoup. urllib2 allows us to take a URL and get the HTML from it. We can then use beautiful soup to find contents in the HTML text.

First, we do simple import statements and assign initial variables for later use:


from urllib2 import urlopen
from bs4 import BeautifulSoup
wallPage = "http://scripts.mit.edu/~mitoc/wall/"
openWallPage = urlopen(wallPage).read()
html = BeautifulSoup(openWallPage, "html.parser")

I looked at the actual HTML for the page, and was able to identify the lines that determined the status and changed.

<span class='entry open'><span class='name '>open</span></span>
<span class='entry closed'><span class='name dim'>closed</span></span>

Are the ones which actually change. The current status is given by “class=’name ‘.” So what we really need to do is find out if the contents of <span class=’entry open’> and <span class=’name ‘> are the same. I did this by a simple string check, with some BeautifulSoup parsing thrown in.

openEntry = str(html.find_all(class_="entry open"))[1:-1]
currentStatus = str(html.find_all(class_="name "))[1:-1]
return currentStatus in openEntry

And now we have some a simple script which tells us if the wall is open! There’s probably some magical way to do this better with BeautifulSoup. The string method is a little messy. Note that we have to take off the first and last character in the string, because this method returns something of the form [string], and having the brackets around a string (while looking for a substring) would cause the conditional to always be false.

The next part of this is to send an email whenever this returns true. For this, we need to use the libraries stmplib, and email. The import statements are:

import smtplib
from email.MIMEMultipart import MIMEMultipart

From there, it’s just a little bit of following a pattern. Here you can see what all I did to make Python send an email.

fromAddress = "wall-is-open@mit.edu"
toAddress = "wall-is-open@mit.edu"
message = MIMEMultipart()
message['From'] = fromAddress
message['To'] = toAddress
message['Subject'] = "The wall is open! eom"
text = message.as_string()
server = smtplib.SMTP('outgoing.mit.edu',587)
server.starttls()
server.ehlo()
server.login("MIT_username", "password")
server.sendmail(fromAddress, toAddress, text)

The email address I want to send and receive mail to is wall-is-open@mit.edu, which I can easily make a mailing list (something awesome about being an MIT student). From there, it’s a game of adding the correct SMTP settings. Here I’m using outgoing.mit.edu, since I’ll be sending and receiving from an MIT server. This requires an MIT username and password, which I have omitted here.

Great. Now we have an email protocol and it can send an email if the wall is open, right? Nope. I thought this would work, but it turns out that getting an email every 5 minutes becomes annoying relatively quickly. Surprise there. What this code needs is a way to keep a state. All this means having a file which keeps track of the state by reading only “open” or “closed” depending on the previous state of the wall. This means we need to incorporate the reading and writing of the file.


with open("statusFile.txt", "r") as statusFile:
previousEntry = statusFile.readlines()[0]
if currentStatus in openEntry:
if previousStatus == "closed\n":
#block of the info to send emails, and then...
with open("statusFile.txt", "w") as statusFile:
statusFile.write("open\n")
else:
with open("statusFile.txt", "w") as statusFile:
statusFile.write("closed\n")

And there we go! A lot of the challenge of this came from two sources: 1, trying to do file permissions (since I was SSHing into an Athena computer, and running the code virtually), and 2, getting the correct file path (because this was done using Linux; if you’re also using Linux, you need the complete file path for statusFile.txt).

CRON Scripts

This turned out to be easier than I thought it would. MIT has a different way of using scripts to write cron commands, but it turned out to not be much of an issue. There was actually only one line to write (which I probably wrote inefficiently)


0,5,10,15,20,25,30,35,40,45,50,55 * * * * python ~/Programming/climbing_script.py

And there we go! Now the python script runs once every five minutes, and updates you if the wall is open (and it was previously closed). If you’re on MIT, add yourself to wall-is-on@mit.edu :D

Tagged with: ,
Posted in Personal Projects

Louvain Algorithm for Fuzzy Graphs

As alluded to in a previous post, I have been working on an implementation of the Louvain algorithm for fuzzy graphs. Here we will extend fuzzy set theory to apply to graphs, we will consider the logistical problem of using fuzzy graphs, and then we will implement the Louvain algorithm for these fuzzy graphs.

Fuzzy Graphs

When we have a fuzzy graph, there is ambiguity in the relationships between objects, or even the objects themselves. We represent this ambiguity in the form of a membership function, described last post. Before we define a fuzzy graph, we must understand that a fuzzy graph is itself a fuzzy version of an underlying crisp graph, meaning that all nodes and edges in the graph exist with membership 1. Formally, we write a crisp graph using the notation G^*(V,E), where E \subseteq V \times V.

From this graph, we can then define a corresponding fuzzy graph, formally written as G = (\sigma, \mu), where \sigma is a fuzzy (non-empty) subset of V, and \mu is a symmetric relation on \sigma. A property of note here is that each edge must have a membership value less than or equal to the minimum membership of the nodes it connects. More formally, \mu(u,v) \leq \min[\sigma(u), \sigma(v)].

These are the main properties that we will consider for now. Over the next few days, aside from considering how to write a fuzzy algorithm for the community-affiliation graph model (AGM), I will be considering paths through the graph: efficiently finding the strongest, most existent, shortest, etc., path of edges through the graph. When it comes time to write about that, I will list additional properties of interest in this graph.

Modifying the Algorithm

Fuzzy logic is more difficult to implement than the standard algorithm for weighted, crisp edges. First, a semantic change: instead of referring to the value of edges as “edge weights” we will call them “membership of the edges.” We must assert that the membership of each edge is between 0 and 1 (inclusive), and less than or equal to the minimum value of the nodes it connects. On the same note, we must assert all nodes have membership between 0 and 1 (inclusive).

We know from the previous post that there are many possible ways to define a community. This becomes even more true as we allow partial membership: a node to be 0.3 in one network and 0.4 in another. Because of the numerous possibilities, I chose a practical solution that uses approximations to the best of my ability. Here we use the same framework of the original algorithm, changing very little.

Step One: We begin by assigning each node in the graph entirely in its own community (ie., if a node as 0.4 membership in the graph, it starts in its own community with membership 0.4). For each node i, we calculate the change in modularity when we place some portion of i from its community into the communities of its neighbor nodes, j. Each community which i moves into is in the set C. We can then modify the formula for modularity as follows:

\Delta Q = \sum_{c \in C} \mu_c(i)\left(\left[\frac{\Sigma_{in} + k_{i,in}}{2m} - \left( \frac{\Sigma_{tot} + k_i}{2m}\right)^2\right] - \left[ \frac{\Sigma_{in}}{2m} - \left( \frac{\Sigma_{tot}}{2m}\right)^2 - \left( \frac{k_i}{2m}\right)^2 \right]\right)

For this, we have a new set of symbols that we must define. We define \mu_c as the membership of the node i in the community. This was chosen because the change in modularity should also depend proportionally on the membership of the community. (Note that if we have a crisp graph with only one community, the term drops out and we are left with the original equation) \Sigma_{in} is the sum of all the memberships of the edges in C. \Sigma_{tot} is the sum of the edge memberships of the nodes incident to (but not in) C. k_{i,in} is the sum of the edge weights from i to nodes in C. We do this by letting edge weights from i to the other members of C be equal to the minimum membership value of the two nodes. We calculate this for each of i‘s neighbor nodes and move i in the partition with the greatest modularity increase. If there is no increase, it remains in its community. Repeat this process for all nodes until there is no modularity increase.

Step Two: A new network is created. Here, the communities created from step one are aggregated into their own nodes. Finding the correct weighting of these communities and edges is difficult. The method to weight the membership and aggregation of communities, we should consider all nodes. If we simply sum these, we will have memberships greater than 1, very trivially. Instead, I propose averaging; no other obvious metric appears. In order to weight edges between communities (and self loops), first average all of the edges. If this value is less than the minimum of the two communities it is connected, use this value. Otherwise, if it is greater, use the value of the minimum of the two communities. There is likely a better metric for computing these, but I am unaware of them. Please feel free to send me suggestions or improvements. Since there is currently no literature on this particular subject, I welcome all feedback.

The glaring problems

This algorithm sounds really reasonable in theory, and it even seems like an intuitive way to define a community. But there are two huge problems here:

  1. Consider the case were three nodes that we put in three different communities. One could imagine a case in which each node is divided equally into each of the three communities. It quickly becomes meaningless.
  2. The definition is recursive, so weighting becomes a huge issue. Even using a simple toy example, the math blows up and becomes increasingly difficult as more communities exist, and has individual nodes are divided into multiple communities (since we now have to use more space to keep track of more nodes, need to loop through more nodes as they are divided)

Any insight on this would be awesome. Shoot me an email and maybe we can discuss my failings over coffee!*

 

 

 

 

*if you’re in the Boston/Cambridge area in the fall and I am not completely hosed.

Tagged with: ,
Posted in Computer Science, Mathematics Problems