PyPedal 2 CHANGELOG
===================

"---" indicates a known bug;
"+++" indicates a feature addition;
"***" indicates an API change or a major bugfix;
"'''" indicates a minor bugfix or feature enhancement.
"???" indicates a possible problem (i.e. bug) that has
      not been verified.

PLANNED CHANGES in PyPedal 2.0.0a8
==================================
*** 07/21/2004  Major overhaul of pyp_utils/preprocess() pedigree format code handling.

CHANGES in PyPedal 2.0.0a7
==========================
''' 08/12/2004  Changed pyp_metrics/fast_a_coefficients() to catch exceptions
            when no relationship matrix is provided and the pedigree is too large for
            fast_a_matrix() to compute one.  In these cases, a value of -999.9 is
            returned.
''' 08/12/2004  Changed pyp_metrics/a_effective_ancestors_indefinite() to catch exceptions
            when no relationship matrix is provided and the pedigree is too large for
            fast_a_matrix() to compute one.  In these cases, a value of -999.9 is
            returned.
''' 08/12/2004  Changed pyp_metrics/a_effective_ancestors_definite() to catch exceptions
            when no relationship matrix is provided and the pedigree is too large for
            fast_a_matrix() to compute one.  In these cases, a value of -999.9 is
            returned.
''' 08/12/2004  Changed pyp_metrics/a_effective_founders_boichard() to catch exceptions
            when no relationship matrix is provided and the pedigree is too large for
            fast_a_matrix() to compute one.  In these cases, a value of -999.9 is
            returned.
''' 08/12/2004  Changed pyp_metrics/a_effective_founders_lacy() to catch exceptions
	    when no relationship matrix is provided and the pedigree is too large for
	    fast_a_matrix() to compute one.  In these cases, a value of -999.9 is
	    returned.
''' 08/12/2004  Made changes to pyp_metrics/a_coefficients() to catch exceptions in
	    fast_a_matrix() or fast_a_matrix_r() when they cannot allocate a matrix.
	    When an exception is caught all successive computations are performed on
	    a 1x1 matrix whose value is -999.9.  This is kind of hacky, but will prevent
	    many problems.
''' 08/12/2004  Added summary statistics (mean/min/max) to the pyp_nrm/inbreeding() routine.
*** 08/12/2004  Changed pyp_classes/Pedigree.nus() to use dictionaries instead of lists;
	    Changed pyp_classes/Pedigree.nud() to use dictionaries instead of lists;
	    Changed pyp_classes/Pedigree.nug() to use dictionaries instead of lists;
	    Changed pyp_classes/Pedigree.nuy() to use dictionaries instead of lists;
	    Changed pyp_classes/Pedigree.nuf() to use dictionaries instead of lists.
            There are, as always, huge gains in large pedigrees fro doing this.  Why?
	    Because, silly rabbit, you avoid looping over increaseing large arrays for
	    every animal in the pedigree.  It is not a big win on a small pedigree, but
	    on, e.g., an 800,000 animal pedigree it makes a very significant difference.
*** 08/02/2004  Changed pyp_utils/renumber() so that it checks sire and dam birthyears
	    before renumbering.  If the child has an earlier birthdate than a parent,
	    that parent is set to unknown, '0'.  This is a temporary fix pending a
	    rewrite of the actual pedigree component of PyPedal.  I am thinking that a
	    dictionary of animal objects might be a better way to handle things than a
	    simple list.  If everything was in a dictionary, for example, then it would
	    be simple to check the sire and dam birthyears using a key->value lookup.  As
	    is, there is no reliable way to check those sorts of things unless the pedigree
	    has been reordered and renumbered.
''' 07/31/2004  Added a new pedigree format code, asdbx, to pyp_utils/preprocess().
''' 07/31/2004  Changed pyp_classes/Animal() so that the default birthyear is 1900.
''' 07/31/2004  Added debug statements to several routines in pyp_utils.
*** 07/29/2004  Added pyp_utils/new_preprocess() which is the major rewrite of the pedigree
            format code handling that I have been promising for a while.
''' 07/21/2004  Added a species attribute to the Animal() class which defaults to 'u'.
+++ 07/21/2004  Added pyp_utils/reverse_string() to reverse a string.  Useful when you have a
            string on which you cannot readily use string.split().
+++ 07/21/2004  Added pyp_demog/age_distribution() for computing the distribution of ages in
            a population.
+++ 07/21/2004  Added pyp_utils/simple_histogram_dictionary() for creating a simple test-based
            histogram from a dictionary of integral counts.
''' 07/21/2004  Changed Animal/__init__() so that birthyears default to -999 when they are
            not specified in the pedigree file.  This was done to support age computations
            in the demographics module.
''' 07/21/2004  Added age and alive attributes to the Animal() class which default to -999.
+++ 07/21/2004  Added a new file, pyp_demog.py, which contains some routines for
            demographic computations, such as age distributions.  There are going
            to be some potentially hairy issues with date handling.  Maybe.  If I
            don't get lazy and just say that everything is on a year basis.
''' 07/21/2004  Added a stub file, pyp_peel.py, for forthcoming support for pedigree
            peeling.
''' 07/20/2004  Added some notes to pyp_utils/preprocess() detailing an idea for
            greatly improving the way in which pedigree format strings are handled.
            No code has been written yet, but the idea is on the table.
*** 07/20/2004  I *think* that pyp_metrics/pedigree_completeness() works correctly now.
''' 07/20/2004  Added a breedcode attribute to the Animal() class which defaults to 'u'.
''' 07/20/2004  Fixed recurse_pedigree_n() so that it recurses to the correct depth.
+++ 07/20/2004  Added recurse_pedigree_onesided() to pyp_nrm.  It recurses to return the
            complete sire or dam side of an animal's pedigree.
*** 06/11/2004  Added stringme() methods to the Animal() and Pedigree() classes  to support
            integration with the GUI.  The output returned is identical to the printme() methods.
+++ 06/11/2004  Started working on a GUI for PyPedal, pyp_gui.  It requires that you have
            the wxPython toolkit installed.  How to do that is up to you.
*** 05/26/2004  Added pyp_nrm/recurse_pedigree_n(), which returns a pedigree of a
            specified depth.
''' 05/26/2004  Fixed pyp_classes/Animal() so that animal names are actually assigned
            correctly in __init__().
*** 05/26/2004  Added pyp_utils/set_generation() to infer the generation to which
            each individual in the pedigree belongs.  This was added to make
            pyp_metrics/pedigree_completeness() easier to code as the igen is
            really just a count of the depth of an individual's pedigree.
''' 05/26/2004  Added an igen (inferred generation) attribute to the Animal() class
            which defaults to -999.  A non-negative value will be assigned to
            this attribute by pyp_utils/set_generation().
''' 05/26/2004  Added a pedcomp attribute to the Animal() class which defaults to
            -999.9.  A non-negative value will be assigned to this attribute by
            pyp_metrics/pedigree_completeness().
--- 05/26/2004  There is a bug in pyp_utils/renumber() such that the offspring stored
            in myped[i].sons, myped[i].daus, and myped[i].unks are not updated to
            reflect changes in animal IDs when a pedigree is renumbered.
--- 05/26/2004  There is still a bug in pyp_utils/preprocess() where the sex of an
            animal is assigned based on a "best guess".
*** 05/26/2004  Added pyp_utils/load_pedigree(), which is a wrapper around several
            pedigree processing routines.  It is a convenient way to roll several
            common operations (load, reorder, renumber, etc.) into a single call.
''' 05/26/2004  Updated pyp_utils/renumber() so that the renumberedID attribute is
            set as each animal is renumbered.
''' 05/26/2004  Added originalID and renumberedID properties to the Animal() class
            with the eventual goal of eliminating ID maps from the renumbering
            code.  originalID defaults to animalID and renumberedID defaults to
            -999.
''' 05/26/2004  Made small changes to Animal.printme() method to add new attributes.
''' 05/26/2004  Changed pyp_metrics/effective_founder_genomes() so that the quiet flag
            suppresses all outout to stdio.

CHANGES in PyPedal 2.0.0a6
==========================
*** 05/25/2004  Added pyp_metrics/effective_founder_genomes() for running gene-drop
            simulations on a pedigree to determine the effective number of
            founder genomes as defined in Lacy (1989) and Boichard et al. (1997).
*** 05/25/2004  Added pyp_metrics/assign_founder_alleles() to be used for setting-up
            gene-drop simulations on pedigrees for which no founder alleles are
            provided in the input file.
*** 05/25/2004  Added a new pedigree format code, 'asdt', to pyp_classes/preprocess()
            to support simple pedigrees with genotype data (two alleles only).
''' 05/25/2004  Added an alleles attribute to pyp_classes/Animal() to support
            gene dropping.
*** 05/25/2004  Added pyp_utils/sort_dict_by_keys() to return a dictionary where the keys
            are sorted in ascending order (from "Python Cookbook", P. 39).

CHANGES in PyPedal 2.0.0a5
==========================
*** 05/06/2004  Added pyp_nrm/fast_a_coefficients() for testing some loop
            optimization.
*** 05/06/2004  Moved some code in pyp_utils/preprocess() outside of a loop in
            which it did not belong for a HUGE win in performance!
''' 05/06/2004  Made changes to pyp_utils/preprocess() to support the changed
            attribute types in pyp_classses/Animal/__init__().
''' 05/06/2004  Changed self.sons, self.daus. and self.unk from lists to
            dictionaries.
''' 05/03/2004  Tweaked pyp_classes/Pedigree/nus() and pyp_classes/Pedigree/nud()
            so that the counts computed do NOT include unknown sires or dams.
''' 04/27/2004  Added some "try...except" code to pyp_utils/preprocess() so that
            non-renumbered pedigrees do not cause the sex assignment code to
            halt the program.
''' 04/27/2004  Added a "method" parameter to pyp_metrics/a_coefficients() so that
            the user can specify which type of relationship they would like --
            the NRM using pyp_nrm/fast_a_matrix() or the complete (inbreeding-
            adjusted) RM using pyp_nrm/fast_a_matrix_r().  Method takes the values
            'frm' (full relationship matrix) or 'nrm' (numerator relationship
            matrix).
+++ 04/27/2004  Added pyp_nrm/fast_a_matrix_r(), which corrects the relationships
            in A for the inbreeding of the parents.  The A matrix returned by
            fast_a_matrix_r is, therefore, NOT a numerator relationship matrix.
            It is a matrix of coefficients of relationship.

CHANGES in PyPedal 2.0.0a4
==========================
''' 04/23/2004  Possibly corrected a subtle bug in the Animal.pad_id_new method that
            resulted in incorrect sorting in some cases.
+++ 04/23/2004  Added pyp_metrics/mating_coi(), which computes the coefficient of
            inbreeding of offspring that would result from a matinge  between
            two animals.
+++ 04/23/2004  Added pyp_metrics/relationship(), which computes the coefficient of
            relationship between two animals.
''' 04/23/2004  Added three new attributes to Animal() objects: self.sons, self.daus,
            and self.unks, which are lists to store renumbered animalIDs of sons
            and daughters of an animal, as well as the IDs of offspring with un-
            known sex.
''' 04/20/2004  Added a 'name' attribute to the Animal() object to accomodate,
            e.g., dog breeders.
+++ 04/20/2004  Added a new procedure, pyp_utils/draw_pedigree(), to draw
            pedigrees using the pydot interface to Graphviz.  If the necessary
            modules are not installed the procedure will return a result of '0'
            rather than exploding.  :-)
''' 04/20/2004  Beginnings of a tutorial in the PyPedal manual.
''' 04/19/2004  Corrected a minor bug in pyp_nrm/inbreeding_tabular() that
            resulted in negative CoI being written to returned dictionary.
''' 04/19/2004  Enhanced pyp_nrm/inbreeding() to update Animal() instances with
            the CoI computed by that routine.
''' 04/19/2004  Enhanced pyp_utils/preprocess() to assign sex codes to Animal()
            instances based on the inferred sex iff no sex code was specified
            in the pedigree file.

CHANGES in PyPedal 2.0.0a3
==========================
+++ 04/19/2004  Added a new routine, pyp_metrics/a_effective_ancestors, that will
            call either a_effective_ancestors_definite() or
            a_effective_ancestors_indefinite() depending on the size of the
            pedigree passed in.  Currently, they cutoff is 1,000.
+++ 04/19/2004  Added a new routine, pyp_metrics/a_effective_ancestors_indefinite()
            routine, that attempts to estimate upper and lower bounds for f_a
            in large pedigrees rather than computing all contributions
            explicitly.  a_effective_ancestors_indefinite() is NOT WELL TESTED.
            There are almost certainly bugs; the routine does not iterate.  All
            I can really tell you for sure is that it sometimes returns values
            that are extreme underestimates of f_a.  It is supposed to work
            reasonably well on large pedigrees rather than small ones.
*** 04/19/2004  FINALLY fixed all known bugs in the tragically-written
            pyp_metrics/a_effective_ancestors_definite() routine!
+++ 04/16/2004  Added pyp_utils/set_ancestor_flag() to be used to
            set ancestor flags.
+++ 04/16/2004  Added an ancestor flag to pyp_classes/Animal/__init__().
*** 04/15/2004  Fixed bugs in pyp_metrics/a_effective_founders_lacy()
            and pyp_metrics/a_effective_founders_boichard() that
            were introduced by changes in pyp_utils/preprocess().
*** 04/15/2004  Changed pyp_utils/preprocess() so that pedigree entries
            are not made for unknown parents by the "add parent
            records to the pedigree if they are not already there"
            routine.
+++ 04/15/2004  Added pyp_metrics/common_ancestors() which
            returns a list of all of the ancestors that
            two animals share in common.
+++ 04/15/2004  Added pyp_metrics/related_animals() which
            recurses through a pedigree to build a
            list of all animals related to a given
            animal, if any.

CHANGES in PyPedal 2.0.0a2
==========================
***/+++ 04/??/2004  Refactored and added new code to pyp_nrm to
            support a VanRaden's iterative method for
            computing CoI in large pedigrees:
                inbreeding()
                inbreeding_vanraden()
                recurse_pedigree()
                inbreeding_tabular()

CHANGES in PyPedal 2.0.0a1
==========================
--- 03/31/2004  pyp_utils/fast_a_matrix blows up when passed a
            pedigree of size 80,000 or so;
+++     03/31/2004      pyp_utils/pedigree_range was added -- allows the
            easy creation of a pedigree containing animals
            1 through <n> from a large pedigree.  This will
            be used to determine how large a pedigree PyPedal
            can currently handle;
+++ 03/31/2004  pyp_utils/preprocess rewritten to use dictionary
            lookups instead of list lookups -- improved the
            performance of this routine by about 2 orders of
            magnitude;
+++     03/31/2004      pyp_utils/preprocess now accepts a delimiter to
            accomodate pedigree files that are not CSV;
+++     03/31/2004      pyp_utils/preprocess now properly handles base
            animals that do not have an entry in the pedigree
            file, that is, who only appear as a sire or dam
            in another animal's record;
*** 04/06/2003  Complete rewrite of PyPedal begun.  Major changes
            include incorporation of metadata into the pedigree
            object.

CHANGES in PyPedal 0.0.1
========================
*** First version released to the general public;
--- a_effective_founders_boichard() does not return correct
    answers.  I have not yet found the error in my implementation
    of Boichard's algorithm;
--- a_effective_ancestors_definite() does not return correct
        answers.  I have not yet found the error in my implementation
        of Boichard's algorithm;
??? a_effective_founders_lacy() is believed to work correctly;
--- a_matrix() is deprecataed in favor of fast_a_matrix().  It will
    return a properly-formed numerator relationship matrix, but it
    is extremely slow (orders-of-magnitude slower than fast_a_matrix());
--- reorder() is deprecated in favor of fast_reorder();
??? Neither reorder() nor fast_reorder() should be used on a pedigree
    returned by renumber() unless the results are checked very carefully.
    In some cases, renumbered pedigrees are reordered incorrectly.  This
    is due to a bug in the ID padding algorithm which is believed to be
    fixed, but more testing is needed;
