In 2012, I researched computational materials science/physics for Dr. Dimitrios Papaconstantopoulos. The following is my semester report. All source code is listed at the end of the report.
Category: Python
Semi-Autonomous Robotics: (2012) My 1st Software Project
I’m experimenting with committing past projects to github.
Over the summer (2012) at George Washington University Robotics Lab – Positronics Divison (with Roxana Leonetie as my mentor and Gregory Colella as my research partner), we wrote a package for the PR2 using ROS stacks and Python. In short, the PR2 completes a task moving a dowel into a hole (using only force proprioception) as a response to dynamic stimuli.
If you are unfamiliar with the PR2:
Greg was relatively new to Python (an experienced Java coder), and I learned to code the same summer that we completed the project (previously, I had dabbled in mainly math and physics). Bear this in mind while viewing our project.
This is an early demo I simulated in gazebo of the PR2 learning to replicate arm movements (a major part of the project).
Terminal Hexagonal Lattice
Here: have a script to generate plaintext hexagonal lattices for you when you’re feeling blue.
import itertools
pattern1 = ". ."
pattern0 = " "
def main(repeat,length):
for _ in itertools.repeat(None, length):
print (pattern1+pattern0)*repeat
print (pattern0+pattern1)*repeat
if __name__ == "__main__":
main(10,10)
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
SPOILERS: Using Simple Combinatorics
DISCLAIMER: This is the solution to Project Euler’s problem 15. Please attempt to solve the problem yourself before reading my solution.
Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.
How many such routes are there through a 20×20 grid?
I like to use this problem to demonstrate the efficacy of using simple maths to improve code.
Instead of the naive solution….
from itertools import permutations
def unique(iterable):
seen = set()
for x in iterable:
if x in seen:
continue
seen.add(x)
yield x
options = [1]*20 + [0]*20
counter = 0
for a in unique(permutations(options)):
counter = counter+1
print counter
Use simple combinatorics!
To find the number of unique routes through a 20×20 grid, use our friend: the concept of permutations with repeated elements:
\(\frac{\text{number of elements}!}{\text{repetitions of character}!*\text{repetitions of other character}!*…}\)
import math
print math.factorial(40)/(math.factorial(20)*math.factorial(20))
Even better – one line in Haskell:
product [1..40] `div` product[1..20]^2
HackMIT: Polyglass
I attended HackMIT 2013 and had an absolute blast! Kartik Talwar, Spencer Hewett and I make a fantastic team.
Photo by Kevin Yiming Chen © Copyright 2013 Kevin Yiming Chen |
In the turmoil that followed the hackathon (taking a weekend off of schoolwork and research has consequences), it slipped my mind to post our project!
We created Polyglass. A Google Glass application that analyzes the video in slow motion using the Eulerian magnification algorithm to calculate the human pulse from a video frame in quasi-real-time. Using video alone, we achieve the same functionality as a polygraph.
The picture below is a demo of our project; it compares the original video frame to the frame processed by Eulerian Magnification. This processing is an implementation of the Eulerian Magnification framework published by MIT.
Portions of our source are on Kartik’s github.
Braille Cell with VPython
The internet went down at my house, and I decided to play with vpython again!
#type individual brl cell using numkeys
from visual import sphere
R = 0.2 #filled dot radius
r = 0.1 #empty dot radius
#corresponds to numkeys
dotdict = {
'7': [1,3], #dot 1
'4': [1,2], #dot 2
'1': [1,1], #dot 3
'8': [2,3], #dot 4
'5': [2,2], #dot 5
'2': [2,1] #dot 6
}
fulldot = dotdict.keys()
def draw(dots):
[sphere(pos=dotdict[dot], radius=r) for dot in fulldot] #create empty dot matrix to represent empty cell
[sphere(pos=dotdict[dot], radius=R) for dot in dots] #fill appropriate dots
print "Please enter stringn7t8n4t5n1t2n: "
string = raw_input()
if string.isdigit(): draw(str(string))
Let’s see it in action! The letter “j” (or “just” in G2):
Simple Cubic Lattice
Today, let’s have some fun playing with perspective rendering in Python! My graphics package of choice is VPython:
sudo apt-get install python-visual
Suppose we want to represent a simple cubic lattice: Using the visual
package, we can create a collection of spheres at positions \((i,j,k)\) with \(i,j,k = -L…L\).
from visual import sphere
L = 5
R = 0.3
for i in range(-L,L+1):
for j in range(-L,L+1):
for k in range(-L,L+1):
sphere(pos=[i,j,k],radius=R)
Resulting in this beautiful rendering:
But what if we want to change the color? Simply alter the last line:
sphere(pos=[i,j,k],radius=R).color = color.blue
Less atoms? Alter the value of L.
L = 1 |
Same number of atoms with smaller radii? Alter the value of R.
R = 0.2 |
English to Morse Translator
Today, I wanted to code an efficient letter to Morse code translator in Python and whipped this up. I’ve found that a familiarity with many of Python’s lesser-known built-in functions is quite useful in situations such as this!
Just for fun, I encourage the reader to use this script to leave their comments in Morse.
#!usr/bin/python
#Catherine Ray
"""
morse.py {string} [{string} ... ]:
Translates string of english letters and spaces to morse code.
"""
import string
import sys
if len(sys.argv)>=2:
if sys.argv[1].isalpha():
text = ''.join(sys.argv[1:]).lower()
morse = ["01","1000","1010","100","0", "0010", "110", "0000", "00", "0111", "101", "0100", "11", "10", "111", "0110", "1101", "010", "000", "1", "001", "0001", "011", "1001", "1011", "1100"] letter = map(chr, range(97, 123))
LETTER_TO_MORSE = dict(zip(letter, morse))
morse_out = [LETTER_TO_MORSE[x] for x in text] print ' '.join(morse_out).replace("1","-").replace("0",".")
else:
"Restrict yourself to the english alphabet."
else:
print "Enter a string to translate, friend!"
Consequent Challenge
Today, as I was writing a post on sorting in vim, I issued myself a challenge.
The challenge: without using a bash script, write a one liner that reads through all the lines in a file, sorts them and printed these sorted lines to stdout. Do so in under a minute without using the internet.
Before you continue, I encourage you to try it yourself. Get out a timer … Ready? Go!
In about 35 seconds, I had this:
print 'n'.join(sorted([line.strip() for line in open("file.txt")]))
Although this one-liner works, the filename is hardcorded. Quick fix (finished at 52 seconds):
import sys; print 'n'.join(sorted([line.strip() for line in open(sys.argv[1])]))
I find that self-issuing pseudorandom timed challenges is a fun way to train yourself to work under pressure. ‘Tis one of the many ways to gamify everyday life!
Sidenote: Do not fall into the trap of using one-liners in actual code. The Pythonic way to do this is:
import sys
try:
with open(sys.argv[1]) as f:
for line in f:
print 'n'.join(sorted(line.strip()))
except IOError:
print "File does not exist."
Popular Weekdays
The code on my blog will range in quality from “I’m waiting in line and have 10 minutes to code” to “I’ve been working on this all day.”
Let’s with begin some quick, semi-hardcoded scripts, shall we?
# dayofweek.py
import datetime
from sys import argv
from calendar import day_abbr #import day_name for full name
"""
Counts the amount of hits per weekday, given a file of data corresponding to "year month day amount-of hits"
"""
#starts with a zero counter array (each index corresponds to a weekday, 0:Sunday, 1:Monday, ...)
weekcount = [0]*7 #hits per day
argv = argv[1:] #get rid of script declaration in args
#make sure string has year, month, day, amount-of-hits-that-day
if len(argv) % 4 == 0:
for c in range(0, len(argv),4):
#increment slice so we are only looking at one set of (year, month, day, amount-of-hits-that-day) at one time
if (a.isdigit() for a in argv[0+c:4+c]):
year, month, day, count = int(argv[0+c]), int(argv[1+c]), int(argv[2+c]), int(argv[3+c]);
#get index of day that the given date corresponds to
daynum = int(datetime.date(year, month, day).strftime("%w"))
#add the amount-of-hits-that-day to the counter
weekcount[daynum] = weekcount[daynum] + count;
#display days from most to least popular
print 'n'.join([day_abbr[(sorted(range(7), key=lambda k: weekcount[k]))[d]] for d in range(7)])
Okay, we need some random data to test this bad boy on. Naively, we could create a random data set of valid days as follows:
# randomday.py
import random as r
f=[]for x in xrange(12):
year = r.choice(range(1997, 2013))
month = r.choice(range(1, 12))
day = r.choice(range(1, 28))
hits = r.choice(range(6666,9999))
f.extend((year, month, day, hits))
print ' '.join(map(str,f))
An example of this output is:
2008 9 15 7311 2007 7 1 9812 2011 6 9 7721 2003 7 21 6736 2010 9 13 7776 1997 9 14 8776 1999 7 14 8617 2012 9 4 8208 2006 11 26 9689 2004 11 10 8952 1997 7 19 7799 2007 9 15 7858
We can feed these test values into our original script with a quick bash one-liner:
python dayofweek.py `python randomday.py`
We will receive the most and least popular weekdays in this random set of data:
Wed
Fri
Sat
Mon
Tue
Sun
Thu