Tuesday, August 14, 2012

Problem 1 - Integer Multiples of 3 and 5


Problem 1

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. 
Find the sum of all the multiples of 3 or 5 below 1000.

This is a real softball just to get people hooked.  The code could easily be a single line, but I have separated things out a bit.  I'll take the time to discuss the various boilerplate in my code in this blog post because the problem itself doesn't require much discussion.

I have also run my first benchmarks on several different interpreters.  I experiment with the -O switch which runs some sort of optimizations before running the script.  Interpreters tried include, Python 2 & 3, Pypy, and Jython.  The only modifications needed to run in Python 3 were the use of the new Python 3 "print ()" syntax which also worked in all Python 2 flavors.

There is an Ubuntu Launchpad project where I will host all my solution code.  You can get your very own copy on a linux box with bzr installed using this command:

bzr branch lp:eulerplay

Or you can browse online at:
http://bazaar.launchpad.net/~brywilharris/eulerplay/trunk/files.

Solution

Here's the code for Problem 1:
#!/usr/bin/env python

#This program adds all the integer numbers divisible by 3 and 5
#below a selected maximum number.  It is a straight forward, 
#brute-force approach.

if __name__ == '__main__' :   #boilerplate

    import sys  #for command line input
    sum = 0;
    for i in range(0,int(sys.argv[1])): #int arg required
        if (i%3==0) or (i%5==0):  #divisible by 3 or 5?
            sum = sum + i #add to the sum
    print sum #spit it out at the end
This is run using the following command (with the correct number argument for the question asked):

python add35.py 1000

The correct answer is 233168.

Approach

This is a simple, brute-force solution.  I loop through the entire range and add up the numbers divisible by 3 and 5.  The modulo (%) operator lets me see which numbers are evenly divisible.

This program uses the simplest form of command line argument (using sys.argv), the boilerplate (__name__ == __main__ ) for use as a library on Windows and a simple for loop (for i in range(x,y)).  These are some of the only things a python programmer needs to learn to start writing code.  I'm  often pleasantly surprised when I don't know how to do something in Python and it just does what I mean on the first try.  Try that in Java some time.

The first line lets you invoke the script from the command line without specifying the interpreter. Instead of python add35.py 1000, you can just type ./add35.py 1000.  This line is not required when the interpreter is run manually, eg pypy add35.py 1000.
#!/usr/bin/env python
The sys library lets you access command line arguments in python. There are much fancier and more bullet proof ways of doing this, but none are quite this simple.
import sys
astring = sys.argv[1] #argv[0] is the script name
This is how python handles for loops:
for i in range(x,y):

Benchmarks

The following are some simple benchmarks using the unix "time" command.  Python can be run on a variety of interpreters without modification.   My 4-core Intel i7 processor positively spoils me for other machines  (Hopefully it's not bragging to say, "Your benchmarks may be slower").   Python 2.7.3 comes with my copy of Ubuntu 12.04.  I also tried Pypy version 2.7.2, Python 3.2.3 and Jython 2.5.1 running on Java 1.6.0_24.

Code runs in a single thread for all benchmarks in this example.  The "real"number is the wall clock time the program took to set up and run.  This includes loading the interpreter into memory, any optimizations, and the reporting of results.  Later programs may be multi-threaded, but this one didn't need that.

This simple example can be timed with the following command:

time python add35.py 1000
or
time python -O add35.py 1000

In this case, the -O (optimze) switch takes longer than running unoptimized:
bryan@myComputer:~/play$ time python add35.py 1000
233168

real 0m0.025s
user 0m0.024s
sys 0m0.000s
bryan@myComputer:~/play$ time python -O add35.py 1000
233168

real 0m0.071s
user 0m0.060s
sys 0m0.004s

Adding a few zeros makes the -O switch (just barely) worthwhile:
bryan@myComputer:~/play$ time python add35.py 100000000
2333333316666668

real 0m19.323s
user 0m18.457s
sys 0m0.772s
bryan@myComputer:~/play$ time python -O add35.py 100000000
2333333316666668

real 0m19.286s
user 0m18.417s
sys 0m0.792s

Python 3 took longer and required a modification to the print statement syntax.  print sum had to become print(sum).  It looks to me like Python 3 has a way to go before it starts getting optimized.
bryan@bryan-Aspire-V3-771:~/play$ time python3 -O add35.py 100000000

2333333316666668

real 0m22.498s
user 0m22.465s
sys 0m0.004s

On a lark I tried this in pypy.   Pypy is a python interpreter written in a version of python instead of c.  It seems like an interpreter written in an interpreted language would be the definition of clunky, but this isn't the case for pypy.  Pypy runs a lot faster in this simple case:
bryan@myComputer:~/play$ pypy -O add35.py 100000000
2333333316666668

real 0m2.833s
user 0m2.804s
sys 0m0.028s


Jython crashed with an out of memory error after 37 seconds for the number 100000000.  Jython fits my preconceived idea of an interpreter inside an interpreter much better than Pypy. I guess my jython benchmarks will be a bit limited.  Jython was able to solve the original problem, also shown below.
java.lang.OutOfMemoryError: java.lang.OutOfMemoryError: Java heap space

real 0m37.852s
user 1m48.999s
sys 0m1.732s

bryan@myComputer:~/play$ time jython add35.py 1000

233168



real 0m1.580s

user 0m3.444s
sys 0m0.136s



Conclusion

This is a straight-forward problem with a straight forward solution.  While a faster algorithm might be found (multiplying by threes and fives until you get to the target number might be faster) but it was not necessary.  The solution to the initial question above is 233168.  

Pypy is the fastest interpreter for this problem by a factor of almost 7x. Python 3 was  slower than Python 2 and Jython was very slow even for this simple problem.  Jython ran out of memory and crashed when working with the bigger number.

Monday, August 13, 2012

Euler Challenge Introduction


Illustration of the Euler Graph Concept from Wikipedia
This is the first in my series of posts on the programming site projecteuler.net. This site currently has a list of 391 interesting programming challenges and mathematical puzzles. The idea is to write a computer program to solve each problem in under an hour. Some of the puzzles can undoubtedly be solved in under an hour including both programming and run time. In my experience thus far, some of the problems will require creative solutions to solve in less than a day.

I plan to first solve all these problems in Python where possible because this is my favorite non-graphical programming language. I then plan to port some of my code to other languages for benchmarking purposes and just to brush up. One of the problems I have already solved needed to be ported to C just to solve in under a week... I don't expect this to be a series of general interest, but if you like python, math puzzles, or just geeky stuff in general, maybe this will be for you.

I plan to post on one problem a day, and I have a few week head start on solving the problems. I will post all my code along with benchmarks for those who are interested. All the code I write is licensed under the GPL. Here is a link if you don't know what that is. It means you can have, copy, keep, share, modify, sell, whatever, as long as you redistribute the code along with the programs and pass these rights on. Go forth and have fun with it.

I hope you enjoy my blog post series on the Euler challenges. 

Wednesday, December 15, 2010

Firesheep Presentation at Linux SIG

I'll be giving a presentation on Firesheep and cookies:

7pm Thur., December 16, 2010 at Wright State University, Russ Engineering, RC146



Here are my presentation slides:
https://docs.google.com/present/view?id=dtv8cxf_20x2xhpvg2

Saturday, November 6, 2010

Firesheep on Linux! Update 1

As of the current git release you too can get firesheep goodness on linux:

>git clone git://github.com/mickflemm/firesheep.git
>cd firesheep
>git submodule update --init
>./autogen.sh --with-xulrunner-sdk=/usr/lib/xulrunner-devel-1.9.2.13

Now you have to pretend you know what you're doing...  add dependencies it complains about, and hack a makefile

For dependencies, look for what it complains about using apt-cache:
>apt-cache search '[missing dependency name]'
>sudo apt-get install '[package from list]'

On my netbook I needed the following, but you may need more:
sudo apt-get install libhal-dev
 


Once all the dependencies are happy type:
>make

The installer gets built in: 
./firesheep/build/


Just fire up firefox and browse to it.  Double click.

Alternately, type:
> firefox build/firesheep.xpi

At this point, if you go into preferences, there's nothing in the interface list.  There's one last step:
> cd ~/.mozilla/firefox/*.default/extensions/firesheep@codebutler.com/platform/*gcc3
> sudo ./firesheep-backend --fix-permissions

On my eeepc, the interface needs to be in monitor mode to capture cookies:
>ifconfig wlan0 down
>iwconfig wlan0 mode monitor
>ifconfig wlan0 up

This allows firesheep to capture cookies, but you can't connect to the internet.  You need a second connection, or else you can just switch back once a cookie gets captured:
>ifconfig wlan0 down
>iwconfig wlan0 mode managed
>ifconfig wlan0 up

It's not quite as automatic as on the other platforms, but it works!  I tried it by logging into my facebook on my Mac in Safari.  Up popped my facebook entry, but the icon was broken because my interface  was in monitor mode.  I switched to managed mode and then clicked on the entry in the firesheep tab and viola! I'm logged in without a password!

I next added a second wireless interface and put my wireless in monitor mode.  Then everything works pionty clicky, including icons.  I click on my smiling mug and up pops my facebook page, logged in as me.

But it needs two wireless cards to work seamlessly...  :-(  Not ideal.  It works though.  Coool stuff.

PS.  Here's a link to the plugin, in case you're lazy.  (It works for me on Ubuntu 10.04 on an EEEPC 701)
http://www.mediafire.com/?6n0v23oc8cccbkr

Wednesday, December 30, 2009

U3 Howto #1

So here's how you do it: 

First, I run linux.  These commands are all available under Windows, but I don't care.  If you are looking for a Windows how-to, go here first: WUBI

Now once you have a nice sane Ubuntu install here's how you do it:

Supplies:
1 U3 crapware thumb drive (preferably with nothing important on it)
1 bootable iso (Anything will do, but if you want to point and click, HERE YOU GO.)
1 copy of u3-tool  (It builds just fine on Ubuntu 9.10.  Follow the directions.  I'll probably throw it in my PPA for people who are lazy.)

Syntax:
>> A command you can copy and paste
[something you need to fill in for yourself]

Howto:
Insert your thumb drive.

Keep things clean:
>>mkdir customu3
>>cd customu3
Figure out what drive letter it was:
>> sudo fdisk -l
 ...
    Device Boot      Start         End      Blocks   Id  System
/dev/md0p1               1   122095984   488383934   83  Linux

Disk /dev/sdd: 7605 MB, 7605321216 bytes
255 heads, 63 sectors/track, 924 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdd1               1         976     7839698    b  W95 FAT32
If you just plugged it in, chances are it's the last thing in the list.  Also, quickly verify that the size is about right.  My drive is an 8GB drive do 7605MB is about right.  If you have trouble remembering /dev/sdd1, write it down, but beware that it may change in subsequent steps.

If you want the small iso I recommended above (for a first try) you can run this:
>> wget -c http://distro.ibiblio.org/pub/linux/distributions/tinycorelinux/2.x/release/tinycore_2.7.iso
or
>>cp [../myiso.iso] .
Next, find out how big the iso is:

>> ls -l *.iso
-rw-r--r-- 1 myuser myuser 10614784 2009-12-30 22:09 tinycore_2.7.iso
The tinycore 2.7 iso is 10614784 bytes.  I typically add 1000 bytes just to be on the safe side.


Next, make room for the custom iso image:

>>sudo [path to]/u3-tool -p  10615784 /dev/[sdd1]
Ubuntu will remount things for you.  Make sure the drive location didn't change.  Notice that my thumb drive changed size slightly.  Yours should have too or else something didn't work.
>>sudo fdisk -l
...
Disk /dev/sdd: 8055 MB, 8055029248 bytes

255 heads, 63 sectors/track, 979 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdd1               1         976     7839698    b  W95 FAT32
Now write the new image and you're done.
>> sudo [path to]/u3-tool -l tinycore_2.7.iso /dev/[sdd1]
That's it.  You should have a new virtual cdrom:
>> ls -l /dev/scd*
lrwxrwxrwx 1 root root 3 2009-12-27 15:04 /dev/scd0 -> sr0
lrwxrwxrwx 1 root root 3 2009-12-30 22:16 /dev/scd1 -> sr1
I like to then check that it worked right using a virtual machine.  It's faster than rebooting.  If this works, you have a bootable, virtual CDROM running from your thumb drive.  Congratulations!
>>kvm -cdrom /dev/scd1

Thursday, December 24, 2009

I used to hate U3...

U3 is that annoying software that comes pre-installed on your Sandisk thumb drives.  It mounts a virtual CD on your PC when you plug it in and auto-runs a piece of crappy software when all you want is to drag and drop files onto your thumb drive.  I hate that.

But wait - I USED to hate U3. U3 was a closed, windows-only, back-door, auto-run, BS that Sandisk forced me to borrow a Microsoft PC to rip out of my thumb-drive...

I was so wrong. 

I discovered I could hack it. And that CD partition on the U3 drive... looks like a real CD to the computer... and it's bootable! The CD acts like a separate device on an USB hub!

I now have a bootable, 8GB Sandisk Cruzer thumbdrive with all the useful boot CD's I use - all selectable from a little menu. I haven't perfected it yet, but I have half a dozen of them already on there. I want to work on it some more and then post it so all zero of you can easily do this too. :-p

For now, here are some links to the bits and pieces I used (both are cross platform Windows-Linux-Mac-whatever that has mkisofs):
u3-tool - Allows customization of the u3 partition.
UBCD - Has a bunch of boot images pre-installed and easy directions for customizing.


So far, I left all the stuff that came on the UBCD with a few tweaks:
  • I upgraded to the latest memtest86+, and DBAN.
  • I added SpinRite. (The only piece of software I've bought in a decade.)
  • I added the following Live CD's:
  1. TinyCore v2.7 - 10MB, runs almost everything useful, boots into ram 5-10 seconds. Enough said.
  2. Puppy Linux v4.3.1 - A little bigger, also runs in RAM, less customization needed.
  3. Slax 6.3.1 - Most polished Live CD I ever used. Only 200 MB base image. Online customization. Check it out.
  4. BackTrack 4 - 1.3GB of evil hacker tools
    "computer security tools". Mwahahaha.

Really this was mostly a no-brainer with just the two links above. I had to do some hacking editing of the isolinux configs (which requires a bit more than monkey skills) to get things just right, but it was really pretty easy.

The coolest thing is that the live CD's are read only and behave just like a giant CD. The thumb-drive still shows up as a thumb-drive too. It acts like a separate device to the PC. (An U3 thumb-drive acts like a hub with two devices plugged into it.) This has some really cool implications.

Now I say... U3 ROCKS!

Tuesday, May 12, 2009

Didier Stevens Tools

I have created a little branch for Didier Stevens programs. He makes some really useful little gadgets like XORSearch. XORSearch parses a file for plain strings, but also trivially scrambled strings such as ROT13 et al. It's neat.

Anyway, you can get the code like this:

bzr branch lp:ds-tools

I have added a makefile that builds all the tools I could get to work on Linux and copies them into the base directory. From there ./ --help should be enough to get you going. Have fun.