genetic-0.1.1b.orig/CHANGELOG0000644002342000000500000000022310037072553015166 0ustar ducksrc00000000000000Genetic Changelog : Genetic 0.1.1: -Nested scopes bug fixed (thanks to Niki Spahiev) -New demo (demo_jump.py) Genetic 0.1: -First release genetic-0.1.1b.orig/LICENSE0000755002342000000500000004307610037072553015001 0ustar ducksrc00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. genetic-0.1.1b.orig/MANIFEST0000644002342000000500000000063310037072553015112 0ustar ducksrc00000000000000CHANGELOG LICENSE MANIFEST MANIFEST.in README __init__.py environment.py lifecycle.py mutablelist.py organism.py prog.py setup.py demo/__init__.py demo/demo_1.py demo/demo_2.py demo/demo_3.py demo/demo_4.py demo/demo_5.py demo/demo_circle.py demo/demo_graph.py demo/demo_jump.py demo/demo_philosophy.py demo/demo_prog_1.py demo/demo_prog_graph.py demo/demo_saleman.py demo/demo_saleman_2.py demo/demo_sphere.py genetic-0.1.1b.orig/MANIFEST.in0000755002342000000500000000011210037072553015512 0ustar ducksrc00000000000000global-include * global-exclude *.pyc *.pyc *.pyo *.old *.save *.disabled genetic-0.1.1b.orig/PKG-INFO0000644002342000000500000000034310037072553015054 0ustar ducksrc00000000000000Metadata-Version: 1.0 Name: Genetic Version: 0.1.1 Summary: Genetic algorythms in Python Home-page: UNKNOWN Author: Jiba (LAMY Jean-Baptiste) Author-email: jiba@tuxfamily.org License: GPL Description: UNKNOWN Platform: UNKNOWN genetic-0.1.1b.orig/README0000755002342000000500000000166610037072553014653 0ustar ducksrc00000000000000Genetic 0.1 This is a package for Artificial Intelligence and genetic algos in Python. To install it, run : python setup.py build su python setup.py install You'll find some demo / experience / ... in genetic/demo, including the famous TSP. Read genetic/demo/genetic_demo_2.py for the list of the special "magic" genes that make Genetic really fun and... living ! try : python genetic/demo/demo_jump.py python genetic/demo/demo_saleman.py python genetic/demo/demo_circle.py (require at least Python 2.1) python genetic/demo/demo_graph.py for demo with Tkinter interface. The genetic.prog module contains genetic programming stuff... but they are not efficient at all. Try python genetic/demo/demo_prog_graph.py for a Tk demo. I really wonder if i don't give too much liberty to my organism, as they something refuse to evoluate and solve the problem... 8-O Mail me for any trouble, comment or question ! Jiba -- jiba@tuxfamily.org genetic-0.1.1b.orig/__init__.py0000755002342000000500000000022410037072553016071 0ustar ducksrc00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. VERSION = "0.1" genetic-0.1.1b.orig/demo/__init__.py0000755002342000234200000000020510037072553020245 0ustar duckcoinusers00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. genetic-0.1.1b.orig/demo/demo_1.py0000755002342000234200000001460110037072553017657 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math, genetic.organism, genetic.lifecycle from genetic import organism, lifecycle # The only thing we can currently do is minimizing a function -- Hey, if you're # not sure, yes it means that it can do a LOT of things !! # # So first, we need to set the function to minimize. We'll call it FUNC. # # Obviously, x ** 2 + y ** 2 is minimum for (x, y) = (0.0, 0.0) ! FUNC = lambda x, y: x ** 2 + y ** 2 # Now, let create a new organism class, FUNCMinimizer, that extends the base # organism class, organism.Organism. # This organism has only one characteristic, FUNC, and it is computed by our # FUNC function, with a recessive behaviour -- RECESSIVE_PHENOTYPE means that # we choose the best gene's combination. class FUNCMinimizer(organism.Organism): characteristics = [ organism.Characteristic("FUNC", FUNC, organism.RECESSIVE_PHENOTYPE) ] # This compare method says how we should compare 2 organisms # Remember : the smaller is the better ! # Here, comparing 2 organisms means to compare their FUNC value. We want the # smaller one ! # If there was several characteristics, we would choose one or a combinate # them. def __cmp__(self, other): # self and other are both organisms of class FUNCMinimizer. # The FUNC attribute corresponds to the value given by FUNC for the # organism return cmp(self.FUNC, other.FUNC) # But how work genetic algorythms ? # # It's easy : we create organisms. Each organism has some genetic stuff called 'genotype'. # This genotype contains genes. Genes are the argument for FUNC, "x" and "y" here. # # Genes are organized in chromosoms (a group of genes), and the genotype is a list of pairs # of chromosoms. Both chromosoms of a pair have the same gene, but possibly with 2 different # values -- e.g. x = 0.0 and x = 1.0. # # So a single organism carries MANY VALUES (usually 2) for a given gene / variable. # # As we have many values for each gene, we must choose some for FUNC ! This is done by the # phenotype function, i call it PHENOTYPE. PHENOTYPE takes a genotype (= a list of pairs of # chromosoms) as argument, and returns the corresponding phenotype (a tuple with the value # returned by FUNC, and the choosen genes's values). # The lower the phenotype is, the "better" the organism is. # # An organism can reproduce with another (i've not implemented any "sex rextriction", so # anyone can reproduce with anyone). Reproduction create a new organism, whose genotype is # a mix of its parent genotype. # # Running a generation consists in creating a lot of children from the current organism pool, # then all the organisms die and they are replaced by their best children -- other die too. # Lots of deads... we are ready for a next generation. # # The phenotype function. # # 3 functions are provided in the organism module; you can create your own if you want. # The RECESSIVE_PHENOTYPE function correspond to a recessive phenotype = it choose the # genes's combination that give the best result (=the smaller result, as we want to # minimize), and often give the best result. But PERCHROMOSOME_DOMINANCY_PHENOTYPE is faster. # Create an initial set of organisms. We need at least 2 of them. # # Organism can be created from a list of chromosoms pairs, or, as here, from # a list of chromosoms. In this case, the organism is homozygote, and both # chromosoms of each pair are the same. # A chromosom is created by passing to its constructor its genes : # Chromosom(gene = value, ...) # # You can provide as many genes as you want; but you MUST provide genes that # have the same names that the arguments of FUNC ! # # The value of the x and y genes are totally arbitrary ! # We may also choose to put the "x" and the "y" genes on 2 separate chromosoms. # This choice is arbitrary too. organismA = FUNCMinimizer([ organism.Chromosom(x = 6.2, y = -5.4), ]) organismB = FUNCMinimizer([ organism.Chromosom(x = -40.0, y = 1.0), ]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 10 # Number of children each generation made NB_CHILDREN = 100 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 10 # Ready ! # # This will make live a lot of organism, and finally print the last and "best" one -- the # one whose phenotype minimizes FUNC ! lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) # The output will look like that (but values will probably differ) : # # FUNC('x', 'y') : 0.000643230178664(0.024210502678058316, 0.0075552457762450564) # genotype, chromosome 0 A : # __break__ : 0.00129864317455 # __crossover__ : 0.191624101595 # __deletion__ : 0.00266990769512 # __dominancy__ : 0.0238659494491 # __duplicate__ : 0.0195951343295 # __loss__ : 0.0495540539135 # __mutampl__ : 0.315303864049 # __mutation__ : 0.0980921568131 # x : -0.177204523541 # y : 0.00755524577625 # genotype, chromosome 0 B : # __break__ : 0.000186398770834 # __crossover__ : 0.0628874380032 # __deletion__ : 0.00564882153852 # __dominancy__ : 0.00724456057466 # __duplicate__ : 0.00610509831268 # __loss__ : 0.0384499434339 # __mutampl__ : 0.0224471002322 # __mutation__ : 3.85230515612 # x : 0.0242105026781 # y : -3.87113452133 # # The first line shows the phenotype : the minimal value found for FUNC # (=0.000643230178664), and the corresponding genes's value (x and y). # # The following describes the organism's genetic stuff. Here, you can see one # pair of 2 chromosoms (named "0 A" and "0 B"), and a line for each gene, with # its name and its value. # # Don't care about the ____ value for now. But notice that the x and # y value choosen for the phenotype are the "best" ones -- the ones for which # FUNC returns the lower number. This is because we've used the # RECESSIVE_PHENOTYPE function. genetic-0.1.1b.orig/demo/demo_2.py0000755002342000234200000000761310037072553017665 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math from genetic import organism, lifecycle # Set the function to minimize. We choose the cosinus function, between 0.0 and 6.0 -- the # minimum is PI ! def FUNC(x): if x < 0.0 or x > 6.0: return None # Organism with "None" phenotype cannot live ! return math.cos(x) class FUNCMinimizer(organism.Organism): characteristics = [ organism.Characteristic("FUNC", FUNC, organism.RECESSIVE_PHENOTYPE) ] def __cmp__(self, other): return cmp(self.FUNC, other.FUNC) # Create the initial set of organisms. # # As usual in Python, ____ genes are some "magic" value that # influence the chromosom replication or stability : # # __mutation__ is the pobability that each gene mutate while reproducting, # ranging from 0.0 to 1.0. # # __mutampl__ is the amplitude of the mutation. A gene that mutate is modified # by + or - a random number ranging from 0.0 to __mutampl__. Notice that # __mutampl__ doesn't apply to magic genes, for them the old value of the gene # is used instead. # # __mutsign__ is the sign of the mutation. If __mutsign__ is 0.0 (default) or # if 0.5 < __mutsign__ < 2.0, the mutation can be + or - (it can increase or # decrease the gene value). If __mutsign__ < 0.5, the mutation can only # decrease the value; if > 2.0, it can only increase. # # __crossover__ is the probability that a cross-over occurs -- a cross-over # will mix 2 chromosom. # # __deletion__ is the probability to delete a random gene -- organism doesn't # like that... # # __loss__ is the probability for the chromosom to be lost -- organism doesn't # like it too ! # # __swap__ is the probability to swap the values of 2 random genes. # # __duplicate__ is the probability to get a random gene from the other # chromosom. # # __break__ is the probability for the chromosom to be broken in 2 parts. If # you use the recessive PHENOTYPE, organism often like this one, as it allows # them to have more genetic stuff -- more chance to survive ! # # __dominancy__ is the dominancy of the chromosom. This is only use by the # PHENOTYPE function organism.perchromosom_dominancy_phenotype, which choose # the genes of the most dominant chromosom. # # What is really MAGIC is that the are genes... so they can mutate ! Yes, the # probability of mutation can change ! This is what make the organisms # adaptate very well. # # Those magic genes are set per-chromosom, so if you have genes with different # scales or units, it can be a good idea to put them on different chromosom # (so they can have different magic values). # # Notice that, if __mutation__ and/or __mutampl__ fall down, the organisms # won't continue their evolution, and they will refuse to go on, even if they # are not at the "end" of the problem ! So yes, they are free to "fix" them # where they are, and stop evoluting ! This is also a kind of adaptation... ;-) organismA = FUNCMinimizer([ organism.Chromosom(__mutation__ = 0.5, __mutampl__ = 4.0, x = 5.0), ]) organismB = FUNCMinimizer([ organism.Chromosom(__mutation__ = 1.0, __mutampl__ = 2.0, x = 1.0), ]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 8 # Number of children each generation made NB_CHILDREN = 75 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 10 # Ready ! # # This will make live a lot of organism, and finally print the last and "best" # one -- the one whose phenotype minimizes FUNC ! lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) # You should approach the PI value. # # Obviously, mathematicians will say that the cos function already include the # PI value, so we do nothing... let them speak and let our organisms live ! genetic-0.1.1b.orig/demo/demo_3.py0000755002342000234200000000314310037072553017660 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math from genetic import organism, lifecycle # Set the function to minimize. def FUNC(x): if x < 0.0 or x > 6.0: return None # Organism with "None" phenotype cannot live ! return math.cos(x) class FUNCMinimizer(organism.Organism): characteristics = [ organism.Characteristic("FUNC", FUNC) ] def __cmp__(self, other): return cmp(self.FUNC, other.FUNC) # Create an initial set of organisms. # # Here, we've set the deletion to 0.5 = 50%. Remember, organisms hate loosing gene... # So you will see the value of the __deletion__ gene falling down accross the generation ! # # See how your organisms adaptate and reject the "bad" gene ! organismA = FUNCMinimizer([ organism.Chromosom(__deletion__ = 0.5, __mutation__ = 0.5, __mutampl__ = 4.0, x = 5.0), ]) organismB = FUNCMinimizer([ organism.Chromosom(__deletion__ = 0.5, __mutation__ = 1.0, __mutampl__ = 2.0, x = 1.0), ]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 8 # Number of children each generation made NB_CHILDREN = 75 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 10 # Ready ! lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) # You should approach the PI value -- but worse than the previous demo, since # the deletion slows the organisms evolution ! genetic-0.1.1b.orig/demo/demo_4.py0000755002342000234200000000256610037072553017671 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math from genetic import organism, lifecycle # Set the function to minimize. FUNC = lambda x, y: x ** 2 + y ** 2 class FUNCMinimizer(organism.Organism): characteristics = [ organism.Characteristic("FUNC", FUNC, organism.RECESSIVE_PHENOTYPE) ] def __cmp__(self, other): return cmp(self.FUNC, other.FUNC) # Create an initial set of organisms. # # This time, the organisms are already "perfect" : they minimize FUNC ! # # As organisms don't need to evoluate, you will see __mutation__ and __mutampl__ falling # down ! ANY mutation is bad here ! organismA = FUNCMinimizer([ organism.Chromosom(x = 0.0, y = -0.0), ]) organismB = FUNCMinimizer([ organism.Chromosom(x = -0.0, y = 0.0), ]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) -- We MUST disable it here ! (Else we'll get the first organism at the end !) ELITISM = 0 # Number of generation to run NB_GENERATION = 10 # Number of children each generation made NB_CHILDREN = 100 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 10 # Ready ! lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) genetic-0.1.1b.orig/demo/demo_5.py0000755002342000234200000000270610037072553017666 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math from genetic import organism, lifecycle # Set the function to minimize. f(x) = x minimize in -infinity ! def FUNC(x): return x class FUNCMinimizer(organism.Organism): characteristics = [ organism.Characteristic("FUNC", FUNC, organism.RECESSIVE_PHENOTYPE) ] def __cmp__(self, other): return cmp(self.FUNC, other.FUNC) # Create the initial set of organisms. organismA = FUNCMinimizer([ organism.Chromosom(x = 5.0), ]) organismB = FUNCMinimizer([ organism.Chromosom(x = 1.0), ]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 10 # Number of children each generation made NB_CHILDREN = 100 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 10 # Ready ! lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) # This time we see __mutation__ and __mutampl__ increasing quickly ! # # Obviously the final result IS NOT the minimum, as we'll never obtain infinity. But, at the # end of the experience, if you can see that __mutation__ and / or __mutampl__ are high, # this clearly means that you are not arrived at the real minimum, since the organisms are # not stable ! genetic-0.1.1b.orig/demo/demo_circle.py0000755002342000234200000000602110037072553020755 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. from __future__ import nested_scopes import random, string, math, Tkinter from genetic import organism, lifecycle SIZE = 250 class Point: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return "" % (self.x, self.y) points = [] def radius_func(x, y): # return the largest distance from the center (x, y) to one of the points. if len(points) == 0: return 0.0 return max(map(lambda point: math.sqrt((point.x - x) ** 2 + (point.y - y) ** 2), points)) class CircleMinimizer(organism.Organism): characteristics = [ organism.Characteristic("radius", radius_func, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE) ] def __cmp__(self, other): # Say how we compare 2 organisms. Here, the lower the circle radius is the better the organism is. return cmp(self.radius, other.radius) class Graph(Tkinter.Canvas): def __init__(self, master): Tkinter.Canvas.__init__(self, master, bg = "white", width = SIZE, height = SIZE) self.bind("", self.leftClick ) self.circle = None organismA = CircleMinimizer([ organism.Chromosom(x = 50.0, y = 120.0, __mutampl__ = 50.0, __mutation__ = 0.8, __break__ = 0.0), ]) organismB = CircleMinimizer([ organism.Chromosom(x = 100.0, y = 100.0, __mutampl__ = 20.0, __mutation__ = 0.8, __break__ = 0.0), ]) self.organisms = [organismA, organismB] def recomputephenotypes(self): for organism in self.organisms: organism._compute_phenotypes() def leftClick (self, event): self.addPoint(Point(event.x, event.y)) def addPoint(self, point): points.append(point) self.create_text(point.x - 0, point.y - 0, text = "+") # Phenotypes have changed, because there is one point more ! self.recomputephenotypes() def generation(self, nb = 1): self.organisms = lifecycle.run(self.organisms, 1, nb, 20, 8) def update(self): if self.circle: self.delete(self.circle) best = self.organisms[0] radius = best.radius x, y = best.radius_args self.circle = self.create_oval(x - radius, y - radius, x + radius, y + radius) class GraphFrame(Tkinter.Tk): def __init__(self): Tkinter.Tk.__init__(self, className = "genetic circle") Tkinter.Label(self, text = "Click some points below, then run 1 or 10 generations !\nI will genetically compute the smallest circle around your points !", wraplength = SIZE + 30).pack() self.graph = Graph(self) self.graph.pack() Tkinter.Button(self, text = "1 generation" , command = self.generation1 ).pack() Tkinter.Button(self, text = "10 generations", command = self.generation10 ).pack() def generation1(self, event = None): self.graph.generation(1) self.graph.update() def generation10(self, event = None): self.graph.generation(10) self.graph.update() graphframe = GraphFrame() Tkinter.mainloop() genetic-0.1.1b.orig/demo/demo_graph.py0000755002342000234200000000722210037072553020621 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. # This demo is similar to demo_prog_graph, but it use genetic algo and not # genetic programming. from __future__ import nested_scopes import random, string, math, operator, Tkinter from genetic import organism, lifecycle, prog SIZE = 250 class Point: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return "" % (self.x, self.y) points = [] # square is the function to minimize. # It takes one arg, an equation, and return the sum of the square distance # between theoretical y (given by equation) and observed y (the ones from the # points list). def equation(a, b, c, d, e, x): return (a * (x ** 2) + b * x + c) / (d * x + e) def square(a, b, c, d, e): try: return reduce(operator.add, map( lambda point : (point.y - equation(a, b, c, d, e, point.x)) ** 2, points)) except TypeError: # error when there is no points. return None except ZeroDivisionError: return None # Non viable phenotype. class EquationFinder(organism.Organism): characteristics = [ organism.Characteristic("square", square, organism.RECESSIVE_PHENOTYPE) ] def __cmp__(self, other): # Say how we compare 2 organisms. Here, the lower the square is, the better the organism is. return cmp(self.square, other.square) class Graph(Tkinter.Canvas): def __init__(self, master): Tkinter.Canvas.__init__(self, master, bg = "white", width = SIZE, height = SIZE) self.bind("", self.leftClick ) self.line = None organismA = EquationFinder([ organism.Chromosom(a = 0.0, b = 1.0, d = 0.0), organism.Chromosom(c = -15.0, e = 1.0), ]) organismB = EquationFinder([ organism.Chromosom(a = 0.1, b = -1.5, d = 0.1), organism.Chromosom(c = 50.0, e = 0.9), ]) self.organisms = [organismA, organismB] def recomputephenotypes(self): for organism in self.organisms: organism._compute_phenotypes() def leftClick (self, event): self.addPoint(Point(event.x, event.y)) def addPoint(self, point): points.append(point) self.create_text(point.x - 0, point.y - 0, text = "+") # Phenotypes have changed, because there is one point more ! self.recomputephenotypes() def generation(self, nb = 1): self.organisms = lifecycle.run(self.organisms, 1, nb, 40, 15) def update(self): if self.line: self.delete(self.line) best = self.organisms[0] a, b, c, d, e = best.square_args # Draw the equation found. def y(x): return (x, equation(a, b, c, d, e, x)) try: return (x, equation(a, b, c, d, e, x)) except: return None xy = map(y, range(0, SIZE, 5)) xy = filter(None, xy) self.line = self.create_line(*xy) class GraphFrame(Tkinter.Tk): def __init__(self): Tkinter.Tk.__init__(self, className = "genetic graph") Tkinter.Label(self, text = "Click some points below, then run 1 or 10 generations !\nI will genetically compute the equation of the curve that pass by your point !", wraplength = SIZE + 30).pack() self.graph = Graph(self) self.graph.pack() Tkinter.Button(self, text = "1 generation" , command = self.generation1 ).pack() Tkinter.Button(self, text = "10 generations", command = self.generation10 ).pack() def generation1(self, event = None): self.graph.generation(1) self.graph.update() def generation10(self, event = None): self.graph.generation(10) self.graph.update() graphframe = GraphFrame() Tkinter.mainloop() genetic-0.1.1b.orig/demo/demo_jump.py0000755002342000234200000001207310037072553020473 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math, Tkinter, thread from genetic import organism, lifecycle SIZE = 250 OBSTACLE_HEIGHT = 100 # You may try some harder challanger, e.g. 150. Or no obstacle, e.g. 0. class JumperOrganism(organism.Organism): characteristics = [ organism.Characteristic("ax", lambda ax: ax, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE), organism.Characteristic("bx", lambda bx: bx, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE), organism.Characteristic("cx", lambda cx: cx, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE), organism.Characteristic("ay", lambda ay: ay, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE), organism.Characteristic("by", lambda by: by, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE), organism.Characteristic("cy", lambda cy: cy, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE), ] def __init__(self, genotype): organism.Organism.__init__(self, genotype) self.reset() def __cmp__(self, other): # Say how we compare 2 organisms. Here, the lower the circle radius is the better the organism is. return cmp(self.jumptime, other.jumptime) def play(self, time): dx = self.ax * self.x + self.bx * self.y + self.cx dy = self.ay * self.x + self.by * self.y + self.cy length = math.sqrt(dx ** 2 + dy ** 2) / 2.0 #print length, dx, dy #print length, dx / length, dy / length newx = self.x + dx / length newy = self.y + dy / length #if newx > self.x + 2.0: newx = self.x + 2.0 #if newx < self.x - 2.0: newx = self.x - 2.0 #if newy > self.y + 2.0: newy = self.y + 2.0 #if newy < self.y - 2.0: newy = self.y - 2.0 if canpass(newx, newy): self.x, self.y = newx, newy else: if canpass(newx, self.y): self.x = newx elif canpass(self.x, newy): self.y = newy if arrived(self.x, self.y): self.arrived = 1 self.jumptime = time def reset(self): self.x = 0.0 self.y = float(SIZE) self.jumptime = None self.arrived = 0 def randomjumper(): return JumperOrganism([ organism.Chromosom(ax = rand(), bx = rand(), cx = rand(), __mutampl__ = 0.1, __mutation__ = 0.8, __break__ = 0.0), organism.Chromosom(ay = rand(), by = rand(), cy = rand(), __mutampl__ = 0.1, __mutation__ = 0.8, __break__ = 0.0), ]) def rand(): return (random.random() - 0.5) / 30.0 def canpass(x, y): return 0 < x < SIZE and 0 < y < SIZE and not (100 < x < 150 and y > (SIZE - OBSTACLE_HEIGHT)) def arrived(x, y): return x > 220 and y > 150 class Graph(Tkinter.Canvas): def __init__(self, master): Tkinter.Canvas.__init__(self, master, bg = "white", width = SIZE, height = SIZE) self.running = 0 self.obstacle = self.create_rectangle(100, SIZE - OBSTACLE_HEIGHT, 150, 250); self.organisms = [randomjumper() for i in range(20)] def generation(self, nb = 1): self.running = 1 thread.start_new_thread(self.run, ()) def run(self): tags = [] for organism in self.organisms: organism.tag = self.create_text(organism.x, organism.y, text = "O") tags.append(organism.tag) for time in range(500): # Let give them 500 moves ! if not self.running: break # Stop ! nooneleft = 1 for organism in self.organisms: if not organism.arrived: oldx, oldy = organism.x, organism.y organism.play(time) self.move(organism.tag, organism.x - oldx, organism.y - oldy) nooneleft = 0 if nooneleft: break # Remove the looser (jumptime is None) self.organisms = filter(lambda organism: not organism.jumptime is None, self.organisms) print "%s organisms arrived at destination !" % len(self.organisms) # Sort them self.organisms.sort() # Take the 10 first self.organisms = self.organisms[:10] # Add random organisms if less than 3 while len(self.organisms) < 3: self.organisms.append(randomjumper()) # Elitism (keep the best one). We need to reset this champion to the start line ! self.organisms[0].reset() # Keep the best one, and 20 new organisms. self.organisms = [self.organisms[0]] + lifecycle.make_love(self.organisms, 20) self.delete(*tags) self.running = 0 class GraphFrame(Tkinter.Tk): def __init__(self): Tkinter.Tk.__init__(self, className = "genetic jump !") Tkinter.Label(self, text = "Organisms starts on the lower left corner; they must arrive at the lower right corner. The rectangle is an obstacle they must jump !\nRun some generations, and organisms will learn how to jump !", wraplength = SIZE + 30).pack() self.graph = Graph(self) self.graph.pack() Tkinter.Button(self, text = "1 generation" , command = self.generation1 ).pack() def generation1(self, event = None): if not self.graph.running: self.graph.generation(1) self.graph.update() else: self.graph.running = 0 graphframe = GraphFrame() Tkinter.mainloop() genetic-0.1.1b.orig/demo/demo_philosophy.py0000755002342000234200000000374710037072553021726 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math from genetic import organism, lifecycle PHENOTYPE_GOOD = 1 PHENOTYPE_EVIL = 2 def alignment(x): if x > 0.0: return PHENOTYPE_GOOD if x < 0.0: return PHENOTYPE_EVIL return None class GoodOrBad(organism.Organism): characteristics = [ organism.Characteristic("alignment", alignment, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE) ] def __cmp__(self, other): return cmp(self.alignment, other.alignment) def cycle(max = 70, printoutput = 1): # Create the initial set of organisms. organismA = GoodOrBad([ organism.Chromosom(x = 1.0, __mutampl__ = 2.0, __break__ = 0.0), ]) organismB = GoodOrBad([ organism.Chromosom(x = -1.0, __mutampl__ = 2.0, __break__ = 0.0), ]) organisms = [organismA, organismB] generation = 0 try: while 1: generation = generation + 1 if generation > max: return PHENOTYPE_GOOD children = lifecycle.make_love(organisms, 30) organisms = children nb_evil = len(filter(lambda organism: organism.alignment == PHENOTYPE_EVIL, organisms)) for i in range(nb_evil): organisms.remove(random.choice(organisms)) if len(organisms) == 0: return PHENOTYPE_EVIL nb_good = len(filter(lambda organism: organism.alignment == PHENOTYPE_GOOD, organisms)) if printoutput: print "generation %s: %s organisms, %s%% good." % (generation, len(organisms), (nb_good * 100.0) / len(organisms)) except: return PHENOTYPE_EVIL nb_good = 0 for i in range(100): if cycle(50, 0) == PHENOTYPE_GOOD: nb_good = nb_good + 1 print "test %s: good wins ;-)" % i else: print "test %s: evil wins :-(" % i print "result %s%% good." % nb_good genetic-0.1.1b.orig/demo/demo_prog_1.py0000755002342000234200000000377110037072553020714 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. from __future__ import nested_scopes import random, string, math, operator from genetic import organism, lifecycle, prog class Point: def __init__(self, x, y): self.x = x self.y = y points = [ Point(0.0, 0.0 ), Point(0.5, 0.45), Point(0.7, 0.7 ), Point(0.8, 0.82), ] def square(equation): try: return reduce(operator.add, map( lambda point : (point.y - equation(x = point.x)) ** 2, points)) except ZeroDivisionError: return None equationcontext = prog.EquationContext(x = 0.0) import sys, operator #eq = equationcontext(data = [operator.add, -0.012010999445366544, equationcontext.args[0]]) #print eq, square(eq) #sys.exit() class EquationFinder(organism.Organism): characteristics = [ organism.Characteristic("square", square, organism.RECESSIVE_PHENOTYPE) ] def __cmp__(self, other): return cmp(self.square, other.square) organismA = EquationFinder([ organism.Chromosom(equation = equationcontext()), ]) organismB = EquationFinder([ organism.Chromosom(equation = equationcontext()), ]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 10 # Number of children each generation made NB_CHILDREN = 100 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 10 # Ready ! # # This will make live a lot of organism, and finally print the last and "best" one -- the # one whose phenotype minimizes FUNC ! organisms = lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) print organisms[0].genotype[0][0].__dict__.keys() print organisms[0].genotype[0][0].equation print square(organisms[0].genotype[0][0].equation) print organisms[0].genotype[0][1].equation print square(organisms[0].genotype[0][1].equation) genetic-0.1.1b.orig/demo/demo_prog_graph.py0000755002342000234200000000750110037072553021650 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math, operator, Tkinter from genetic import organism, lifecycle, prog SIZE = 250 class Point: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return "" % (self.x, self.y) points = [] # square is the function to minimize. # It takes one arg, an equation, and return the sum of the square distance # between theoretical y (given by equation) and observed y (the ones from the # points list). def square(equation): try: return reduce(operator.add, map( lambda point : (point.y - equation(x = point.x)) ** 2, points)) except TypeError: # error when there is no points. return None except ZeroDivisionError: return None # Non viable phenotype. # Create a new equation context. # The equation context takes the arguments/parameters of the equation to find # (don't care about the value given to these parameters; they are currently # unused !). # Equation context acts as a metaclass for creating equation object. equationcontext = prog.EquationContext(x = 0.0) # Create our organism class. # It has one characteristic, "square". It's the value returned by the function # of the same name. class EquationFinder(organism.Organism): characteristics = [ organism.Characteristic("square", square, organism.RECESSIVE_PHENOTYPE) ] def __cmp__(self, other): # Say how we compare 2 organisms. Here, the lower the square is, the better the organism is. return cmp(self.square, other.square) class Graph(Tkinter.Canvas): def __init__(self, master): Tkinter.Canvas.__init__(self, master, bg = "white", width = SIZE, height = SIZE) self.bind("", self.leftClick ) self.line = None organismA = EquationFinder([ organism.Chromosom(equation = equationcontext()), ]) organismB = EquationFinder([ organism.Chromosom(equation = equationcontext()), ]) self.organisms = [organismA, organismB] def recomputephenotypes(self): for organism in self.organisms: organism._compute_phenotypes() def leftClick (self, event): self.addPoint(Point(event.x, event.y)) def addPoint(self, point): points.append(point) self.create_text(point.x - 0, point.y - 0, text = "+") # Phenotypes have changed, because there is one point more ! self.recomputephenotypes() def generation(self, nb = 1): self.organisms = lifecycle.run(self.organisms, 1, nb, 25, 10) def update(self): if self.line: self.delete(self.line) best = self.organisms[0] # Recover the arguments list given to the square function. # The first (and last) one is the equation. equation = best.square_args[0] # Draw the equation found. def y(x): try: return (x, equation(x = x)) except: return None xy = map(y, range(0, SIZE, 5)) xy = filter(None, xy) self.line = self.create_line(*xy) class GraphFrame(Tkinter.Tk): def __init__(self): Tkinter.Tk.__init__(self, className = "genetic graph") Tkinter.Label(self, text = "Click some points below, then run 1 or 10 generations !\nI will genetically compute the equation of the curve that pass by your point !", wraplength = SIZE + 30).pack() self.graph = Graph(self) self.graph.pack() Tkinter.Button(self, text = "1 generation" , command = self.generation1 ).pack() Tkinter.Button(self, text = "10 generations", command = self.generation10 ).pack() def generation1(self, event = None): self.graph.generation(1) self.graph.update() def generation10(self, event = None): self.graph.generation(10) self.graph.update() graphframe = GraphFrame() Tkinter.mainloop() genetic-0.1.1b.orig/demo/demo_saleman.py0000755002342000234200000001103310037072553021133 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. from __future__ import nested_scopes import random, string, math, operator from genetic import organism, lifecycle # This will solve the traveller saleman problem (=TSP). # SEE demo_saleman_2.py FOR A MUCH EFFICIENT IMPLEMENTATION WITH TK INTERFACE ! # # The saleman must travel from city to city, and pass in each city; but he # wants to walk as less as possible... Are genetic algos his best chance ? # Define a City class. Cities are defined by 2 coordinates x and y on a map. class City: next_id = 0 def __init__(self, x, y): self.x, self.y = x, y self.id = City.next_id self.name = "city" + str(self.id) City.next_id = City.next_id + 1 # Define a list of cities. You can add some if you want. # With this value, the minimum distance is 4 -- but this demo doesn't give # really good results. cities = [ City(0.0, 0.0), City(0.8, 0.0), City(0.1, 0.0), City(1.0, 0.0), City(0.0, 1.0), City(0.8, 1.0), City(0.1, 1.0), City(1.0, 1.0), ] # Define the function to minimize. # # We consider having a gene for each city, called "city", except for the # first city. The saleman always start in the first city ! # # Each gene indicates the priority of the corresponding city : the higher the # corresponding gene value is, the first the city will be visited. # # journey_distance takes the list of city-priorities (= the genes values) and # return the length of the journey. def journey_distance(*city_priorities): # city_priorities is : [city1_priority, city2_priority, ...] # 1 - Associate each priority with its city index, in a tuple : [(city1_priority, city1), (city2_priority, city2), ...] city_list = map(None, city_priorities, cities[1:]) # 2 - Sort the city_list by priority (= the first value in the tuple) city_list.sort() # 3 - Remove the priorities -- there are useless now city_list = map(lambda tuple: tuple[1], city_list) # 4 - Add the first city at the beginning city_list.insert(0, cities[0]) # 5 - Compute the journey distance return reduce(operator.add, map(lambda cityA, cityB: math.sqrt((cityA.x - cityB.x) ** 2 + (cityA.y - cityB.y) ** 2), city_list, city_list[1:] + [city_list[0]])) class TSPSolver(organism.Organism): characteristics = [ organism.Characteristic("journey_distance", journey_distance, organism.PERCHROMOSOM_DOMINANCY_PHENOTYPE, [ city.name for city in cities[1:]] # = ["city0", "city1", ...] the args names must be explicitely specified, because they cannot be guessed from the journey_distance function. ) ] def __cmp__(self, other): return cmp(self.journey_distance, other.journey_distance) # Override the Organism.__repr__ method, so it will give the city order def __repr__(self): # self.journey_distance_args is the args that has been used to compute # journey_distance -- the city_priorities ! city_list = map(None, self.journey_distance_args, cities[1:]) # 2 - Sort the city_list by priority (= the first value in the tuple) city_list.sort() # 3 - Remove the priorities -- there are useless now city_list = map(lambda tuple: tuple[1], city_list) # 4 - Add the first city at the beginning city_list.insert(0, cities[0]) repr = "Cities order : %s\n" % map(lambda city: city.name, city_list) return repr + organism.Organism.__repr__(self) # Create an initial set of organisms. # # This complex dict manipulation allows to automatically give the needed genes, # but you can also use organism.Chromosom(city1 = 0.0, city2 = 0.0, ...) args_names = TSPSolver.characteristics[0].funcargs genesA = { "__mutation__" : 10.0, "__mutampl__" : 5.0 } map(genesA.__setitem__, args_names, [0.0] * len(args_names)) organismA = TSPSolver([organism.Chromosom(**genesA)]) genesB = { "__mutation__" : 10.0, "__mutampl__" : 5.0 } map(genesB.__setitem__, args_names, [10.0] * len(args_names)) organismB = TSPSolver([organism.Chromosom(**genesB)]) organisms = [organismA, organismB] # Define some parameters # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 6 # Number of children each generation made NB_CHILDREN = 100 # Number of organisms kept per generation (other children doesn't survive) NB_ORGANISMS = 4 # Ready ! lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS, 0) genetic-0.1.1b.orig/demo/demo_saleman_2.py0000755002342000234200000001004210037072553021353 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math, operator, Tkinter from genetic import organism, lifecycle, mutablelist # This will solve the traveller saleman problem (=TSP) with a different, MUCH # efficient approach than demo_saleman.py. # # The saleman must travel from city to city, and pass in each city; but he # wants to walk as less as possible... Are genetic algos his best chance ? # Define a City class. Cities are defined by 2 coordinates x and y on a map. class City: next_id = 0 def __init__(self, x, y): self.x, self.y = x, y self.id = City.next_id self.name = "city" + str(self.id) City.next_id = City.next_id + 1 def __repr__(self): return self.name # Define a list of cities. cities = [] # Define the function to minimize. # # Here, we'll use a MutableOrderList, i.e. a list whose order can mutate # (= item are swapped in the list). # # MutableOrderList extends the Chromosom class. The gene that contains the list # is called "data", and so the arg of journey_distance is called "data" too. def journey_distance(data): # data is : [first_city, second_city, ...] return reduce(operator.add, map(lambda cityA, cityB: math.sqrt((cityA.x - cityB.x) ** 2 + (cityA.y - cityB.y) ** 2), data, data[1:] + [data[0]])) # Create our class of organism, with a "journey_distance" characteristic that # we want to minimize. class TSPSolver(organism.Organism): characteristics = [ organism.Characteristic("journey_distance", journey_distance, organism.RECESSIVE_PHENOTYPE) ] # An organism is better (= smaller) than another if the journey is shorter. def __cmp__(self, other): return cmp(self.journey_distance, other.journey_distance) SIZE = 250 class Graph(Tkinter.Canvas): def __init__(self, master): Tkinter.Canvas.__init__(self, master, bg = "white", width = SIZE, height = SIZE) self.bind("", self.leftClick ) self.line = None #self.reset() def reset(self): listA = cities[:] random.shuffle(listA) organismA = TSPSolver([ mutablelist.MutableOrderList(data = listA), ]) listB = cities[:] random.shuffle(listB) organismB = TSPSolver([ mutablelist.MutableOrderList(data = listB), ]) self.organisms = [organismA, organismB] def leftClick (self, event): self.addcity(City(event.x, event.y)) def addcity(self, city): cities.append(city) self.create_text(city.x - 0, city.y - 0, text = "+") # Phenotypes have changed, because there is one more city ! self.reset() def generation(self, nb = 1): self.organisms = lifecycle.run(self.organisms, 1, nb, 50, 7) def update(self): if self.line: self.delete(self.line) best = self.organisms[0] cities = best.journey_distance_args[0] xy = map(lambda city: (city.x, city.y), cities) xy.append(xy[0]) # close the figure self.line = self.create_line(*xy) class GraphFrame(Tkinter.Tk): def __init__(self): Tkinter.Tk.__init__(self, className = "genetic saleman traveler") Tkinter.Label(self, text = "Click some points below, then run 1 or 10 generations !\nI will genetically compute the shortest ways between all your points !", wraplength = SIZE + 30).pack() self.graph = Graph(self) self.graph.pack() Tkinter.Button(self, text = "1 generation" , command = self.generation1 ).pack() Tkinter.Button(self, text = "10 generations", command = self.generation10 ).pack() def generation1(self, event = None): if len(cities) < 2: print "No enough cities ! Click in the white rectangle !" else: self.graph.generation(1) self.graph.update() def generation10(self, event = None): if len(cities) < 2: print "No enough cities ! Click in the white rectangle !" else: self.graph.generation(10) self.graph.update() graphframe = GraphFrame() Tkinter.mainloop() genetic-0.1.1b.orig/demo/demo_sphere.py0000755002342000234200000000323310037072553021004 0ustar duckcoinusers00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import random, string, math from genetic import organism, lifecycle # Set the function to minimize. # # Here we compute the smallest sphere that contains all the points in the following list. # FUNC return the sphere radius, and genes are the center coordinates (x, y, z). points = [ [ 1.0, 0.0, 0.0], [-1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [0.0, 0.0, -1.0], ] def radius_func(x, y, z): radius = 0.0 for point in points: distance = math.sqrt((point[0] - x) ** 2 + (point[1] - y) ** 2 + (point[2] - z) ** 2) if distance > radius: radius = distance return radius class SphereMinimizer(organism.Organism): characteristics = [ organism.Characteristic("radius", radius_func) ] def __cmp__(self, other): # Say how we compare 2 organisms. Here, the lower the sphere radius is the better the organism is. return cmp(self.radius, other.radius) # Initial set of organisms organismA = SphereMinimizer([ organism.Chromosom(x = -0.5, y = 9.8, z = 0.9, __mutampl__ = 2.0, __mutation__ = 0.8), ]) organismB = SphereMinimizer([ organism.Chromosom(x = -5.5, y = 0.2, z = -1.0, __mutampl__ = 2.0, __mutation__ = 0.8), ]) organisms = [organismA, organismB] # True for elitism (= always keep the best organism) ELITISM = 1 # Number of generation to run NB_GENERATION = 10 # Number of children they made NB_CHILDREN = 50 # Number of organisms kept per set NB_ORGANISMS = 10 lifecycle.run(organisms, ELITISM, NB_GENERATION, NB_CHILDREN, NB_ORGANISMS) genetic-0.1.1b.orig/environment.py0000755002342000000500000000020410037072553016674 0ustar ducksrc00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. genetic-0.1.1b.orig/lifecycle.py0000755002342000000500000000650110037072553016275 0ustar ducksrc00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. """genetic.lifecycle -- generation and life-cycle management Just setup genetic.organism and then call run(...) to run a big number of generations ! """ import organism, random, string, math def couple(organisms): """couple([organism1, organism2, ...]) -> (father, mother) -- Get a random couple from a list of organisms.""" father, mother = None, None while father is mother: father, mother = random.choice(organisms), random.choice(organisms) return father, mother def make_love(organisms, nb_children): """make_love(organisms, nb_children) --> children -- Make the requested number of children, from the given population of organisms.""" if len(organisms) < 2: import sys print print "Less than 2 organisms ! Cannot continue !" sys.exit(1) children = [] for i in xrange(nb_children): father, mother = couple(organisms) child = organism.multiply(father, mother) if child is None or not child.canlive: # This child is not OK... continue children.append(child) return children def life_cycle(organisms, elitism, nb_children, nb_organisms): """life_cycle(organisms, elitism, nb_children, nb_organisms) -> [Organism1, ...] -- Do a life cycle / a generation for the given organisms, and return the new population. If true, elitism means always keep the better organism. nb_children is the requested number of children, and nb_organisms the number oOrganismf organisms to retain in the final population. """ children = make_love(organisms, nb_children) if elitism: # Add the best organism of the previous generation in the possible candidates for the next one. children.append(min(organisms)) children.sort() organisms = [] for child in children: if not child in organisms: organisms.append(child) if len(organisms) >= nb_organisms: break return organisms def dump(organisms): """dump(organisms) -- print the given list of organisms.""" i = 0 for organism in organisms: print "organism %s :" % i print indent(`organism`) i = i + 1 def indent(s, indentation = " "): """indent("firstline\nsecondline\n,...") -> " firstline\n secondline\n,..." -- Indent the given line of text.""" return indentation + string.join(s.split("\n"), "\n%s" % indentation)[:-len(indentation)] def run(organisms, elitism = 1, nb_generation = 10, nb_children = 100, nb_organisms = 10, dump_generation = 0): """run(organisms, elitism = 1, nb_generation = 10, nb_children = 100, nb_organisms = 10, dump_generation = 0) -- Runs the given number of generations, starting with the given population (=sequence) of organisms. If true, elitism means always keep the better organism. nb_children is the number of children created per generation, and nb_organisms the number of organisms to retain in the final population, for each generation. If dump_generation is true, dumps all generation. Else, prints only the final best organisms.""" for i in xrange(nb_generation): print print "Generation %s..." % i organisms = life_cycle(organisms, elitism, nb_children, nb_organisms) if dump_generation: dump(organisms) best = organisms[0] print print "Best organism :" print `best` return organisms genetic-0.1.1b.orig/mutablelist.py0000755002342000000500000000256510037072553016671 0ustar ducksrc00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. """genetic.prog -- module for genetic programming """ import operator, random, UserList, copy from genetic import organism class MutableOrderList(organism.Chromosom, UserList.UserList): """MutableOrderList implements a list; the order of its items can be changed (by mutation, ...) but the number and the value of these items don't change. Usefull for TSP (see demo) ! """ DEFAULT_GENES = { "__crossover__" : 0.0 , "__mutation__" : 0.6 , "__loss__" : 0.0 , } def __init__(self, **genes): UserList.UserList .__init__(self) organism.Chromosom.__init__(self, **genes) def useless(self): return 0 def crossover(self, other): # No cross-over here ! pass def checkmutate(self): newdict = self.checkmutate_object(self.__dict__) if not newdict is self.__dict__: mutated = self.__class__(**newdict) else: mutated = self for i in range(len(self)): if random.random() < self.__mutation__: if mutated is self: mutated = self.__class__(**self.__dict__) mutated[i - 1], mutated[i] = mutated[i], mutated[i - 1] return mutated # def __repr__(self): # return organism.Chromosom.__repr__(self) + " \t : %s\n" % (gene, value) genetic-0.1.1b.orig/organism.py0000755002342000000500000003775510037072553016174 0ustar ducksrc00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. """genetic.organism -- Organism and Chromosom class. FUNC is the function to minimize. The only thing this module can do is minimizing a function, but hey, that can do a LOT of thing !!! You should provide FUNC by calling setfunc(FUNC); see the demos for example. FUNC can take as many args as you need, and those args's names must correspond to genes's names. FUNC must return a float value, or None is no result is available. An Organism is described by his 'genotype' and his 'phenotype'. A 'genotype' is considered to be a list of pairs of chromosoms : [(chromosom_0_A, chromosom_0_B), (chromosom_1_A, chromosom_1_B), ...] Some chromosoms can be 'None', for incomplete pairs. The genotype is inherited from the parents (A child take one chromosom of each pair of each parent). A 'phenotype' is a 2-values tuple; the first value is the result of FUNC for the organism, the second is the sequence of the args for FUNC. The phenotype is computed from the genotype, according to the PHENOTYPE function. This function take the genotype, and must return the genotype, or None is the organism cannot live (e.g. he has lost some gene...). You may want to provide the PHENOTYPE function by calling setphenotypefunc(PHENOTYPE); see its docstring for more info. Default is recessive choice. """ #from __future__ import nested_scopes import random, types, copy, operator RECESSIVE_PHENOTYPE = 1 DOMINANT_PHENOTYPE = 2 PERCHROMOSOM_DOMINANCY_PHENOTYPE = 3 class Characteristic: """A characteristic of an organism : e.g. eyes color, ... The characteritic's phenotype is computed from the genotype. This class should be inherited/extended to create different, and : A characteristic id defined by : - The "func" function that computes its value. "func" takes genes values and return the phenotype. The args of "func" should have the same names that genes. - The "phenotype" function that choose between the multiple values for a genes the one used by "func" : there's typically 2 values for the same gene, but only one can be used by "func" ! Common phenotype functions are provided in this class, use the following constant in the constructor : RECESSIVE_PHENOTYPE (the default), DOMINANT_PHENOTYPE and PERCHROMOSOME_DOMINANCY_PHENOTYPE. """ def __init__(self, name, func, phenotype = RECESSIVE_PHENOTYPE, funcargs = None): """Characteristic(name, func, phenotype = RECESSIVE_PHENOTYPE, funcargs = None) -> Characteristic -- Create a new characteristic. funcargs is the list of the name of the genes that correspond to "func" argument. If not provided, funcargs is guessed from func's arguments names. """ self.name = name self.func = func if funcargs is None: if not type(func) is types.FunctionType: func = func.im_func self.funcargs = func.func_code.co_varnames[: func.func_code.co_argcount] else: self.funcargs = funcargs if phenotype is RECESSIVE_PHENOTYPE: self.phenotype = self.recessive_phenotype elif phenotype is DOMINANT_PHENOTYPE : self.phenotype = self.dominant_phenotype elif phenotype is PERCHROMOSOM_DOMINANCY_PHENOTYPE: self.phenotype = self.perchromosom_dominancy_phenotype else: self.phenotype = phenotype def perchromosom_dominancy_phenotype(self, genotype): """perchromosom_dominancy_phenotype(genotype) -> phenotype -- Gets the dominant phenotype from the given list, this func use per-chromosom dominancy (__dominancy__ gene). Notice that this phenotype computation method is cheaper in time that dominant or recessive method.""" # 1 - Collects all the values for each gene, in a dict : {"gene1" : (dominancy, value), ...} attrs = {} for pair in genotype: for chromosom in pair: if chromosom is None: continue for gene, value in chromosom.__dict__.items(): attr = attrs.get(gene, None) if (not attr is None) and (attr[0] >= chromosom.__dominancy__): # The previous found version of this gene is on a chromosom more dominant that the current one... skip ! continue attrs[gene] = (chromosom.__dominancy__, value) # 2 - Gets all the attrs needed by func in a list : [(dominancy1, value1), ...] attrs_for_func = map(attrs.get, self.funcargs) # 3 - Gets all the args in a list : [value1, value2, ...] try: args = [attr[1] for attr in attrs_for_func] except TypeError: # A needed gene is not present ! (= attr is None) return (None, None) # 4 - Computes the phenotype return (self.func(*args), args) def recessive_phenotype(self, genotype): """recessive_phenotype(genotype) -> phenotype -- Gets the better phenotype from the given list. This roughly corresponds to a recessive disease.""" # Compute all the phenotype, and choose the one with the minimal value -- the best one def chooser(phenotypes): phenotypes = filter(lambda phenotype: not phenotype[0] is None, phenotypes) if phenotypes: return min(phenotypes) return (None, None) return self._compute_all_phenotypes(genotype, chooser) phenotype = recessive_phenotype def dominant_phenotype(self, genotype): """dominant_phenotype(genotype) -> phenotype -- Gets the worst phenotype from the given list. This roughly corresponds to a dominant disease.""" # Compute all the phenotype, and choose the one with the maximal value -- the worst one def chooser(phenotypes): for phenotype in phenotypes: if phenotype[0] is None: return phenotype return max(phenotypes) return self._compute_all_phenotypes(genotype, chooser) def _compute_all_phenotypes(self, genotype, chooser): """_compute_all_phenotypes(genotype, chooser) -> phenotype -- An utility func that compute ALL the possible phenotype, and let chooser choose the right one. genotype is a list of chromosoms pair, and chooser a function that take a list of phenotypes as argument, and should return the right one.""" # 1 - Collects all the values for each gene, in a dict : {"gene1":[value1, value2, ...], ...} attrs = {} for pair in genotype: for chromosom in pair: if chromosom is None: continue for gene, value in chromosom.__dict__.items(): attr = attrs.get(gene, None) if attr is None: attr = [] attrs[gene] = attr attr.append(value) # Computes the phenotype from the genotype : # 2 - Gets all the args in a list : [[x1, x2], [y1, y2], ...] attrs_for_func = map(attrs.get, self.funcargs) # 3 - Gets all the combinations of these args : [[x1, y1], [x1, y2], ..., [x2, y1], [x2, y2], ...] try: allcombinations = combinations(*attrs_for_func) except EmptyListError: # All the needed genes are not present... this organism cannot live ! return (None, None) # 4 - Computes all the possible phenotypes : [(result, [x1, y1]), ...] phenotypes = [(self.func(*combination), combination) for combination in allcombinations] # 5 - Choose the right one. return chooser(phenotypes) class Organism: """The Organism class. An organism has : - a genotype = a list of (possibly incomplete) pair of chromosoms, - a phenotype, computed from the genotype by the phenotype function of the environment. A phenotype is a tupple whose first element is the phenotype value and whose second element is the list of arguments (= values of genes) that has given this value. You must override this class, and change the class attribute "characteristics". This attribute should be set to the list of characteristics yours organisms have. """ characteristics = [] def __init__(self, genotype): """Organism(genotype) -> Organism -- Creates a new Organism with the given genotype. genotype can be either a list of pairs of chromosoms, or a list of chromosoms for homozygote organisms (= both chromosoms of each pair are the same).""" # 1 - Save data if len(genotype) > 0 and isinstance(genotype[0], Chromosom): # genotype is not a list of pairs of chromosoms but a list of chromosom # => this organism is homozygote genotype = map(None, genotype, genotype) self.genotype = genotype # 2 - Remove useless pair of chromosoms from the genotype -- this may not be really fair... ?? for pair in self.genotype[:]: if (pair[0] is None or pair[0].useless()) and (pair[1] is None or pair[1].useless()): self.genotype.remove(pair) # 3 - Compute the phenotypes self._compute_phenotypes() def _compute_phenotypes(self): # Compute the phenotypes for each characteristic self.canlive = 1 for characteristic in self.characteristics: value, args = characteristic.phenotype(self.genotype) setattr(self, characteristic.name, value) setattr(self, characteristic.name + "_args", args) # The args that give this result -- usefull ! It's often what we want to know. # If a phenotype returns None, there is no available phenotype, so the organism cannot live. if value is None: self.canlive = 0 def __repr__(self): if self.canlive: charac = ["%s%s : %s%s\n" % (characteristic.name, characteristic.funcargs, getattr(self, characteristic.name), getattr(self, characteristic.name + "_args")) for characteristic in self.characteristics] repr = reduce(operator.add, charac) # repr = reduce(operator.add, # map(lambda characteristic: "%s%s : %s%s\n" % (characteristic.name, characteristic.funcargs, getattr(self, characteristic.name), getattr(self, characteristic.name + "_args")), # self.characteristics # ) # ) else: repr = "phenotype : DEAD (non-viable)\n" i = 0 for pair in self.genotype: if pair[0] is None: repr = repr + "genotype, chromosome %s A : None\n" % i else: repr = repr + "genotype, chromosome %s A :\n%s" % (i, `pair[0]`) if pair[1] is None: repr = repr + "genotype, chromosome %s B : None\n" % i else: repr = repr + "genotype, chromosome %s B :\n%s" % (i, `pair[1]`) i = i + 1 return repr def __eq__(self, other): return self.genotype == other.genotype def givetochild(self): gift = [] for pair in self.genotype: chromosom = self.givechromosomtochild(pair) if isinstance(chromosom, Chromosom): gift.append(chromosom) else: gift.extend(chromosom) return gift def givechromosomtochild(self, pair): if pair[0] is None: return pair[1] or [] if pair[1] is None: return pair[0] if random.random() < (pair[0].__crossover__ + pair[1].__crossover__) / 2.0: # Crossing over ! chromosom = pair[0].crossover(pair[1]) else: # Choose a random chromosom if random.random() < 0.5: chromosom = pair[0] else: chromosom = pair[1] # Checks for mutation return chromosom.checkmutate() class Mutable: """Mixin class for mutable object. This allows to use object as gene's value, instead of float. """ def checkmutate(self): """Mutable.checkmutate() -> new value -- Called to check mutation in this mutable object. The returned value should be the mutable object itself if it hasn't been changed. """ pass NotMutableAttributeError = "NotMutableAttributeError" class Chromosom(Mutable): DEFAULT_GENES = { "__dominancy__" : 1.0 , "__mutation__" : 0.5 , "__mutampl__" : 50.0 , "__mutsign__" : 0.0 , "__crossover__" : 0.2 , "__break__" : 0.01, "__deletion__" : 0.01, "__loss__" : 0.01, } def __init__(self, **data): self.__dict__.update(self.DEFAULT_GENES) self.__dict__.update(data) def useless(self): # A useless chromosom is a chromosom that has ONLY "magic" genes (=__(something)__) for gene in self.__dict__.keys(): if not gene.startswith("__"): return 0 return 1 def crossover(self, other): dict = {} genes1 = self .__dict__.items() genes2 = other.__dict__.items() crossat = int(random.random() * len(genes1)) i = 0 while i < crossat: dict[genes1[i][0]] = genes1[i][1] i = i + 1 while i < len(genes2): dict[genes2[i][0]] = genes2[i][1] i = i + 1 return Chromosom(**dict) def checkmutate(self): # Checks if the chromosom is lost if random.random() < self.__loss__: return [] mutated = None newdict = self.checkmutate_object(self.__dict__) if not newdict is self.__dict__: mutated = self.__class__(**newdict) # Checks if a gene is deleted on the chromosom if random.random() < self.__deletion__: if mutated is None: mutated = self.__class__(**self.__dict__) deletablegenes = filter(lambda gene: not gene.startswith("__"), mutated.__dict__.keys()) if len(deletablegenes) > 0: delattr(mutated, random.choice(deletablegenes)) mutated = mutated or self # Checks if the chromosom break in 2 parts if random.random() < self.__break__: genes = mutated.__dict__.items() breakat = int(random.random() * (len(genes) + 1)) genes1, genes2 = {}, {} for i in range(breakat): genes1[genes[i][0]] = genes[i][1] for i in range(breakat, len(genes)): genes2[genes[i][0]] = genes[i][1] return self.__class__(**genes1), self.__class__(**genes2) return mutated def checkmutate_object(self, object, name = ""): objtype = type(object) if objtype is types.FloatType: if random.random() > self.__mutation__: return object if name.startswith("__"): # The gene is a "magic" gene. For magic gene, the amplitude of mutation is the gene's value itself. return object * random.random() * 2.0 else: # Else, use the default mutation sign and amplitude (= the value of the "__mutsign__" and "__mutampl__" gene) mutsign = self.__mutsign__ if mutsign == 0.0 or (mutsign > 0.5 and mutsign < 2.0): # No sign for the mutation return object + (random.random() - 0.5) * 2.0 * self.__mutampl__ else: # The mutation has a sign : if sign < 0.5, mutation can only decrease the gene's value. Else increase it. if mutsign < 0.5: return object - random.random() * self.__mutampl__ else: return object + random.random() * self.__mutampl__ elif isinstance(object, Mutable): return object.checkmutate() elif objtype is types.DictType: mutated = None for gene, value in object.items(): newvalue = self.checkmutate_object(value, gene) if not newvalue is value: if mutated is None: mutated = object.copy() mutated[gene] = newvalue return mutated or object elif objtype is types.ListType: #mutated = object[:] #for i in range(len(mutated)): mutated[i] = self.checkmutate_object(mutated[i]) #return mutated return map(self.checkmutate_object, object) else: # Non mutable => do not mutate ! return object def __repr__(self): repr = "" genes = self.__dict__.items() genes.sort() for gene, value in genes: if value != 0.0 or not gene.startswith("__"): repr = repr + " %s\t : %s\n" % (gene, value) return repr.expandtabs(32) def multiply(organismA, organismB): return organismA.__class__(map(None, organismA.givetochild(), organismB.givetochild())) # Tools functions : EmptyListError = "EmptyListError" def combinations(*lists): """combinations([x1, x2,...], [y1, y2, ...], ...) -> [[x1, y1], [x1, y2], ..., [x2, y1], [x2, y2], ...] -- Get all the possible combinations, from the given lists of args.""" if not lists[0]: raise EmptyListError if len(lists) == 1: return zip(lists[0]) r = [] subcombinations = combinations(*lists[1:]) for first in lists[0]: r.extend([[first] + list(combination) for combination in subcombinations]) return r def mean(*floats): return reduce(operator.add, floats) / len(floats) genetic-0.1.1b.orig/prog.py0000755002342000000500000001176110037072553015311 0ustar ducksrc00000000000000# Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. """genetic.prog -- module for genetic programming """ import operator, random, UserList, copy from genetic import organism class LispList(UserList.UserList): """LispList implements a callable list, similar to Lisp one ! E.g.: LispList([func, a, b])() is the same that func(a, b). """ def __call__(self, **args): def _subcall(object): if isinstance(object, LispList) or isinstance(object, Argument): return object(**args) return object l = map(_subcall, self) return l[0](*l[1:]) def __repr__(self): if self[0] is operator.add: return "[%s]" % " + ".join(map(repr, self.data[1:])) if self[0] is operator.sub: return "[%s]" % " - ".join(map(repr, self.data[1:])) if self[0] is operator.mul: return "[%s]" % " * ".join(map(repr, self.data[1:])) if self[0] is operator.div: return "[%s]" % " / ".join(map(repr, self.data[1:])) return "%s%s" % (self[0].func_name, tuple(self[1:])) class Argument: def __init__(self, name): self.name = name def __copy__ (self ): return self # Non changeable => useless to copy def __deepcopy__(self, dict): return self def __call__ (self, **args): return args[self.name] def __repr__(self): return self.name class EquationContext: def __init__(self, **args): self.args = [] for name, value in args.items(): arg = Argument(name) self.args.append(arg) context = self # for access in inner class. class EquationChromosom(LispList, organism.Chromosom): DEFAULT_GENES = { "__change__" : 0.5 , "__mutation__" : 0.6 , "__mutampl__" :100.0 , "__mutsign__" : 0.0 , } def __init__(self, **args): LispList.__init__(self) organism.Chromosom.__init__(self, **args) if len(self.data) == 0: eq_parts = [] self.args = [] for arg in context.args: # eq_parts = [ [* constant0 arg0], [* constant1 arg1], ...] eq_parts.append(EquationChromosom(data = [operator.mul, random.random() - 0.5, arg])) # equation = [+ [* constant0 arg0], [+ [* constant1 arg1], ...]] # NB: we cannot do [+ a, b, c, d ...]; operator.add accepts only 2 arguments. eq = reduce(lambda eq, eq_part: EquationChromosom(data = [operator.add, eq_part, eq]), eq_parts) self.data = [operator.add, eq, (random.random() - 0.5) * self.__mutampl__] def useless(self): return 0 def crossover(self, other): pass def checkmutate(self): self.__mutation__ = .5 #self.__mutampl__ = 50.0 self.__change__ = .2 newdict = self.checkmutate_object(self.__dict__) if not newdict is self.__dict__: mutated = self.__class__(**newdict) else: mutated = self #mutated = organism.Chromosom.checkmutate(self) #for i in range(1, len(self.data)): # if random.random() < self.__change__: # if mutated is self: mutated = self.__class__(self.__dict__) # mutated.data[i] = mutated.new_equation_member() for i in range(1, len(self.data)): if random.random() < self.__change__: if mutated is self: mutated = self.__class__(self.__dict__) h = random.random() if h < .6: mutated.data[i] = self.new_equation_member() elif h < .7: mutated.data[i] = EquationChromosom(data = [operator.add, mutated.data[i], self.new_equation_member()]) elif h < .8: mutated.data[i] = EquationChromosom(data = [operator.sub, mutated.data[i], self.new_equation_member()]) elif h < .9: mutated.data[i] = EquationChromosom(data = [operator.mul, mutated.data[i], self.new_equation_member()]) else: mutated.data[i] = EquationChromosom(data = [operator.div, mutated.data[i], self.new_equation_member()]) return mutated def new_equation_member(self): h = random.random() if h < 0.3 : return (random.random() - 0.5) * self.__mutampl__ if h < 0.35: return EquationChromosom(data = [operator.add, self.new_equation_member(), self.new_equation_member()]) if h < 0.4 : return EquationChromosom(data = [operator.sub, self.new_equation_member(), self.new_equation_member()]) if h < 0.45: return EquationChromosom(data = [operator.mul, self.new_equation_member(), self.new_equation_member()]) if h < 0.5 : return EquationChromosom(data = [operator.div, self.new_equation_member(), self.new_equation_member()]) #return random.choice(context.args) return EquationChromosom(data = [operator.mul, (random.random() - 0.5), random.choice(context.args)]) def __repr__(self): return LispList.__repr__(self) self.Chromosom = self.__call__ = EquationChromosom genetic-0.1.1b.orig/setup.py0000755002342000000500000000145110037072554015476 0ustar ducksrc00000000000000#! /usr/bin/env python # Genetic # Copyright (C) 2001 Jean-Baptiste LAMY # # This program is free software. See README or LICENSE for the license terms. import os.path, sys, distutils.core if sys.argv[-1] == "sdist": sys.argv.extend(["-f", "--dist-dir", os.path.expanduser("~/python/dist")]) distutils.core.setup(name = "Genetic", version = "0.1.1", license = "GPL", description = "Genetic algorythms in Python", author = "Jiba (LAMY Jean-Baptiste)", author_email = "jiba@tuxfamily.org", url = "", package_dir = {"genetic" : ""}, packages = ["genetic", "genetic.demo"], )