Mainly Tech projects on Python and Electronic Design Automation.

Saturday, April 26, 2008

Bug in simple code after 2+ years and 133 comments

I was just reading this blog entry about a simple game of presenting a scrambled list of numbers and you having to reverse the leftmost N numbers until all numbers are in ascending order.

The game is implemented in various languages, including PHP Ruby and Python and most seem to be structured as:
  1. create a randomized list of numbers
  2. while the list is not sorted:
    1. ask for and input the number to be reversed
    2. reverse that portion of the list.
Ignoring any checks on input, it seemed odd that the programs did not check that the initial randomization did not produce a sorted list at step 1 that would cause the inner while loop to be skipped altogether!

Here is proof for Python:

>>> n = 10
>>> sortlist = range(n)
>>> randlist = range(n)
>>> random.shuffle(randlist)
>>> x = 0
>>> while randlist != sortlist:
... x += 1
... random.shuffle(randlist)
...
>>> print x
714418
>>>
If you were testing an implementation or otherwise running it, every once in a while it would just exit. Run it again and it would most likely work for a long time. It is not something I would like to use the normal xUnit type tests/continuous testing regime to uncover as although a transient fail would be noted, those test regimes rely heavily on easy reproducibility of the failure.

I guess what would be needed is knowledge of corner cases. For shuffle, corner cases to think of would include returning the input order, reverse input order, sorted, and reverse sorted order.





- Paddy.






P.S. Work pays me to be this finickity when testing ASICs

Friday, April 11, 2008

That history meme, in Python!


It seemsed that everyone was joining in the 'history meme', and finding out what was in their history:

They were all using unix command line tools, piped together to show the most frequent commands they had used.:
history|awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head

This being a Python blog, and knowing before-hand that Python is really awful at one-liners, I nevertheless decided that it would be of some use to try and pipe history to a Python one-liner that performed a similar task .

I came up with:
bash$ history | python  -c 'import sys,itertools,pprint; 
    pprint.pprint(sorted([
        (len(list(g)),k) for k,g in itertools.groupby(sorted([
            x.split()[1]for x in sys.stdin if len(x.split())>1])
            , lambda x:x)
        ])
        [-10:][::-1])' 
[(63, 'echo'),
 (41, 'history'),
 (30, './tst1.sh'),
 (28, 'declare'),
 (21, 'python'),
 (18, 'perl'),
 (18, 'cat'),
 (16, 'ls'),
 (15, 'xterm'),
 (15, 'history|python')]
bash$ 
I decided to break the command into multiple lines for readability above; it was developed, painfully, all on one line.

So readers, the above is something that Python stinks at - one-liners. (Unless you know a better way in Python ...)

- Paddy.

Tuesday, March 25, 2008

Writing a VCD to toggle-count generator in Python

I have an interesting problem at work which has been taxing me before
the Easter break. One of the less traditional ways forward is to write
a toggle count utility - something to take a simulation of a
hardware design and count which nets transition both to a zero and a
one in the simulation. For various reasons I could not get the design
to simulate in a modern version of a simulator with in-built toggle
counting without having to rebuild a C-based testbench for a later
version of an OS and a simulator that a major part of the TB is not
certified on.



I decided to spend my Easter Monday writing a VCD
to toggle-count
utility.



I started by searching my C: drive for a non-trivial vcd file and found
a ~200k/300 net sample generated from the Icarus Verilog program. I
then googled for the file format and found the IEEE 1394-2001 document
and went for that. I googled for ready-made utilities too and found an
interesting document on mining VCD files and parsing RTL to generate
all sorts of coverage metrics, but the VCD readers I found were in C
and, e.g. GTKWave
, and didn't seem to clarify how to write a vcd reader. (OK,
specifically - the liberal sprinkling of goto's in GTKWave sources put
me off, there - I've said it :-).



I moved on to read the IEEE spec, peruse my example vcd files, reject
writing an evcd (extended VCD), parser as I could
later extend a VCD parser, and I think the works simulator has enough
controls to tailor the VCD generated to be what I want.



The VCD files I will eventually have to work on may be a gigabyte in
size so I want to step through the file one token at a time gathering
stats as I go, and my reading of the VCD file format seemed to show
that that was possible, so the fist line of Python I wrote was this
line:



175   tokeniser = (word for line in f for word in line.split() if word)


The above generator
comprehension
, just gives successive words from the VCD file
without storing a huge chunk of the file in memory. tokeniser worked
originally with :

154 keyword2handler = {
155 # declaration_keyword ::=
156 "$comment": drop_declaration,
157 "$date": vcd_date,
158 "$enddefinitions": vcd_enddefinitions,
159 "$scope": vcd_scope,
160 "$timescale": vcd_timescale,
161 "$upscope": vcd_upscope,
162 "$var": vcd_var,
163 "$version": vcd_version,
164 # simulation_keyword ::=
165 "$dumpall": vcd_dumpall,
166 "$dumpoff": vcd_dumpoff,
167 "$dumpon": vcd_dumpon,
168 "$dumpvars": vcd_dumpvars,
169 "$end": vcd_end,
170 }

and the 'switch statement':

176   for count,token in enumerate(tokeniser):
181 keyword2handler[token](tokeniser, token)

... to form the guts of the program but when I had fleshed out all the
declaration keyword handlers beyond mere stubs, I decided to
add the second half of the parse routine as I realised that I would
skip all the simulation keywords and only needed to concentrate on the
first character of a token to determine what to do. This led to the
finished form of function vcd_toggle_count



I had thought that the rules for left-expanding a VCD value to a larger
word size might lead to a compact Python solution and i was pleased
with my result, which I tested in the Python interpreter as:

>>> for
number in "10 X10 ZX0 0X10".split():

...
extend = size-len(number)

...
print "%-4s -> %s" % (number,
('0' if number[0]=='1' else number[0])*extend + number)

...
10
-> 0010

X10
-> XX10

ZX0
-> ZZX0

0X10 -> 0X10


.This became:


 81       extend = stats.size - len(number)
82 if extend:
83 number = ('0' if number[0]=='1' else number[0])*extend + number




Well, enough prattling on about how I wrote the program, the full
source is below, and I'm off to work to to try it for real. It should
work, and since I have done no optimisations for speed as yet , I am
confident that I could get acceptable run-times out of its
variants to handle the gigabyte VCD file if I get one.



  1 #!python
2 '''
3 Extract toggle count from vcd file
4
5 Refer to IEEE standard 1364 2001
6 (http://inst.eecs.berkeley.edu/~cs150/ProtectedDocs/verilog-ieee.pdf)
7
8 Author Donald 'Paddy' McCarthy (C) 24 March 2008
9 '''
10
11 from __future__ import with_statement
12 from itertools import dropwhile, takewhile, izip
13 from collections import defaultdict
14 from pprint import pprint as pp
15
16 vcdfile = r"C:\cygwin\home\HP DV8025EA\tmp\ivtest_v1.0\test_div16.vcd"
17
18 class VCD(object):
19 def __init__(self):
20 self.scope = []
21 self.idcode2references = defaultdict(list)
22 self.reference2idcode = dict()
23 self.enddefinitions = False
24 self.id2stats = dict() # Maps id to its accumulated statistics
25 def textstats(self):
26 total, updown, uponly, downonly = 0,0,0,0
27 out = []
28 for ref in sorted(self.reference2idcode.keys()):
29 id = self.reference2idcode[ref]
30 stats = self.id2stats[id]
31 if stats.size == 1:
32 total +=1
33 if stats.zero2one and stats.one2zero:
34 updown +=1
35 covered = 'PASS'
36 elif stats.zero2one:
37 uponly +=1
38 covered = 'FAIL0'
39 elif stats.one2zero:
40 downonly +=1
41 covered = 'FAIL1'
42 else:
43 covered = 'FAIL10'
44 out.append( " %-50s %s" % ( '"'+".".join(x[1] for x in ref)+'":', (covered, stats.zero2one, stats.one2zero)) )
45 else:
46 total += stats.size
47 for count, (one2zero, zero2one) in enumerate(izip(stats.one2zero, stats.zero2one)):
48 if zero2one and one2zero:
49 updown +=1
50 covered = 'PASS'
51 elif zero2one:
52 uponly +=1
53 covered = 'FAIL0'
54 elif stats.one2zero:
55 downonly +=1
56 covered = 'FAIL1'
57 else:
58 covered = 'FAIL10'
59 name = ".".join( x[1] for x in (ref+(('BIT:','<'+str(count)+'>'),)) )
60 out.append( " %-50s %s" % ( '"'+name+'":', (covered, zero2one, one2zero)) )
61 header = "# TOGGLE REPORT: %g %%, %i / %i covered. %i up-only, %i down-only." % (
62 updown/1.0/total*100, updown, total, uponly, downonly )
63 body = "toggle={\n" + "\n".join(out) + '\n }'
64 return header, body
65
66 def scaler_value_change(self, value, id):
67 if value in '01' :
68 stats = self.id2stats[id]
69 if not stats.value:
70 stats.value = value
71 elif stats.value != value:
72 stats.value = value
73 if value == '0':
74 stats.one2zero +=1
75 else:
76 stats.zero2one +=1
77
78 def vector_value_change(self, format, number, id):
79 if format == 'b':
80 stats = self.id2stats[id]
81 extend = stats.size - len(number)
82 if extend:
83 number = ('0' if number[0]=='1' else number[0])*extend + number
84 newdigit, newone2zero, newzero2one = [],[],[]
85 for digit, olddigit, one2zero, zero2one in izip(number, stats.value, stats.one2zero, stats.zero2one):
86 if digit in '01' and olddigit and olddigit != digit:
87 if digit == '0':
88 one2zero +=1
89 else:
90 zero2one +=1
91 elif digit not in '01':
92 digit = olddigit
93 newdigit.append(digit)
94 newone2zero.append(one2zero)
95 newzero2one.append(zero2one)
96 stats.value, stats.one2zero, stats.zero2one = newdigit, newone2zero, newzero2one
97
98
99 class IdStats(object):
100 def __init__(self, size):
101 size = int(size)
102 self.size = size
103 if size ==1:
104 self.value = ''
105 self.zero2one = 0
106 self.one2zero = 0
107 else:
108 # stats for each bit
109 self.value = ['' for x in range(size)]
110 self.zero2one = [0 for x in range(size)]
111 self.one2zero = [0 for x in range(size)]
112 def __repr__(self):
113 return "<IdStats: " + repr((self.size, self.value, self.zero2one, self.one2zero)) + ">"
114
115
116 vcd = VCD()
117
118 def parse_error(tokeniser, keyword):
119 raise "Don't understand keyword: " + keyword
120
121 def drop_declaration(tokeniser, keyword):
122 dropwhile(lambda x: x != "$end", tokeniser).next()
123
124 def save_declaration(tokeniser, keyword):
125 vcd.__setattr__(keyword.lstrip('$'),
126 " ".join( takewhile(lambda x: x != "$end", tokeniser)) )
127 vcd_date = save_declaration
128 vcd_timescale = save_declaration
129 vcd_version = save_declaration
130
131 def vcd_enddefinitions(tokeniser, keyword):
132 vcd.enddefinitions = True
133 drop_declaration(tokeniser, keyword)
134 def vcd_scope(tokeniser, keyword):
135 vcd.scope.append( tuple(takewhile(lambda x: x != "$end", tokeniser)))
136 def vcd_upscope(tokeniser, keyword):
137 vcd.scope.pop()
138 tokeniser.next()
139 def vcd_var(tokeniser, keyword):
140 var_type, size, identifier_code, reference = tuple(takewhile(lambda x: x != "$end", tokeniser))
141 reference = vcd.scope + [('var', reference)]
142 vcd.idcode2references[identifier_code].append( (var_type, size, reference))
143 vcd.reference2idcode[tuple(reference)] = identifier_code
144 vcd.id2stats[identifier_code] = IdStats(size)
145 def vcd_dumpall(tokeniser, keyword): pass
146 def vcd_dumpoff(tokeniser, keyword): pass
147 def vcd_dumpon(tokeniser, keyword): pass
148 def vcd_dumpvars(tokeniser, keyword): pass
149 def vcd_end(tokeniser, keyword):
150 if not vcd.enddefinitions:
151 parse_error(tokeniser, keyword)
152
153
154 keyword2handler = {
155 # declaration_keyword ::=
156 "$comment": drop_declaration,
157 "$date": vcd_date,
158 "$enddefinitions": vcd_enddefinitions,
159 "$scope": vcd_scope,
160 "$timescale": vcd_timescale,
161 "$upscope": vcd_upscope,
162 "$var": vcd_var,
163 "$version": vcd_version,
164 # simulation_keyword ::=
165 "$dumpall": vcd_dumpall,
166 "$dumpoff": vcd_dumpoff,
167 "$dumpon": vcd_dumpon,
168 "$dumpvars": vcd_dumpvars,
169 "$end": vcd_end,
170 }
171 keyword2handler = defaultdict(parse_error, keyword2handler)
172
173 def vcd_toggle_count(vcdfile):
174 f = open(vcdfile)
175 tokeniser = (word for line in f for word in line.split() if word)
176 for count,token in enumerate(tokeniser):
177 if not vcd.enddefinitions:
178 # definition section
179 if token != '$var':
180 print token
181 keyword2handler[token](tokeniser, token)
182 else:
183 if count % 10000 == 0:
184 print count, "\r",
185 c, rest = token[0], token[1:]
186 if c == '$':
187 # skip $dump* tokens and $end tokens in sim section
188 continue
189 elif c == '#':
190 vcd.now = rest
191 elif c in '01xXzZ':
192 vcd.scaler_value_change(value=c, id=rest)
193 elif c in 'bBrR':
194 vcd.vector_value_change(format=c.lower(), number=rest, id=tokeniser.next())
195 else:
196 raise "Don't understand: %s After %i words" % (token, count)
197 print count
198 f.close()
199
200 vcd_toggle_count(vcdfile)
201 header, body = vcd.textstats()
202 print '\n'+header+'\n\n'+body+'\n'

STOP PRESS!
I'm back from work and the program worked with minor changes:
  1. I used the fileinput module to allow greater flexibility in specifying the input VCD file.
  2. Works, simulator had a slightly different interpretation of the spec around the definition of $var. (The spec needs to explicitely mark where spaces can/must occur).
  3. I missed adding commas to separate the output lines which should form a valid Python dict.
With an unchanged core algorithm the program churned through 200Mbytes of VCD file in 3 minutes. 2 gigs in 30 minutes is fine for me.

Sunday, March 23, 2008

Ain't Vista crap!

I went off to see the folks this weekend, one of which had a shiny new
Philips branded deskside PC that runs Vista. Being the member of the
family who is "in computers", I was asked to set up a few things for
them: (remove the login password; make frequently used tools easier to
find ...).

Now this was my first taste of Vista Premium and I was disappointed -
not with the display, that was a lovely 22 inch wide-screen LCD monitor
- It was the speed of the machine, or lack of it.



I should explain that I sit in front of a 1.8Gig Athlon based 17" HP
laptop at home, 1 Gig of ram, Windows XP, and Virgin broadband (cable,
4Megs). My machine is ~2 years old. The machine I was using with Vista
had 3 Gigs of Ram, and was a quad core Intel jobbie at 2.2Gigs. That is
three times the memory and four cores, each of which is faster than
mine. I expected Vista's response to be instant and it was not.

Some of the problems were to do with the broadband connection of the
Vista machine, which was Sky TV's broadband  deal (the one
that comes free with the TV subscription to try and combat Virgins
offerings),  there was a noticeable delay before pages started
to download; but a lot was to do with the machine itself:


  • Why did I have to wait for microsoft works wordprocessor to
    fire up?

  • Why did it take so long to boot-up from cold?

  • It just did not feel style="font-weight: bold; font-style: italic;">snappy!


I don't know if the recent Vista upgrade was installed, but this is a
very recent machine on very respectable hardware. Instead of being
green with envy I was shocked at how much of the hardware was wasted by
Vista (and to some extent Sky broadband).

(I should explain that the Vista machine is more than enough for what it will be used for and
my folks will be happy with it.)



This has got me worried. Multi-core is the solution for soaking up all
those extra trannies that Moore's law gives us over time, but Microsoft
Vista does not show the benefit.



Thinking about my next PC purchase, I have a family of two adults and
three children. If I were to buy a quad core laptop that I sat in front
of, I would want more than broadband traffic to go through my ethernet
cable. I would want it to be a transparent compute resource for several
thin-ish clients, maybe something like the Eee PC so the kids could
have a laptop they could use for school, but at home dock them to
 19" LCD screens and proper keyboards and Mice but more
importantly, they could use one of my quad cores transparently for
their compute intensive "Make a Video about Oxbow lakes" school assignments.
My normal TV's should have  just enough smarts to also act as
a (native), web browser and thin client, they could add the
functionality to my cable box. I want to be able to switch to BBC
Iplayer on the TV as well as any of the normal Cable TV offerings; or
select the news from www.bbc.co.uk/news, without buying a separate media-centre PC - I have four speedy cores just sitting in another room waiting to be shared!



Hopefully My future quad core machine would be better used if it was
packaged as a compute resource for the rest of my household items to
tap.



- Paddy.

Saturday, February 23, 2008

Length Sorts

Andre Roberge just informed me of a site with ninety nine Prolog problems. A quick scan and I got as far as P28 before thinking that I would like to try it. so here is my solution to P28. Note that there is much more comments than code, I decided to cut-n-paste my command line scribblings as an explanation of the second function, rather like doctests.



In doing this, I also learned that you could not take the len of a groupby object :-)



The code:


(Note: I would like to make this available under the Python License version 2.4.2)



''' \
Length sorts. From https://prof.ti.bfh.ch/hew1/informatik3/prolog/p-99/ P28

A code kata

Answer in Python (C) Donald 'Paddy' McCarthy, Feb. 23, 2008
'''

from itertools import groupby


def length_sort(lst):
''' \
Sort a list-of-lists on sub-list length

Example

>>> l = [['a','b','c'],['d','e'],['f','g','h'],['d','e'],['i','j','k','l'],['m','n'],['o']]
>>> length_sort(l)
[['o'], ['d', 'e'], ['d', 'e'], ['m', 'n'], ['a', 'b', 'c'], ['f', 'g', 'h'], ['i', 'j', 'k', 'l']]

'''
return sorted(lst, key=len)

def length_freq_sort(lst):
''' \
Sort a list-of-lists on frequency of sub-lists length

Example

>>> l = [['a','b','c'],['d','e'],['f','g','h'],['d','e'],['i','j','k','l'],['m','n'],['o']]
>>> length_freq_sort(l)
[['i', 'j', 'k', 'l'], ['o'], ['a', 'b', 'c'], ['f', 'g', 'h'], ['d', 'e'], ['d', 'e'], ['m', 'n']]

'''
## Comments give example working out

# >>> lst = [['a','b','c'],['d','e'],['f','g','h'],['d','e'],['i','j','k','l'],['m','n'],['o']]
lengths = sorted(len(x) for x in lst)
# >>> lengths
# [1, 2, 2, 2, 3, 3, 4]
# >>> [(a,len(list(b))) for a,b in groupby(lengths)]
# [(1, 1), (2, 3), (3, 2), (4, 1)]
# >>> dict([(a,len(list(b))) for a,b in groupby(lengths)])
# {1: 1, 2: 3, 3: 2, 4: 1}
len2freq = dict([(a,len(list(b))) for a,b in groupby(lengths)])

return sorted(lst, key=lambda x: len2freq[len(x)])



Wednesday, February 06, 2008

Python tuples and lists

Just my attempt at explaining lists w.r.t. tuples, after href="http://news.e-scribe.com/397">this post.

With a tuple, the value and type of items at each index of a
tuple may have significance, but successive items in a tuple rarely
have similar meanings.

With lists, successive items usually have similar meanings.



(Big analogy time): cars on a motorway might be modelled as a list of
car objects, but a car might be modelled as a tuple as the constituents
of a car might be treated differently:

  style="font-family: monospace;"> style="font-weight: bold; color: rgb(255, 0, 0);">(engine,
seats, wheels, colour, valid_tax, speed,  lights_on ,... style="font-weight: bold; color: rgb(255, 0, 0);">)



 wheras each car on a motorway might be treated in a similar
way:

style="font-family: monospace;">pull_over( car for cars in style="font-weight: bold; color: rgb(255, 0, 0);">[car1,
car2, ...] if not car[valid_tax_index style="font-weight: bold; color: rgb(255, 0, 0);">])




- Paddy.

Tuesday, December 18, 2007

Batch Process Runner in bash shell

Picked up an interesting problem from a colleague:
How to run n batch processes but only m at a time?

It seems that resource constraints allow every four batch processes to share one license - so long as all four batch processes are started from the same terminal on the same machine. Users may have tens of processes to run and currently they are run individually on our compute farm.



I tend to code whilst having a cold for some reason? And needed to use more advanced bash scripting - I decided against Python for the task as I would like my colleague to take over further developments of the code and I can't rely on him knowing Python, (and I don't want to code in Perl today).



I came up with this little demonstrator which runs processes that go to sleep for a random amount of time. The script runs as many as you specify but only a maximum number of proc's at a time.



The script is followed by sample output and was tested on cygwin using bash version 3.2.9(11)-release (i686-pc-cygwin):




1 #!/bin/bash
2
3 ##
4 ## process_runner.sh <concurrent> <total procs>
5 ##
6 ## Example script given the maximum number of processes to
7 ## run concurrently, c, and the total number of processes, n
8 ## runs at most c, processes in the background until all n
9 ## Have been run.
10 ##
11 ## Author Donald 'Paddy' McCarthy Dec. 17 2007
12 ##
13
14 # how many processes to run in parallel
15 concurrent=$1
16 # total processes to run
17 maxprocs=$2
18
19 printf "\n## STARTING %i Processes, %i at a time\n\n" \
20 $maxprocs $concurrent
21
22
23 # main loop wait time between checking background procs.
24 tick=1
25
26
27 # dummy processes sleep for a random time
28 function runproc {
29 local -i n=$1
30 local -i j
31 (( j = 5+$RANDOM*10/32767 ))
32 #(date; printf "#>>>JOB %i : Sleeping for %i\n" $n $j)
33 printf "OUT JOB ,%03i, Sleep for ,%2i, , @,%s\n" $n $j "`date`"
34 sleep $j
35 returned=$?
36 printf "IN JOB ,%03i, Slept for ,%2i, returned ,%i, @,%s\n" \
37 $n $j $returned "`date`"
38 #(date; printf "#<<<JOB %i : Slept for %i\n" $n $j)
39 }
40
41 function print_runstats {
42 printf '# %i Jobs in background. %i/%i started\n\n' \
43 `jobs -r|wc -l` $ran $maxprocs
44 }
45
46 # Bash array running keeps track of the background process numbers
47 # Start with nothing running (sentinel value will not be a process number
48 for ((i=0; i<$concurrent; i+=1 )); do running[$i]=123456789; done
49
50 ran=0
51 until
52 while [ $ran -lt $maxprocs ]; do
53 for ((p=0; p<$concurrent; p+=1 )); do
54 proc=${running[$p]}
55 # Over all running processes...
56 # $proc still running?
57 ps -p $proc | fgrep $proc >/dev/null
58 if [ $? -ne '0' ] ; then
59 # Not found i.e. finished
60 # Run another in background and store the proc number
61 runproc $ran &
62 running[$p]=$!
63 ((ran+=1))
64 if [ $ran -ge $maxprocs ]; then break 1; fi
65 fi
66 done
67 sleep $tick
68 # Status
69 print_runstats
70 done
71
72 sleep $tick
73 # Status
74 print_runstats
75 do [ `jobs -r|wc -l` -eq 0 ]
76 done
77 wait
78 printf "\n## FINISHED\n"
79
80 exit 0
81
82 sample_output=<<!
83 bash$ ./process_runner.sh 2 5
84
85 ## STARTING 5 Processes, 2 at a time
86
87 OUT JOB ,000, Sleep for ,10, , @,Tue Dec 18 09:26:00 GMTST 2007
88 OUT JOB ,001, Sleep for , 8, , @,Tue Dec 18 09:26:00 GMTST 2007
89 # 2 Jobs in background. 2/5 started
90
91 # 2 Jobs in background. 2/5 started
92
93 # 2 Jobs in background. 2/5 started
94
95 # 2 Jobs in background. 2/5 started
96
97 # 2 Jobs in background. 2/5 started
98
99 # 2 Jobs in background. 2/5 started
100
101 IN JOB ,001, Slept for , 8, returned ,0, @,Tue Dec 18 09:26:09 GMTST 2007
102 # 1 Jobs in background. 2/5 started
103
104 OUT JOB ,002, Sleep for ,11, , @,Tue Dec 18 09:26:09 GMTST 2007
105 IN JOB ,000, Slept for ,10, returned ,0, @,Tue Dec 18 09:26:10 GMTST 2007
106 # 2 Jobs in background. 3/5 started
107
108 OUT JOB ,003, Sleep for , 7, , @,Tue Dec 18 09:26:11 GMTST 2007
109 # 2 Jobs in background. 4/5 started
110
111 # 2 Jobs in background. 4/5 started
112
113 # 2 Jobs in background. 4/5 started
114
115 # 2 Jobs in background. 4/5 started
116
117 # 2 Jobs in background. 4/5 started
118
119 IN JOB ,003, Slept for , 7, returned ,0, @,Tue Dec 18 09:26:18 GMTST 2007
120 # 1 Jobs in background. 4/5 started
121
122 OUT JOB ,004, Sleep for , 6, , @,Tue Dec 18 09:26:19 GMTST 2007
123 # 2 Jobs in background. 5/5 started
124
125 IN JOB ,002, Slept for ,11, returned ,0, @,Tue Dec 18 09:26:20 GMTST 2007
126 # 1 Jobs in background. 5/5 started
127
128 IN JOB ,004, Slept for , 6, returned ,0, @,Tue Dec 18 09:26:25 GMTST 2007
129
130 ## FINISHED
131 !
132
133
134
135
136

Thursday, December 13, 2007

Terry Pratchett

I feel sad that someone who has given me so much pleasure over such an extended time, has medical problems. I wish him well.

Sunday, November 25, 2007

Python: Concise

I have spent several years both reading and contributing to comp.lang.python. Yet another thread on proposed language changes together with replies pointing out that Python tries to be both short and clear set me off on a tangent trying to find that one adjective that captured that property of Python.



After some online research using Chambers, (do they use Python on their website? The link includes /chref.py/); AskOxford; and Thesaurus.com, I introduced myself to the alt.usage.english newsgroup and asked them to help me improve on my then best candidate word - succinct.



After some useful dialogue I received a private email through the newsgroup from Orlando Enrique suggesting concise. Acting quite mechanically I went and did a search on AskOxford for concise and got many more hits than I expected, and then it dawned on me, the publishers of the Oxford dictionary use the word concise in the title of their abridged works to convey just what I wanted for Python: it is short, comprehensive, and clear. Any shorter would affect clarity. Any longer would not be necessary.



So in summary: Try Python, it's concise.

Saturday, October 13, 2007

What's in a name?

I wrote a tool for work that would order VHDL files for compilation. VHDL is one of those languages in which, (annoyingly), everything that file a.vhd depends on must be compiled before a.vhd. After scanning all the source files I extract a dependency list which I stored as a dictionary mapping source file names to the source files they depended on.

I then needed to sort the files so that no file was compiled before any file it depended on.



Now I did google for such a pre-written routine using phrases that included dependency, dependancy :-), depends etc; sort and maybe Python. I got nothing! Eventually I wrote my own which worked very well and I was proud of it.



A couple of months later, whilst reading a newsgroup reply on something or other, someone mentioned a topological sort and so I went and looked that up. If only I knew the term 'topological' I could have found a ready-made solution such as this (which has a good explanation too).



So, "What's in a name"?

Quite a lot actually.



:-) Paddy.



P.S. There is also the tsort Unix utility.

Followers

Subscribe Now: google

Add to Google Reader or Homepage

Go deh too!

whos.amung.us

Blog Archive