Enigmatic Code

Programming Enigma Puzzles

Notes

Here are some notes that I hope will prove useful for contributors to the site:

 

Including code in WordPress

The best solution seems to be to use [code language="python"]...[/code] tags in your comment (with the language adjusted accordingly). See this support page for details.

Prior to finding out about this I suggested you could just use <code>...</code> tags, but I used to use HTML <pre>...</pre> tags and filter the code with the following Python 3 program (which I call pre-cat) to escape HTML entities (although this makes it difficult to easily switch to using [code] tags, as the HTML entities get escaped twice):

# process a text file suitable for inclusion in HTML tags

import fileinput
import html

for line in fileinput.input():
  print(html.escape(line, quote=False), end='')

 

Including maths in WordPress

If you know the LaTex document markup language the good news is you can include LaTex directly in WordPress, by using the $latex ...$ construct.

So for example by entering:

$latex d = \frac{ 25 }{ sin(\theta) } - \frac{ 24 }{ tan(\theta) }&s=2$

I get the following expression:

d = \frac{ 25 }{ sin(\theta) } - \frac{ 24 }{ tan(\theta) }

(as used in the solution to Enigma 1728).

 

Python 2 or Python 3?

I try to write code that is portable between Python 2 and Python 3 (at the time of writing I am using Python 2.7.11 and Python 3.5.1). I use the new-style print function and string formatting, which means if you’re executing the code under Python 2 you’ll need to:

from __future__ import print_function

(although now I just tend to use the printf() function from the enigma.py library, which works in both Python 2 and Python 3 and makes interpolating variables much easier than the standard print statement/function).

Python 3.3 introduced the yield from ... construct, which makes writing recursive generators neater. I occasionally use this, and where I do the program will only run in Python 3.3 or later.

If you want to run code that uses yield from ... under Python 2 try replacing:

yield from EXPRESSION

with:

for x in EXPRESSION: yield x

 

Python style

I tend to use 2-space indents for whatever language I’m using, so naturally I also do this for Python, which will no doubt annoy some of the Python purists, but it does let code fit better in WordPress comments, and it looks better to me than 4-space indents.

If it worries you unduly run it through:

unexpand -t 2 | expand -t 4

 

Timing Python programs

I use my shell’s (Z-shell) built-in time function, and report the total time (in this case 0.125s or 125ms):

% time python enigma1609.py
5468 [4, 4, 5, 4, 4, 4, 5] 5
python enigma1609.py 0.11s user 0.01s system 97% cpu 0.125 total

The time reported includes all phases of execution from Python start-up, compilation and execution, but you can also use the cProfile module to get an idea of the number of function calls involved (although this will vary between different Python versions) and the internal execution time of the code:

% python -mcProfile -scumulative enigma1609.py
5468 [4, 4, 5, 4, 4, 4, 5] 5
         120855 function calls (120695 primitive calls) in 0.114 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.095    0.095    0.114    0.114 enigma1609.py:4()
   103218    0.008    0.000    0.008    0.000 {len}
     2800    0.004    0.000    0.006    0.000 {filter}
    11088    0.002    0.000    0.002    0.000 enigma1609.py:26()
       93    0.000    0.000    0.002    0.000 enigma.py:57(factor)
   253/93    0.001    0.000    0.002    0.000 enigma.py:65(_factor)
       78    0.000    0.000    0.002    0.000 enigma.py:53(prime)
      192    0.001    0.000    0.001    0.000 {range}
        1    0.001    0.001    0.001    0.001 __future__.py:48()
     2645    0.001    0.000    0.001    0.000 {divmod}
        1    0.000    0.000    0.000    0.000 enigma.py:19()
      280    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
      191    0.000    0.000    0.000    0.000 {math.sqrt}
        1    0.000    0.000    0.000    0.000 {print}
        2    0.000    0.000    0.000    0.000 {map}
        7    0.000    0.000    0.000    0.000 __future__.py:75(__init__)
        2    0.000    0.000    0.000    0.000 {method 'count' of 'list' objects}
        1    0.000    0.000    0.000    0.000 __future__.py:74(_Feature)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

For more flexible timing options in Python you can use the Timer class in my enigma.py library.

 

Rating Enigma puzzles

I have enabled ratings for the puzzles on the site, so you can express an opinion as to what you think of a puzzle.

The ratings go from 1 to 5 stars. I rate puzzles according to how much fun it is to program a solution. So a rating of 1 means the puzzle is trivial to program a solution for (e.g. Enigma 1494). A rating of 3 is an averagely challenging Enigma puzzle. And a rating of 5 is a fun programming challenge.

The list of Challenging Enigmas are all puzzles I have awarded 4 and 5 stars to.

 

Advertisements

9 responses to “Notes

  1. Brian Gladman 1 July 2013 at 8:53 am

    In view of the recent problems with the measurement of the running times of Python code on different machines, it might be useful to have a timing capability in enigma.py. Here is one possible version that provides for overall timing and subroutine timing using a decorator.

    from __future__ import print_function
    from functools import wraps
    
    try:
      from time import perf_counter as _timer
    except ImportError:
      from time import time as _timer
    
    class Timer(object) :
      def __enter__(self): self.start = _timer()
      def __exit__(self, *args):
        t = _timer() - self.start
        if t < 1.0:
          print(' ({:0.3f} ms)'.format(1000 * t))
        else:
          print(' ({:0.3f} seconds)'.format(t))
    
    def timing(f):
      @wraps(f)
      def _timing(*arg):
        t = _timer()
        r = f(*arg)
        t = _timer() - t
        print('{:s} took {:0.3f} ms'.format(f.__name__, 1000.0 * t))
        return r
      return _timing
    
    • Brian Gladman 1 July 2013 at 9:25 am

      Here is an example of use:

      from timer import Timer, timing
      from enigma import Primes
      
      @timing
      def get_primes(n):
        return Primes(n).list()
      
      with Timer():
        get_primes(10000000)
      
      • Jim Randell 16 August 2013 at 2:00 pm

        I’ve folded some of these ideas into a timing module I wrote a while back. If you want to try it out you can download it at this link [ http://www.magwag.plus.com/jim/timing.py ]. There’s some documentation in the file. I haven’t tested it in a MS Windows environment, so it would be good to know if it works there. (I’ve put code in to use time.clock on Windows, as timeit does).

        Of course it will report very different timings to the run times I usually report as this is measuring an internal elapsed time to the Python interpreter, rather than an all inclusive elapsed time of the whole thing. For instance, my solution to Enigma 1762 is reported as taking 776µs, rather than 38ms. (Both of which still count as “instantaneous”).

        I’ve not included it directly into enigma.py at the moment because I like the fact you can just add import timing to your code and get a pretty good measure of the internal runtime, but I don’t think I want that to happen if you import enigma.py. (I could only enable the default time only if you have some environment variable set, but that seems a bit messy).

        • Jim Randell 16 August 2013 at 4:44 pm

          Actually I think I’ve persuaded myself that I could put most of this into enigma.py, and have a special Timer object you can import. Then you would be able to wrap the code you wanted to time with calls to timer.start() and timer.stop(). Then at least it would be explicit what you are timing. And the rest of it would still be available for people who want to use the more esoteric functionality.

          Update: This is now included in the latest version (2013-08-16) of enigma.py.

    • Jim Randell 7 August 2013 at 11:22 am

      For measuring the timing of snippets of code Python has its own module called timeit, which says it “avoids a number of common traps for measuring execution times”, so I’m happy to use it rather than roll my own code (which may well stumble into several of these common traps).

      You could use it like this:

      % python -mtimeit -s'from enigma import Primes' 'sum(Primes(10000000))'
      

      For overall program execution time I do multiple runs of the program and report the shortest elapsed time (as reported by my shell’s time builtin). I did consider having a “Raspberry Pi” metric to allow people to estimate comparable runtimes with minimal outlay, but really the times I report are only “tourist information” to give a rough idea of how much work the program is doing, as accurate timings depend on all aspects of the system the code is executing on.

      But generally I tend to consider my programs to fall into roughly the following categories:

      Instantaneous: ≤ 100ms
      Fast: ≤ 1s
      OK: ≤ 10s
      Slow: ≤ 100s
      Better than nothing: > 100s

      And usually try to aim for a “Fast” solution (although I will prefer readability and correctness of a program over execution speed).

      The advantage of using the shell’s timing the program is that it gives me a way of comparing the execution time of programs that use different programming environments. When I started coding Enigma puzzles I would do them in Perl, and I’m able to use the same technique to estimate the run time of those programs (and if I were comparing compiled code I would think it would be only fair to include the compilation time into the overall runtime). Although I am aware it may be trickier to get such timings under MS Windows based systems.

      • Brian Gladman 7 August 2013 at 5:07 pm

        I agree that timing can be difficult and can also depend on what the objective of the timing really is. But I have noticed a number of people who are adding timing code to their Python programs in various ways, some of which are highly suspect and others that are just plain wrong. So I am still of the view that it would make sense to offer a common way of doing timing for those who want to add timing capabilities into their code.

        • Ahmet Saracoğlu 7 August 2013 at 6:13 pm

          Hi to all,

          What about the cpu’s speed? That does matter, so I suggest that Jim should measure each one’ code on his machine, that is more true

          • Brian Gladman 7 August 2013 at 10:33 pm

            Yes that matters but people can simply announce the speed of their machines if this matters. Its not perfect but a common approach would avoid the big errors we have seen recently in timing. Jim can speak for himself but I am doubtful that he would be willing to take on the task you suggest given the limited benefits and the added costs involved.

            • Jim Randell 14 August 2013 at 10:22 am

              Actually I don’t mind reporting comparative timings for code posted on the site (if I can get it to run). Just ask when you post the code and I’ll do a comparative timing run on it.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: