> # This program simulates the random branching and extinction of
linages.
> # It also mutates a series of characters representing morphology at
> each branch point
> # The program replicates the program first described by D.M. Raup
and
> S.G. Gould
> # 1974 Systematic Zoology 23: 305-322.
> # written by Vincent Wan with help from tutor@python.org

Put the above set of comments in triple quotes and it will
become a *docstring* and hence accessible via Pythons help()
function...

> import random
>
> debug = 0    # turns debug diagnostic printing on = 1 or off = 0
>
> #constants that control the simulation
> max_linages = 201    # the number of linage to be evolved + 1
> branching_probablity = .1
> extinction_probablity = .1
> mutation_rate = .5

Constants should be in UPPER_CASE by convention.

> # initalize
> living_linages = [[0, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]] # the
> ancestor
> dead_linages = []
> tree = "*0*"
> time = 0
> next_linage = 0
>
> def Mutate_morphology(a_morphology, rate):

the fashion for function naming is to separewt words
with capitals so this would be mutateMorphology(...)
Names starting upper case are conventionally classes.
So a Python reader may think the function call is a
class instatiation as it is.

>      "Each morphological character has a rate chance it is increased
or
> decreased by 1"
>      a_morphology = a_morphology[:]
>      character = 0
>      while character < len(a_morphology):
>          if random.random() <= rate:
>              if random.random() < .5:

.5 would be clearer as 0.5, the point on its own is easily missed.

>                   a_morphology[character] =
a_morphology[character] - 1
>              else:a_morphology[character] = a_morphology[character]
+ 1

You could use += and -+ here to save a wee bit of space.

>          character += 1
>      return a_morphology
>
> def Braching(debug, next_linage, time, living_linages,
mutation_rate,
> tree):
>      "With branching_probablity creates a new linage, mutates its
> morphology, and updates tree."
>      counter = 0
>      while counter < len(living_linages):
>          if random.random() < branching_probablity:
>              # creates new linage
>              next_linage += 1
>              new_linage = [next_linage, time, 0,
> Mutate_morphology(living_linages[counter][3], mutation_rate)]

better to line this up with the other parameters:
               new_linage = [next_linage, time, 0,

Mutate_morphology(living_linages[counter][3],
                                              mutation_rate)]

it keeps the block structure clear.

>              living_linages.append(new_linage)
>              # updates linage tree
>              target = '*' + str(living_linages[counter][0]) + '*'
>              replacement = '(' + target + ',*' + str(new_linage[0])
+
> '*)'

You could use string formatting to do both lines in one:

replacement = "(*%s*,*%s*)" %  (living_linages[counter][0],
new_linage[0])

it will be faster too.

>              tree = tree.replace(target, replacement)

Ah, but here you use both bits.... Ok, but you could still use
formatting to create the two strings.

>          counter += 1
>          if debug: print 'at time ', time, ' living_linages: ',
> [linage[0] for linage in living_linages]
>      return (next_linage, living_linages, tree)
>
> def Extinction(debug, extinction_probablity, living_linages, time,
> dead_linages):
>      "With extinction_probablity kills living species and adds them
to
> the dead list"
>      counter = 0
>      while counter < len(living_linages):
>          if random.random() < extinction_probablity:
>              newly_dead = living_linages[counter]
>              newly_dead[2] = time
>              dead_linages.append(newly_dead)
>              living_linages.remove(living_linages[counter])
>              if len(living_linages) == 0: break    # when the last
> living_linages goes extinct exit
>          counter += 1

there may be a subtle bug here. IF you remnove an entry above
then all the elements shuffle up one. If you now increment
counter you will in effect step over one entry without
checking it. Is that what you want?


>      if debug: print 'at time ', time, ' dead_linages : ',
[linage[0]
> for linage in dead_linages]
>      return (living_linages, dead_linages)
>
> def Print_results(next_linage, max_linages, living_linages,
> dead_linages, tree):
>      "prints number of linages, the data about the linages living
and
> dead, and the tree"
>      if next_linage < max_linages:
>          print '\nall extinct with only ', next_linage + 1, ' linage
of
> ', max_linages
>      else:
>          print '\n', max_linages - 1, ' linages evolved'
>      print '\nliving linages:'
>      for each in living_linages:
>          print 'linage', each[0], 'born', each[1], 'morphology:',
each[3]
>      print '\nextinct linages: '
>      for each in dead_linages:
>          print 'linage', each[0], 'born', each[1], '- died', each[2]
>          print 'morphology:', each[3]
>      tree = tree.replace('*','')
>      print '\ntree (in New Hampshire form: )', tree
>
> # main loop
> while next_linage < max_linages:
>      # handles branching
>      (next_linage, living_linages, tree) = Braching(debug,
next_linage,
> time, living_linages, mutation_rate, tree)
>      # handles extinction
>      (living_linages, dead_linages) = Extinction(debug,
> extinction_probablity, living_linages, time, dead_linages)
>      if len(living_linages) == 0: break    # when the last
> living_linages goes extinct exit
>      time += 1
>
> Print_results(next_linage, max_linages, living_linages,
dead_linages,
> tree)

might be nicer to put the main code in a main function and then
use the magic incantation

if __name__ == '__main__': main()

to execute it. It allows for easier extension of your code
by using your file as a module, and also allows you to
experiment with it from the Python prompt by importing it
without the main code executing.

These are nearly all style comments and as such are subjective
and open do debate, but I hope they are helpful.

Looks like another good candidate for Useless Python...

Alan G.

_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to