[pyevolve] 01/81: Imported Upstream version 0.6~rc1~svn397
Christian Kastner
chrisk-guest at moszumanska.debian.org
Sun Aug 17 21:12:38 UTC 2014
This is an automated email from the git hooks/post-receive script.
chrisk-guest pushed a commit to branch master
in repository pyevolve.
commit cf4d95bb24d12020106d5f66662a325090507e1a
Author: Christian Kastner <debian at kvr.at>
Date: Tue May 25 21:49:20 2010 +0200
Imported Upstream version 0.6~rc1~svn397
---
build_dist.bat | 9 +
build_dist.sh | 8 +
docs/build_docs.bat | 9 +
docs/build_docs.sh | 2 +
docs/build_docs_inc.bat | 2 +
docs/build_docs_inc.sh | 2 +
docs/epydoc.conf | 26 +
docs/pyevolve-graph.1 | 138 ++++
docs/source/.static/bottom.png | Bin 0 -> 6012 bytes
docs/source/.static/brasil_flag.jpg | Bin 0 -> 657 bytes
docs/source/.static/default_patch.css | 707 +++++++++++++++++
docs/source/.static/delicious_icon.png | Bin 0 -> 4122 bytes
docs/source/.static/digg_icon.png | Bin 0 -> 5760 bytes
docs/source/.static/feed_icon.png | Bin 0 -> 1989 bytes
docs/source/.static/fg.menu.css | 114 +++
docs/source/.static/fg.menu.js | 645 +++++++++++++++
docs/source/.static/hover.png | Bin 0 -> 2838 bytes
docs/source/.static/index_slide_1.jpg | Bin 0 -> 40717 bytes
docs/source/.static/index_slide_2.jpg | Bin 0 -> 33249 bytes
docs/source/.static/index_slide_3.jpg | Bin 0 -> 34830 bytes
docs/source/.static/index_slide_4.jpg | Bin 0 -> 38070 bytes
docs/source/.static/jquery.betterTooltip.js | 88 +++
docs/source/.static/jquery.js | 154 ++++
docs/source/.static/jquery.nivo.slider.pack.js | 13 +
docs/source/.static/nivo-slider.css | 137 ++++
docs/source/.static/nivo_images/arrows.png | Bin 0 -> 475 bytes
docs/source/.static/nivo_images/bullets.png | Bin 0 -> 509 bytes
docs/source/.static/nivo_images/loading.gif | Bin 0 -> 1737 bytes
docs/source/.static/pyevolve.css | 663 ++++++++++++++++
docs/source/.static/reddit_icon.png | Bin 0 -> 6136 bytes
.../ui-bg_diagonals-small_100_f0efea_40x40.png | Bin 0 -> 157 bytes
.../theme/images/ui-bg_flat_35_f0f0f0_40x100.png | Bin 0 -> 180 bytes
.../theme/images/ui-bg_glass_55_fcf0ba_1x400.png | Bin 0 -> 127 bytes
.../images/ui-bg_glow-ball_25_2e2e28_600x600.png | Bin 0 -> 49306 bytes
.../ui-bg_highlight-soft_100_f0efea_1x100.png | Bin 0 -> 114 bytes
.../ui-bg_highlight-soft_25_327E04_1x100.png | Bin 0 -> 121 bytes
.../ui-bg_highlight-soft_25_5A9D1A_1x100.png | Bin 0 -> 123 bytes
.../ui-bg_highlight-soft_95_ffedad_1x100.png | Bin 0 -> 130 bytes
.../images/ui-bg_inset-soft_22_3b3b35_1x100.png | Bin 0 -> 161 bytes
.../theme/images/ui-icons_808080_256x240.png | Bin 0 -> 4379 bytes
.../theme/images/ui-icons_8DC262_256x240.png | Bin 0 -> 4379 bytes
.../theme/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4379 bytes
.../theme/images/ui-icons_e7e6e4_256x240.png | Bin 0 -> 5399 bytes
.../theme/images/ui-icons_eeeeee_256x240.png | Bin 0 -> 4379 bytes
.../theme/images/ui-icons_ffffff_256x240.png | Bin 0 -> 4379 bytes
docs/source/.static/theme/ui.accordion.css | 9 +
docs/source/.static/theme/ui.all.css | 2 +
docs/source/.static/theme/ui.base.css | 9 +
docs/source/.static/theme/ui.core.css | 37 +
docs/source/.static/theme/ui.datepicker.css | 62 ++
docs/source/.static/theme/ui.dialog.css | 13 +
docs/source/.static/theme/ui.progressbar.css | 4 +
docs/source/.static/theme/ui.resizable.css | 13 +
docs/source/.static/theme/ui.slider.css | 17 +
docs/source/.static/theme/ui.tabs.css | 9 +
docs/source/.static/theme/ui.theme.css | 245 ++++++
docs/source/.static/tip_images/tipBtm.png | Bin 0 -> 1409 bytes
docs/source/.static/tip_images/tipMid.png | Bin 0 -> 181 bytes
docs/source/.static/tip_images/tipTop.png | Bin 0 -> 897 bytes
docs/source/.templates/layout.html | 129 +++
docs/source/README.TXT | 3 +
docs/source/conf.py | 207 +++++
docs/source/contact.rst | 18 +
docs/source/contributors.rst | 23 +
docs/source/examples.rst | 214 +++++
docs/source/ext/pyevolve_tooltip.py | 20 +
docs/source/faq.rst | 15 +
docs/source/getstarted.rst | 852 ++++++++++++++++++++
docs/source/graphs.rst | 329 ++++++++
docs/source/imgs/Thumbs.db | Bin 0 -> 49664 bytes
docs/source/imgs/brasil_flag.jpg | Bin 0 -> 657 bytes
docs/source/imgs/email_amit.png | Bin 0 -> 5485 bytes
docs/source/imgs/email_boris.png | Bin 0 -> 5330 bytes
docs/source/imgs/email_christian_kastner.png | Bin 0 -> 5148 bytes
docs/source/imgs/email_henrik.png | Bin 0 -> 5796 bytes
docs/source/imgs/email_jelle.png | Bin 0 -> 5568 bytes
docs/source/imgs/ex1equation.png | Bin 0 -> 6032 bytes
docs/source/imgs/ex_12_tsp_result.png | Bin 0 -> 35565 bytes
docs/source/imgs/gp_trees_img1.jpg | Bin 0 -> 174660 bytes
docs/source/imgs/graph_1_ex1.png | Bin 0 -> 56600 bytes
docs/source/imgs/graph_2_ex1.png | Bin 0 -> 52640 bytes
docs/source/imgs/graph_3_ex1.png | Bin 0 -> 62146 bytes
docs/source/imgs/graph_4_ex1.png | Bin 0 -> 61894 bytes
docs/source/imgs/graph_5_ex1.png | Bin 0 -> 57059 bytes
docs/source/imgs/graph_6_ex1.png | Bin 0 -> 64854 bytes
docs/source/imgs/graph_7_ex1.png | Bin 0 -> 75374 bytes
docs/source/imgs/graph_8_ex1.png | Bin 0 -> 103359 bytes
docs/source/imgs/graph_8_ex1_spec.png | Bin 0 -> 101558 bytes
docs/source/imgs/graph_9_ex1.png | Bin 0 -> 99418 bytes
docs/source/imgs/graph_9_ex1_hot.png | Bin 0 -> 81091 bytes
docs/source/imgs/iteract_histogram.png | Bin 0 -> 44519 bytes
docs/source/imgs/iteract_plotraw.png | Bin 0 -> 37012 bytes
docs/source/imgs/logo.png | Bin 0 -> 12655 bytes
docs/source/imgs/original/Thumbs.db | Bin 0 -> 45568 bytes
docs/source/imgs/original/graph_1_ex1.png | Bin 0 -> 46627 bytes
docs/source/imgs/original/graph_2_ex1.png | Bin 0 -> 47400 bytes
docs/source/imgs/original/graph_3_ex1.png | Bin 0 -> 72561 bytes
docs/source/imgs/original/graph_4_ex1.png | Bin 0 -> 76405 bytes
docs/source/imgs/original/graph_5_ex1.png | Bin 0 -> 74433 bytes
docs/source/imgs/original/graph_6_ex1.png | Bin 0 -> 65380 bytes
docs/source/imgs/original/graph_7_ex1.png | Bin 0 -> 90484 bytes
docs/source/imgs/original/graph_8_ex1.png | Bin 0 -> 108483 bytes
docs/source/imgs/original/graph_8_ex1_spec.png | Bin 0 -> 113893 bytes
docs/source/imgs/original/graph_9_ex1.png | Bin 0 -> 91641 bytes
docs/source/imgs/original/graph_9_ex1_hot.png | Bin 0 -> 77950 bytes
docs/source/imgs/original/iteract_histogram.png | Bin 0 -> 29480 bytes
docs/source/imgs/original/iteract_plotraw.png | Bin 0 -> 25456 bytes
docs/source/imgs/pyevolve_logo_new.png | Bin 0 -> 7957 bytes
docs/source/index.rst | 71 ++
docs/source/intro.rst | 506 ++++++++++++
docs/source/license.rst | 63 ++
docs/source/module_allele.rst | 6 +
docs/source/module_const.rst | 4 +
docs/source/module_crossovers.rst | 4 +
docs/source/module_dbadapters.rst | 4 +
docs/source/module_functionslot.rst | 4 +
docs/source/module_g1dbinarystring.rst | 6 +
docs/source/module_g1dlist.rst | 6 +
docs/source/module_g2dbinarystring.rst | 6 +
docs/source/module_g2dlist.rst | 6 +
docs/source/module_genomebase.rst | 5 +
docs/source/module_gpopulation.rst | 6 +
docs/source/module_gsimplega.rst | 4 +
docs/source/module_gtree.rst | 6 +
docs/source/module_initializators.rst | 4 +
docs/source/module_interaction.rst | 4 +
docs/source/module_migration.rst | 6 +
docs/source/module_mutators.rst | 4 +
docs/source/module_network.rst | 4 +
docs/source/module_pyevolve.rst | 54 ++
docs/source/module_scaling.rst | 6 +
docs/source/module_selectors.rst | 6 +
docs/source/module_statistics.rst | 4 +
docs/source/module_util.rst | 4 +
docs/source/modules.rst | 14 +
docs/source/sitemap.xml | 184 +++++
docs/source/sphinx06_code_patch.py | 150 ++++
docs/source/whatsnew.rst | 186 +++++
examples/LICENSE.TXT | 46 ++
examples/pyevolve_ex10_g1dbinstr.py | 40 +
examples/pyevolve_ex11_allele.py | 72 ++
examples/pyevolve_ex12_tsp.py | 130 +++
examples/pyevolve_ex13_sphere.py | 30 +
examples/pyevolve_ex14_ackley.py | 54 ++
examples/pyevolve_ex15_rosenbrock.py | 52 ++
examples/pyevolve_ex16_g2dbinstr.py | 37 +
examples/pyevolve_ex17_gtree.py | 44 ++
examples/pyevolve_ex18_gp.py | 47 ++
examples/pyevolve_ex19_gp.py | 94 +++
examples/pyevolve_ex1_simple.py | 54 ++
examples/pyevolve_ex20_gp_dotwrite.py | 56 ++
examples/pyevolve_ex21_nqueens.py | 58 ++
examples/pyevolve_ex22_monkey.py | 54 ++
examples/pyevolve_ex2_realgauss.py | 42 +
examples/pyevolve_ex3_schaffer.py | 46 ++
examples/pyevolve_ex4_sigmatrunc.py | 49 ++
examples/pyevolve_ex5_callback.py | 45 ++
examples/pyevolve_ex6_dbadapter.py | 47 ++
examples/pyevolve_ex7_rastrigin.py | 40 +
examples/pyevolve_ex8_gauss_int.py | 44 ++
examples/pyevolve_ex9_g2dlist.py | 43 +
pyevolve/Consts.py | 531 +++++++++++++
pyevolve/Crossovers.py | 784 +++++++++++++++++++
pyevolve/DBAdapters.py | 792 +++++++++++++++++++
pyevolve/FunctionSlot.py | 205 +++++
pyevolve/G1DBinaryString.py | 203 +++++
pyevolve/G1DList.py | 199 +++++
pyevolve/G2DBinaryString.py | 230 ++++++
pyevolve/G2DList.py | 259 ++++++
pyevolve/GAllele.py | 279 +++++++
pyevolve/GPopulation.py | 467 +++++++++++
pyevolve/GSimpleGA.py | 848 ++++++++++++++++++++
pyevolve/GTree.py | 741 ++++++++++++++++++
pyevolve/GenomeBase.py | 633 +++++++++++++++
pyevolve/Initializators.py | 267 +++++++
pyevolve/Interaction.py | 85 ++
pyevolve/LICENSE.TXT | 46 ++
pyevolve/Migration.py | 268 +++++++
pyevolve/Mutators.py | 871 +++++++++++++++++++++
pyevolve/Network.py | 446 +++++++++++
pyevolve/Scaling.py | 131 ++++
pyevolve/Selectors.py | 177 +++++
pyevolve/Statistics.py | 102 +++
pyevolve/Util.py | 332 ++++++++
pyevolve/__init__.py | 44 ++
pyevolve/clean_pyc.bat | 5 +
pyevolve/clean_pyc.sh | 3 +
pyevolve_graph.py | 610 +++++++++++++++
pylintrc.conf | 309 ++++++++
run_pylint.bat | 2 +
setup.py | 18 +
191 files changed, 17395 insertions(+)
diff --git a/build_dist.bat b/build_dist.bat
new file mode 100644
index 0000000..f969270
--- /dev/null
+++ b/build_dist.bat
@@ -0,0 +1,9 @@
+ at echo off
+python setup.py build
+
+python setup.py bdist_wininst --target-version="2.5"
+python setup.py bdist_wininst --target-version="2.6"
+python setup.py sdist --formats=gztar,zip
+python setup.py bdist --formats=egg
+
+
diff --git a/build_dist.sh b/build_dist.sh
new file mode 100644
index 0000000..256cc4e
--- /dev/null
+++ b/build_dist.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+python setup.py build
+python setup.py bdist_wininst --target-version="2.5"
+python setup.py bdist_wininst --target-version="2.6"
+python setup.py sdist
+python setup.py bdist
+python setup.py bdist_egg
+
diff --git a/docs/build_docs.bat b/docs/build_docs.bat
new file mode 100644
index 0000000..da01023
--- /dev/null
+++ b/docs/build_docs.bat
@@ -0,0 +1,9 @@
+ at echo off
+
+rd /s/q build_htmlhelp
+rd /s/q build_web
+rd /s/q build_latex
+
+c:\python26\scripts\sphinx-build -E -a -b htmlhelp .\source .\build_htmlhelp
+c:\python26\scripts\sphinx-build -E -a -b html .\source .\build_web
+c:\python26\scripts\sphinx-build -E -a -b latex .\source .\build_latex
\ No newline at end of file
diff --git a/docs/build_docs.sh b/docs/build_docs.sh
new file mode 100644
index 0000000..a8a1490
--- /dev/null
+++ b/docs/build_docs.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+sphinx-build -E -a -b html ./source ./build
diff --git a/docs/build_docs_inc.bat b/docs/build_docs_inc.bat
new file mode 100644
index 0000000..9a56da4
--- /dev/null
+++ b/docs/build_docs_inc.bat
@@ -0,0 +1,2 @@
+ at echo off
+c:\python26\scripts\sphinx-build -b html .\source .\build
diff --git a/docs/build_docs_inc.sh b/docs/build_docs_inc.sh
new file mode 100644
index 0000000..4ddb6c6
--- /dev/null
+++ b/docs/build_docs_inc.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+sphinx-build -b html ./source ./build
diff --git a/docs/epydoc.conf b/docs/epydoc.conf
new file mode 100644
index 0000000..4f82155
--- /dev/null
+++ b/docs/epydoc.conf
@@ -0,0 +1,26 @@
+[epydoc]
+
+modules: ../pyevolve/
+
+output: pdf
+target: epydocs/
+
+verbosity: 1
+
+introspect: yes
+
+private: yes
+imports: yes
+
+sourcecode: yes
+
+name: Pyevolve 0.6
+
+# The documented project's URL.
+url: http://pyevolve.sourceforge.net/
+
+graph: all
+#dotpath: /usr/local/bin/dot
+
+graph-font: Helvetica
+
diff --git a/docs/pyevolve-graph.1 b/docs/pyevolve-graph.1
new file mode 100644
index 0000000..c763b62
--- /dev/null
+++ b/docs/pyevolve-graph.1
@@ -0,0 +1,138 @@
+.TH PYEVOLVE-GRAPH 1 "2010-05-10" "pyevolve_graph" PYEVOLVE-GRAPH
+.SH NAME
+pyevolve-graph \- graphical plotting tool for Pyevolve
+.SH SYNOPSIS
+.B pyevolve-graph
+.RI [ options ]
+.br
+.SH DESCRIPTION
+This manual page documents briefly the
+.B pyevolve-graph
+command, a graphical plotting tool for programs based on Pyevolve. To use this
+program, you must have \fBpython-matplotlib\fP and \fBpython-sqlite\fP
+installed.
+.SH GENERAL OPTIONS
+\fBPyevolve-pygraph\fP supports the following options:
+.TP
+.B \-h, \-\-help
+show a brief summary of available options and exit
+.TP
+.BI \-f " FILENAME\fP, " \-\-file= FILENAME
+Database file to read from. default is \fI./pyevolve.db\fP.
+.TP
+.BI \-i " IDENTIFY\fP, " \-\-identify= IDENTIFY
+The identify of evolution.
+.TP
+.BI \-o " OUTFILE\fP, " \-\-outfile= OUTFILE
+Write the graph image to a file. Don't specify an extension, just the filename.
+The file will be written in PND format by default, but this can be changed
+using the \fB\-\-extension\fP or \fB\-e\fP options.
+.TP
+.BI \-e " EXTENSION\fP, " \-\-extension= EXTENSION
+Graph image file format. Supported options (formats) are all those supported by
+\fBpython-matplotlib\fP. Currently, these should be: EMF, EPS, PDF, PNG, PS,
+RAW, RGBA, SVG, SVGZ. Default is PNG.
+.TP
+.BI \-g " GENRANGE\fP, " \-\-genrange= GENRANGE
+This is the generation range of the graph. For example, 1:30 would denote
+an interval between 1 and 30.
+.TP
+.BI \-c " COLORMAP\fP, " \-\-colormap= COLORMAP
+Sets the Color Map for the graph types \fB\-8\fP and \fB\-9\fP. Some options
+are: summer, bone, gray, hot, jet, cooper, spectral. The default is \fBjet\fP.
+.TP
+.BI \-m, \-\-minimize
+Sets the 'Minimize' mode. Default is the Maximize mode. This option makes sense
+if you are minimizing your evaluation function.
+.TP
+.B \-0
+Write all standard graphs to file. Equivalent to specifying \fB\-1\fP \fB\-2\fP
+\fB\-3\fP \fB\-4\fP \fB-5\fP.
+.TP
+.B \-1
+Error bars graph (raw scores).
+.TP
+.B \-2
+Error bars graph (fitness scores).
+.TP
+.B \-3
+Max/min/avg/std. dev. graph (raw scores).
+.TP
+.B \-4
+Max/min/avg graph (fitness scores).
+.TP
+.B \-5
+Raw and Fitness min/max difference graph.
+.TP
+.B \-6
+Compare best raw score of two or more evolutions. You must specify the identify
+as a comma-separated list with the \fB\-\-identify\fP or \fB\-i\fP options.
+The maximum is 6 items.
+.TP
+.B \-7
+Compare best fitness score of two or more evolutions. You must specify the
+identify as a comma-separated list with the \fB\-\-identify\fP or \fB\-i\fP
+options. The maximum is 6 items.
+.TP
+.B \-8
+Show a heat map of population raw score distribution between generations.
+.TP
+.B \-9
+Show a heat map of population fitness score distribution between generations.
+.SH EXAMPLES
+The following are some examples on how to use \fBpyevolve-graph\fP:
+.PP
+1. Output a graph for identify 'ex1' in PNG format (default) to
+file 'graph_ex1.png':
+.sp
+.RS 12
+.nf
+pyevolve-graph \-i ex1 \-1 \-o graph_ex1
+.fi
+.RE
+.sp
+2. Output a graph for identify 'ex1' to the PDF file 'graph_ex1.pdf':
+.sp
+.RS 12
+.nf
+pyevolve-graph \-i ex1 \-1 \-o graph_ex1 \-e pdf
+.fi
+.RE
+.sp
+3. This command will plot the evolution of the generations between 10 and 20:
+.sp
+.RS 12
+.nf
+pyevolve-graph \-i ex1 \-1 \-g 10:20
+.fi
+.RE
+.sp
+4. Use \fB\-m\fP to indicate that you have minimized the evaulation fuction:
+.sp
+.RS 12
+.nf
+pyevolve_graph.py \-i ex1 \-1 \-m
+.fi
+.RE
+.sp
+5. Specify an identify list for the comparison output options \fB\-6\fP and
+\fB\-7\fP:
+.sp
+.RS 12
+.nf
+pyevolve_graph.py \-i ex1_run1,ex1_run2,ex1_run3 \-6
+.fi
+.RE
+.sp
+Fore more examples on how to use pyevolve-graph, including sample images, users
+are recommended to install the \fBpython-pyevolve-doc\fP package.
+.SH SEE ALSO
+.TP
+.I /usr/share/doc/python-pyevolve/examples
+Contains many examples.
+.br
+.SH AUTHOR
+pyevolve-graph was written by Christian S. Perone <christian.perone at gmail.com>.
+.PP
+This manual page was written by Christian Kastner <debian at kvr.at>
+for the Debian project (and may be used by others).
diff --git a/docs/source/.static/bottom.png b/docs/source/.static/bottom.png
new file mode 100644
index 0000000..8706027
Binary files /dev/null and b/docs/source/.static/bottom.png differ
diff --git a/docs/source/.static/brasil_flag.jpg b/docs/source/.static/brasil_flag.jpg
new file mode 100644
index 0000000..d3d01b6
Binary files /dev/null and b/docs/source/.static/brasil_flag.jpg differ
diff --git a/docs/source/.static/default_patch.css b/docs/source/.static/default_patch.css
new file mode 100644
index 0000000..c199470
--- /dev/null
+++ b/docs/source/.static/default_patch.css
@@ -0,0 +1,707 @@
+/**
+ * Sphinx Doc Design
+ */
+
+body {
+ font-family: sans-serif;
+ font-size: 100%;
+ background-color: #11303D;
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+.ttip {
+ border-bottom: 1px dotted #BBBBBB;
+ color: #A64E15;
+ font-style: italic;
+ cursor: help;
+}
+
+.tip {
+ font-size: 75%;
+ width: 212px;
+ padding-top: 30px;
+ display: none;
+ position: absolute;
+ background: transparent url(tip_images/tipTop.png) no-repeat top;
+}
+
+.tipMid {background: transparent url(tip_images/tipMid.png) repeat-y; padding: 0 25px 20px 25px;}
+.tipBtm {background: transparent url(tip_images/tipBtm.png) no-repeat bottom; height: 32px;}
+
+/* :::: LAYOUT :::: */
+
+#contents { width:750px; font-family:Georgia, Times, serif; /* font-size:15px; */}
+#contents ul { /*list-style: none; */}
+#contents ul li { }
+#contents ul li a { display:block; text-decoration:none; line-height:30px;
+ border-bottom-style:solid; border-bottom-width:1px; border-bottom-color:#CCCCCC; padding-left:5px; cursor:pointer; }
+#contents ul li a:hover { color:#FFFFFF; background-image:url(hover.png); background-repeat:repeat-x; }
+#contents ul li a strong { margin-right:5px; }
+
+#extraDiv2 {
+ background-image: url(bottom.png);
+ background-repeat: no-repeat;
+ background-position: right;
+ height: 60px;
+ width: 100%;
+ position: fixed;
+ bottom: 0px;
+ z-index: 5;
+}
+
+div.document {
+ background-color: #005C8A; /*#155146;*/
+}
+
+.inheritance {
+ border-style: hidden;
+}
+
+.graphviz {
+ border-style: hidden;
+ text-align: center;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.body {
+ background-color: white;
+ padding: 0 20px 30px 20px;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.clearer {
+ clear: both;
+}
+
+div.footer {
+ color: #fff;
+ background-color: #363636;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #fff;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #000000 /*#133f52*/;
+ color: #fff;
+ width: 100%;
+ line-height: 30px;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related a {
+ color: white;
+}
+
+/* ::: TOC :::: */
+div.sphinxsidebar h3 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: white;
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: white;
+}
+
+div.sphinxsidebar h4 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: white;
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: white;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ list-style: none;
+ color: white;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar a {
+ color: #98dbcc;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+/* :::: MODULE CLOUD :::: */
+div.modulecloud {
+ margin: -5px 10px 5px 10px;
+ padding: 10px;
+ line-height: 160%;
+ border: 1px solid #cbe7e5;
+ background-color: #f2fbfd;
+}
+
+div.modulecloud a {
+ padding: 0 5px 0 5px;
+}
+
+/* :::: SEARCH :::: */
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* :::: COMMON FORM STYLES :::: */
+
+div.actions {
+ padding: 5px 10px 5px 10px;
+ border-top: 1px solid #cbe7e5;
+ border-bottom: 1px solid #cbe7e5;
+ background-color: #e0f6f4;
+}
+
+form dl {
+ color: #333;
+}
+
+form dt {
+ clear: both;
+ float: left;
+ min-width: 110px;
+ margin-right: 10px;
+ padding-top: 2px;
+}
+
+input#homepage {
+ display: none;
+}
+
+div.error {
+ margin: 5px 20px 0 0;
+ padding: 5px;
+ border: 1px solid #d00;
+ font-weight: bold;
+}
+
+/* :::: INDEX PAGE :::: */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* :::: INDEX STYLES :::: */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+form.pfform {
+ margin: 10px 0 20px 0;
+}
+
+/* :::: GLOBAL STYLES :::: */
+
+.docwarning {
+ background-color: #ffe4e4;
+ padding: 10px;
+ margin: 0 -20px 0 -20px;
+ border-bottom: 1px solid #f66;
+}
+
+p.subhead {
+ font-weight: bold;
+ margin-top: 20px;
+}
+
+a {
+ color: #355f7c;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: 'Trebuchet MS', sans-serif;
+ background-color: #f2f2f2;
+ font-weight: normal;
+ color: #20435c;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+ul.fakelist {
+ list-style: none;
+ margin: 10px 0 10px 20px;
+ padding: 0;
+}
+
+.field-list ul {
+ padding-left: 1em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+/* "Footnotes" heading */
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+/* Sidebars */
+
+div.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+/* "Topics" */
+
+div.topic {
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* Admonitions */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+table.docutils {
+ border: 0;
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 0;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+dl {
+ margin-bottom: 15px;
+ clear: both;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+.refcount {
+ color: #060;
+}
+
+dt:target,
+.highlight {
+ background-color: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+pre {
+ padding: 5px;
+ background-color: #efc;
+ color: #333;
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+ overflow: auto;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.footnote:target { background-color: #ffa }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+form.comment {
+ margin: 0;
+ padding: 10px 30px 10px 30px;
+ background-color: #eee;
+}
+
+form.comment h3 {
+ background-color: #326591;
+ color: white;
+ margin: -10px -30px 10px -30px;
+ padding: 5px;
+ font-size: 1.4em;
+}
+
+form.comment input,
+form.comment textarea {
+ border: 1px solid #ccc;
+ padding: 2px;
+ font-family: sans-serif;
+ font-size: 100%;
+}
+
+form.comment input[type="text"] {
+ width: 240px;
+}
+
+form.comment textarea {
+ width: 100%;
+ height: 200px;
+ margin-bottom: 10px;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+img.math {
+ vertical-align: middle;
+}
+
+div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+img.logo {
+ border: 0;
+}
+
+
+/* :::: PRINT :::: */
+ at media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0;
+ width : 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ div#comments div.new-comment-box,
+ #top-link {
+ display: none;
+ }
+}
diff --git a/docs/source/.static/delicious_icon.png b/docs/source/.static/delicious_icon.png
new file mode 100644
index 0000000..ae8d011
Binary files /dev/null and b/docs/source/.static/delicious_icon.png differ
diff --git a/docs/source/.static/digg_icon.png b/docs/source/.static/digg_icon.png
new file mode 100644
index 0000000..046a269
Binary files /dev/null and b/docs/source/.static/digg_icon.png differ
diff --git a/docs/source/.static/feed_icon.png b/docs/source/.static/feed_icon.png
new file mode 100644
index 0000000..d636414
Binary files /dev/null and b/docs/source/.static/feed_icon.png differ
diff --git a/docs/source/.static/fg.menu.css b/docs/source/.static/fg.menu.css
new file mode 100644
index 0000000..820db38
--- /dev/null
+++ b/docs/source/.static/fg.menu.css
@@ -0,0 +1,114 @@
+/* Styles for jQuery menu widget
+Author: Maggie Wachs, maggie at filamentgroup.com
+Date: September 2008
+*/
+
+
+/* REQUIRED STYLES - the menus will only render correctly with these rules */
+
+.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em; overflow: hidden; }
+.fg-menu-container.fg-menu-flyout { overflow: visible; }
+
+.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
+
+.fg-menu { position:relative; }
+.fg-menu-flyout .fg-menu { position:static; }
+
+.fg-menu ul { position:absolute; top:0; }
+.fg-menu ul ul { top:-1px; }
+
+.fg-menu-container.fg-menu-ipod .fg-menu-content,
+.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
+
+.fg-menu.fg-menu-scroll,
+.fg-menu ul.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
+
+.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }
+.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
+
+.fg-menu-flyout ul ul { padding: .4em; }
+.fg-menu-flyout li { position:relative; }
+
+.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
+
+.fg-menu-breadcrumb { margin: 0; padding: 0; }
+
+.fg-menu-footer { margin-top: .4em; padding: .4em; }
+.fg-menu-header { margin-bottom: .4em; padding: .4em; }
+
+.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
+.fg-menu-breadcrumb li.fg-menu-prev-list,
+.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
+.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
+
+.fg-menu-breadcrumb a,
+.fg-menu-breadcrumb span { float: left; }
+
+.fg-menu-footer a:link,
+.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
+.fg-menu-footer a:hover,
+.fg-menu-footer a:active { }
+
+.fg-menu-footer a span { float:left; cursor: pointer; }
+
+.fg-menu-breadcrumb .fg-menu-prev-list a:link,
+.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
+.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
+.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
+
+.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
+.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
+
+.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
+.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
+.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
+.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
+
+
+
+/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into
+ selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right */
+
+.fg-menu a:link,
+.fg-menu a:visited,
+.fg-menu a:hover,
+.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
+
+.fg-menu a { border: 1px dashed transparent; }
+
+.fg-menu a.ui-state-default:link,
+.fg-menu a.ui-state-default:visited,
+.fg-menu a.ui-state-default:hover,
+.fg-menu a.ui-state-default:active,
+.fg-menu a.ui-state-hover:link,
+.fg-menu a.ui-state-hover:visited,
+.fg-menu a.ui-state-hover:hover,
+.fg-menu a.ui-state-hover:active,
+ .fg-menu a.ui-state-active:link,
+ .fg-menu a.ui-state-active:visited,
+ .fg-menu a.ui-state-active:hover,
+.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
+
+.fg-menu a span { display:block; cursor:pointer; }
+
+
+ /* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */
+
+.fg-menu-indicator span { float:left; }
+.fg-menu-indicator span.ui-icon { float:right; }
+
+.fg-menu-content.ui-widget-content,
+.fg-menu-content ul.ui-widget-content { border:0; }
+
+
+/* ICONS AND DIVIDERS */
+
+.fg-menu.fg-menu-has-icons a:link,
+.fg-menu.fg-menu-has-icons a:visited,
+.fg-menu.fg-menu-has-icons a:hover,
+.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
+
+.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
+.fg-menu .horizontal-divider hr { border:0; height:1px; }
+.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }
+
diff --git a/docs/source/.static/fg.menu.js b/docs/source/.static/fg.menu.js
new file mode 100644
index 0000000..36c32aa
--- /dev/null
+++ b/docs/source/.static/fg.menu.js
@@ -0,0 +1,645 @@
+/*--------------------------------------------------------------------
+Scripts for creating and manipulating custom menus based on standard <ul> markup
+Version: 3.0, 03.31.2009
+
+By: Maggie Costello Wachs (maggie at filamentgroup.com) and Scott Jehl (scott at filamentgroup.com)
+ http://www.filamentgroup.com
+ * reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_menu/
+
+Copyright (c) 2009 Filament Group
+Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
+--------------------------------------------------------------------*/
+
+
+var allUIMenus = [];
+
+$.fn.menu = function(options){
+ var caller = this;
+ var options = options;
+ var m = new Menu(caller, options);
+ allUIMenus.push(m);
+
+ $(this)
+ .mousedown(function(){
+ if (!m.menuOpen) { m.showLoading(); };
+ })
+ .click(function(){
+ if (m.menuOpen == false) { m.showMenu(); }
+ else { m.kill(); };
+ return false;
+ });
+};
+
+function Menu(caller, options){
+ var menu = this;
+ var caller = $(caller);
+ var container = $('<div class="fg-menu-container ui-widget ui-widget-content ui-corner-all">'+options.content+'</div>');
+
+ this.menuOpen = false;
+ this.menuExists = false;
+
+ var options = jQuery.extend({
+ content: null,
+ width: 180, // width of menu container, must be set or passed in to calculate widths of child menus
+ maxHeight: 180, // max height of menu (if a drilldown: height does not include breadcrumb)
+ positionOpts: {
+ posX: 'left',
+ posY: 'bottom',
+ offsetX: 0,
+ offsetY: 0,
+ directionH: 'right',
+ directionV: 'down',
+ detectH: true, // do horizontal collision detection
+ detectV: true, // do vertical collision detection
+ linkToFront: false
+ },
+ showSpeed: 200, // show/hide speed in milliseconds
+ callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the menu is showing
+ loadingState: 'ui-state-loading', // class added to the link/button while the menu is created
+ linkHover: 'ui-state-hover', // class for menu option hover state
+ linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level menus
+ // ----- multi-level menu defaults -----
+ crossSpeed: 200, // cross-fade speed for multi-level menus
+ crumbDefaultText: 'Choose an option:',
+ backLink: true, // in the ipod-style menu: instead of breadcrumbs, show only a 'back' link
+ backLinkText: 'Back',
+ flyOut: false, // multi-level menus are ipod-style by default; this parameter overrides to make a flyout instead
+ flyOutOnState: 'ui-state-default',
+ nextMenuLink: 'ui-icon-triangle-1-e', // class to style the link (specifically, a span within the link) used in the multi-level menu to show the next level
+ topLinkText: 'All',
+ nextCrumbLink: 'ui-icon-carat-1-e'
+ }, options);
+
+ var killAllMenus = function(){
+ $.each(allUIMenus, function(i){
+ if (allUIMenus[i].menuOpen) { allUIMenus[i].kill(); };
+ });
+ };
+
+ this.kill = function(){
+ caller
+ .removeClass(options.loadingState)
+ .removeClass('fg-menu-open')
+ .removeClass(options.callerOnState);
+ container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);
+ if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };
+ if (options.callerOnState) { caller.removeClass(options.callerOnState); };
+ if (container.is('.fg-menu-ipod')) { menu.resetDrilldownMenu(); };
+ if (container.is('.fg-menu-flyout')) { menu.resetFlyoutMenu(); };
+ container.parent().hide();
+ menu.menuOpen = false;
+ $(document).unbind('click', killAllMenus);
+ $(document).unbind('keydown');
+ };
+
+ this.showLoading = function(){
+ caller.addClass(options.loadingState);
+ };
+
+ this.showMenu = function(){
+ killAllMenus();
+ if (!menu.menuExists) { menu.create() };
+ caller
+ .addClass('fg-menu-open')
+ .addClass(options.callerOnState);
+ container.parent().show().click(function(){ menu.kill(); return false; });
+ container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
+ menu.menuOpen = true;
+ caller.removeClass(options.loadingState);
+ $(document).click(killAllMenus);
+
+ // assign key events
+ $(document).keydown(function(event){
+ var e;
+ if (event.which !="") { e = event.which; }
+ else if (event.charCode != "") { e = event.charCode; }
+ else if (event.keyCode != "") { e = event.keyCode; }
+
+ var menuType = ($(event.target).parents('div').is('.fg-menu-flyout')) ? 'flyout' : 'ipod' ;
+
+ switch(e) {
+ case 37: // left arrow
+ if (menuType == 'flyout') {
+ $(event.target).trigger('mouseout');
+ if ($('.'+options.flyOutOnState).size() > 0) { $('.'+options.flyOutOnState).trigger('mouseover'); };
+ };
+
+ if (menuType == 'ipod') {
+ $(event.target).trigger('mouseout');
+ if ($('.fg-menu-footer').find('a').size() > 0) { $('.fg-menu-footer').find('a').trigger('click'); };
+ if ($('.fg-menu-header').find('a').size() > 0) { $('.fg-menu-current-crumb').prev().find('a').trigger('click'); };
+ if ($('.fg-menu-current').prev().is('.fg-menu-indicator')) {
+ $('.fg-menu-current').prev().trigger('mouseover');
+ };
+ };
+ return false;
+ break;
+
+ case 38: // up arrow
+ if ($(event.target).is('.' + options.linkHover)) {
+ var prevLink = $(event.target).parent().prev().find('a:eq(0)');
+ if (prevLink.size() > 0) {
+ $(event.target).trigger('mouseout');
+ prevLink.trigger('mouseover');
+ };
+ }
+ else { container.find('a:eq(0)').trigger('mouseover'); }
+ return false;
+ break;
+
+ case 39: // right arrow
+ if ($(event.target).is('.fg-menu-indicator')) {
+ if (menuType == 'flyout') {
+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
+ }
+ else if (menuType == 'ipod') {
+ $(event.target).trigger('click');
+ setTimeout(function(){
+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
+ }, options.crossSpeed);
+ };
+ };
+ return false;
+ break;
+
+ case 40: // down arrow
+ if ($(event.target).is('.' + options.linkHover)) {
+ var nextLink = $(event.target).parent().next().find('a:eq(0)');
+ if (nextLink.size() > 0) {
+ $(event.target).trigger('mouseout');
+ nextLink.trigger('mouseover');
+ };
+ }
+ else { container.find('a:eq(0)').trigger('mouseover'); }
+ return false;
+ break;
+
+ case 27: // escape
+ killAllMenus();
+ break;
+
+ case 13: // enter
+ if ($(event.target).is('.fg-menu-indicator') && menuType == 'ipod') {
+ $(event.target).trigger('click');
+ setTimeout(function(){
+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
+ }, options.crossSpeed);
+ };
+ break;
+ };
+ });
+ };
+
+ this.create = function(){
+ container.css({ width: options.width }).appendTo('body').find('ul:first').not('.fg-menu-breadcrumb').addClass('fg-menu');
+ container.find('ul, li a').addClass('ui-corner-all');
+
+ // aria roles & attributes
+ container.find('ul').attr('role', 'menu').eq(0).attr('aria-activedescendant','active-menuitem').attr('aria-labelledby', caller.attr('id'));
+ container.find('li').attr('role', 'menuitem');
+ container.find('li:has(ul)').attr('aria-haspopup', 'true').find('ul').attr('aria-expanded', 'false');
+ container.find('a').attr('tabindex', '-1');
+
+ // when there are multiple levels of hierarchy, create flyout or drilldown menu
+ if (container.find('ul').size() > 1) {
+ if (options.flyOut) { menu.flyout(container, options); }
+ else { menu.drilldown(container, options); }
+ }
+ else {
+ container.find('a').click(function(){
+ menu.chooseItem(this);
+ return false;
+ });
+ };
+
+ if (options.linkHover) {
+ var allLinks = container.find('.fg-menu li a');
+ allLinks.hover(
+ function(){
+ var menuitem = $(this);
+ $('.'+options.linkHover).removeClass(options.linkHover).blur().parent().removeAttr('id');
+ $(this).addClass(options.linkHover).focus().parent().attr('id','active-menuitem');
+ },
+ function(){
+ $(this).removeClass(options.linkHover).blur().parent().removeAttr('id');
+ }
+ );
+ };
+
+ if (options.linkHoverSecondary) {
+ container.find('.fg-menu li').hover(
+ function(){
+ $(this).siblings('li').removeClass(options.linkHoverSecondary);
+ if (options.flyOutOnState) { $(this).siblings('li').find('a').removeClass(options.flyOutOnState); }
+ $(this).addClass(options.linkHoverSecondary);
+ },
+ function(){ $(this).removeClass(options.linkHoverSecondary); }
+ );
+ };
+
+ menu.setPosition(container, caller, options);
+ menu.menuExists = true;
+ };
+
+ this.chooseItem = function(item){
+ menu.kill();
+ // edit this for your own custom function/callback:
+ //$('#menuSelection').text($(item).text());
+ location.href = $(item).attr('href');
+ };
+};
+
+Menu.prototype.flyout = function(container, options) {
+ var menu = this;
+
+ this.resetFlyoutMenu = function(){
+ var allLists = container.find('ul ul');
+ allLists.removeClass('ui-widget-content').hide();
+ };
+
+ container.addClass('fg-menu-flyout').find('li:has(ul)').each(function(){
+ var linkWidth = container.width();
+ var showTimer, hideTimer;
+ var allSubLists = $(this).find('ul');
+
+ allSubLists.css({ left: linkWidth, width: linkWidth }).hide();
+
+ $(this).find('a:eq(0)').addClass('fg-menu-indicator').html('<span>' + $(this).find('a:eq(0)').text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>').hover(
+ function(){
+ clearTimeout(hideTimer);
+ var subList = $(this).next();
+ if (!fitVertical(subList, $(this).offset().top)) { subList.css({ top: 'auto', bottom: 0 }); };
+ if (!fitHorizontal(subList, $(this).offset().left + 100)) { subList.css({ left: 'auto', right: linkWidth, 'z-index': 999 }); };
+ showTimer = setTimeout(function(){
+ subList.addClass('ui-widget-content').show(options.showSpeed).attr('aria-expanded', 'true');
+ }, 300);
+ },
+ function(){
+ clearTimeout(showTimer);
+ var subList = $(this).next();
+ hideTimer = setTimeout(function(){
+ subList.removeClass('ui-widget-content').hide(options.showSpeed).attr('aria-expanded', 'false');
+ }, 400);
+ }
+ );
+
+ $(this).find('ul a').hover(
+ function(){
+ clearTimeout(hideTimer);
+ if ($(this).parents('ul').prev().is('a.fg-menu-indicator')) {
+ $(this).parents('ul').prev().addClass(options.flyOutOnState);
+ }
+ },
+ function(){
+ hideTimer = setTimeout(function(){
+ allSubLists.hide(options.showSpeed);
+ container.find(options.flyOutOnState).removeClass(options.flyOutOnState);
+ }, 500);
+ }
+ );
+ });
+
+ container.find('a').click(function(){
+ menu.chooseItem(this);
+ return false;
+ });
+};
+
+
+Menu.prototype.drilldown = function(container, options) {
+ var menu = this;
+ var topList = container.find('.fg-menu');
+ var breadcrumb = $('<ul class="fg-menu-breadcrumb ui-widget-header ui-corner-all ui-helper-clearfix"></ul>');
+ var crumbDefaultHeader = $('<li class="fg-menu-breadcrumb-text">'+options.crumbDefaultText+'</li>');
+ var firstCrumbText = (options.backLink) ? options.backLinkText : options.topLinkText;
+ var firstCrumbClass = (options.backLink) ? 'fg-menu-prev-list' : 'fg-menu-all-lists';
+ var firstCrumbLinkClass = (options.backLink) ? 'ui-state-default ui-corner-all' : '';
+ var firstCrumbIcon = (options.backLink) ? '<span class="ui-icon ui-icon-triangle-1-w"></span>' : '';
+ var firstCrumb = $('<li class="'+firstCrumbClass+'"><a href="#" class="'+firstCrumbLinkClass+'">'+firstCrumbIcon+firstCrumbText+'</a></li>');
+
+ container.addClass('fg-menu-ipod');
+
+ if (options.backLink) { breadcrumb.addClass('fg-menu-footer').appendTo(container).hide(); }
+ else { breadcrumb.addClass('fg-menu-header').prependTo(container); };
+ breadcrumb.append(crumbDefaultHeader);
+
+ var checkMenuHeight = function(el){
+ if (el.height() > options.maxHeight) { el.addClass('fg-menu-scroll') };
+ el.css({ height: options.maxHeight });
+ };
+
+ var resetChildMenu = function(el){ el.removeClass('fg-menu-scroll').removeClass('fg-menu-current').height('auto'); };
+
+ this.resetDrilldownMenu = function(){
+ $('.fg-menu-current').removeClass('fg-menu-current');
+ topList.animate({ left: 0 }, options.crossSpeed, function(){
+ $(this).find('ul').each(function(){
+ $(this).hide();
+ resetChildMenu($(this));
+ });
+ topList.addClass('fg-menu-current');
+ });
+ $('.fg-menu-all-lists').find('span').remove();
+ breadcrumb.empty().append(crumbDefaultHeader);
+ $('.fg-menu-footer').empty().hide();
+ checkMenuHeight(topList);
+ };
+
+ topList
+ .addClass('fg-menu-content fg-menu-current ui-widget-content ui-helper-clearfix')
+ .css({ width: container.width() })
+ .find('ul')
+ .css({ width: container.width(), left: container.width() })
+ .addClass('ui-widget-content')
+ .hide();
+ checkMenuHeight(topList);
+
+ topList.find('a').each(function(){
+ // if the link opens a child menu:
+ if ($(this).next().is('ul')) {
+ $(this)
+ .addClass('fg-menu-indicator')
+ .each(function(){ $(this).html('<span>' + $(this).text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>'); })
+ .click(function(){ // ----- show the next menu
+ var nextList = $(this).next();
+ var parentUl = $(this).parents('ul:eq(0)');
+ var parentLeft = (parentUl.is('.fg-menu-content')) ? 0 : parseFloat(topList.css('left'));
+ var nextLeftVal = Math.round(parentLeft - parseFloat(container.width()));
+ var footer = $('.fg-menu-footer');
+
+ // show next menu
+ resetChildMenu(parentUl);
+ checkMenuHeight(nextList);
+ topList.animate({ left: nextLeftVal }, options.crossSpeed);
+ nextList.show().addClass('fg-menu-current').attr('aria-expanded', 'true');
+
+ var setPrevMenu = function(backlink){
+ var b = backlink;
+ var c = $('.fg-menu-current');
+ var prevList = c.parents('ul:eq(0)');
+ c.hide().attr('aria-expanded', 'false');
+ resetChildMenu(c);
+ checkMenuHeight(prevList);
+ prevList.addClass('fg-menu-current').attr('aria-expanded', 'true');
+ if (prevList.hasClass('fg-menu-content')) { b.remove(); footer.hide(); };
+ };
+
+ // initialize "back" link
+ if (options.backLink) {
+ if (footer.find('a').size() == 0) {
+ footer.show();
+ $('<a href="#"><span class="ui-icon ui-icon-triangle-1-w"></span> <span>Back</span></a>')
+ .appendTo(footer)
+ .click(function(){ // ----- show the previous menu
+ var b = $(this);
+ var prevLeftVal = parseFloat(topList.css('left')) + container.width();
+ topList.animate({ left: prevLeftVal }, options.crossSpeed, function(){
+ setPrevMenu(b);
+ });
+ return false;
+ });
+ }
+ }
+ // or initialize top breadcrumb
+ else {
+ if (breadcrumb.find('li').size() == 1){
+ breadcrumb.empty().append(firstCrumb);
+ firstCrumb.find('a').click(function(){
+ menu.resetDrilldownMenu();
+ return false;
+ });
+ }
+ $('.fg-menu-current-crumb').removeClass('fg-menu-current-crumb');
+ var crumbText = $(this).find('span:eq(0)').text();
+ var newCrumb = $('<li class="fg-menu-current-crumb"><a href="javascript://" class="fg-menu-crumb">'+crumbText+'</a></li>');
+ newCrumb
+ .appendTo(breadcrumb)
+ .find('a').click(function(){
+ if ($(this).parent().is('.fg-menu-current-crumb')){
+ menu.chooseItem(this);
+ }
+ else {
+ var newLeftVal = - ($('.fg-menu-current').parents('ul').size() - 1) * 180;
+ topList.animate({ left: newLeftVal }, options.crossSpeed, function(){
+ setPrevMenu();
+ });
+
+ // make this the current crumb, delete all breadcrumbs after this one, and navigate to the relevant menu
+ $(this).parent().addClass('fg-menu-current-crumb').find('span').remove();
+ $(this).parent().nextAll().remove();
+ };
+ return false;
+ });
+ newCrumb.prev().append(' <span class="ui-icon '+options.nextCrumbLink+'"></span>');
+ };
+ return false;
+ });
+ }
+ // if the link is a leaf node (doesn't open a child menu)
+ else {
+ $(this).click(function(){
+ menu.chooseItem(this);
+ return false;
+ });
+ };
+ });
+};
+
+
+/* Menu.prototype.setPosition parameters (defaults noted with *):
+ referrer = the link (or other element) used to show the overlaid object
+ settings = can override the defaults:
+ - posX/Y: where the top left corner of the object should be positioned in relation to its referrer.
+ X: left*, center, right
+ Y: top, center, bottom*
+ - offsetX/Y: the number of pixels to be offset from the x or y position. Can be a positive or negative number.
+ - directionH/V: where the entire menu should appear in relation to its referrer.
+ Horizontal: left*, right
+ Vertical: up, down*
+ - detectH/V: detect the viewport horizontally / vertically
+ - linkToFront: copy the menu link and place it on top of the menu (visual effect to make it look like it overlaps the object) */
+
+Menu.prototype.setPosition = function(widget, caller, options) {
+ var el = widget;
+ var referrer = caller;
+ var dims = {
+ refX: referrer.offset().left,
+ refY: referrer.offset().top,
+ refW: referrer.getTotalWidth(),
+ refH: referrer.getTotalHeight()
+ };
+ var options = options;
+ var xVal, yVal;
+
+ var helper = $('<div class="positionHelper"></div>');
+ helper.css({ position: 'absolute', left: dims.refX, top: dims.refY, width: dims.refW, height: dims.refH });
+ el.wrap(helper);
+
+ // get X pos
+ switch(options.positionOpts.posX) {
+ case 'left': xVal = 0;
+ break;
+ case 'center': xVal = dims.refW / 2;
+ break;
+ case 'right': xVal = dims.refW;
+ break;
+ };
+
+ // get Y pos
+ switch(options.positionOpts.posY) {
+ case 'top': yVal = 0;
+ break;
+ case 'center': yVal = dims.refH / 2;
+ break;
+ case 'bottom': yVal = dims.refH;
+ break;
+ };
+
+ // add the offsets (zero by default)
+ xVal += options.positionOpts.offsetX;
+ yVal += options.positionOpts.offsetY;
+
+ // position the object vertically
+ if (options.positionOpts.directionV == 'up') {
+ el.css({ top: 'auto', bottom: yVal });
+ if (options.positionOpts.detectV && !fitVertical(el)) {
+ el.css({ bottom: 'auto', top: yVal });
+ }
+ }
+ else {
+ el.css({ bottom: 'auto', top: yVal });
+ if (options.positionOpts.detectV && !fitVertical(el)) {
+ el.css({ top: 'auto', bottom: yVal });
+ }
+ };
+
+ // and horizontally
+ if (options.positionOpts.directionH == 'left') {
+ el.css({ left: 'auto', right: xVal });
+ if (options.positionOpts.detectH && !fitHorizontal(el)) {
+ el.css({ right: 'auto', left: xVal });
+ }
+ }
+ else {
+ el.css({ right: 'auto', left: xVal });
+ if (options.positionOpts.detectH && !fitHorizontal(el)) {
+ el.css({ left: 'auto', right: xVal });
+ }
+ };
+
+ // if specified, clone the referring element and position it so that it appears on top of the menu
+ if (options.positionOpts.linkToFront) {
+ referrer.clone().addClass('linkClone').css({
+ position: 'absolute',
+ top: 0,
+ right: 'auto',
+ bottom: 'auto',
+ left: 0,
+ width: referrer.width(),
+ height: referrer.height()
+ }).insertAfter(el);
+ };
+};
+
+
+/* Utilities to sort and find viewport dimensions */
+
+function sortBigToSmall(a, b) { return b - a; };
+
+jQuery.fn.getTotalWidth = function(){
+ return $(this).width() + parseInt($(this).css('paddingRight')) + parseInt($(this).css('paddingLeft')) + parseInt($(this).css('borderRightWidth')) + parseInt($(this).css('borderLeftWidth'));
+};
+
+jQuery.fn.getTotalHeight = function(){
+ return $(this).height() + parseInt($(this).css('paddingTop')) + parseInt($(this).css('paddingBottom')) + parseInt($(this).css('borderTopWidth')) + parseInt($(this).css('borderBottomWidth'));
+};
+
+function getScrollTop(){
+ return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
+};
+
+function getScrollLeft(){
+ return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
+};
+
+function getWindowHeight(){
+ var de = document.documentElement;
+ return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
+};
+
+function getWindowWidth(){
+ var de = document.documentElement;
+ return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
+};
+
+/* Utilities to test whether an element will fit in the viewport
+ Parameters:
+ el = element to position, required
+ leftOffset / topOffset = optional parameter if the offset cannot be calculated (i.e., if the object is in the DOM but is set to display: 'none') */
+
+function fitHorizontal(el, leftOffset){
+ var leftVal = parseInt(leftOffset) || $(el).offset().left;
+ return (leftVal + $(el).width() <= getWindowWidth() + getScrollLeft() && leftVal - getScrollLeft() >= 0);
+};
+
+function fitVertical(el, topOffset){
+ var topVal = parseInt(topOffset) || $(el).offset().top;
+ return (topVal + $(el).height() <= getWindowHeight() + getScrollTop() && topVal - getScrollTop() >= 0);
+};
+
+/*--------------------------------------------------------------------
+ * javascript method: "pxToEm"
+ * by:
+ Scott Jehl (scott at filamentgroup.com)
+ Maggie Wachs (maggie at filamentgroup.com)
+ http://www.filamentgroup.com
+ *
+ * Copyright (c) 2008 Filament Group
+ * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
+ *
+ * Description: Extends the native Number and String objects with pxToEm method. pxToEm converts a pixel value to ems depending on inherited font size.
+ * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
+ * Demo: http://www.filamentgroup.com/examples/pxToEm/
+ *
+ * Options:
+ scope: string or jQuery selector for font-size scoping
+ reverse: Boolean, true reverses the conversion to em-px
+ * Dependencies: jQuery library
+ * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
+ *
+ * Version: 2.0, 08.01.2008
+ * Changelog:
+ * 08.02.2007 initial Version 1.0
+ * 08.01.2008 - fixed font-size calculation for IE
+--------------------------------------------------------------------*/
+
+Number.prototype.pxToEm = String.prototype.pxToEm = function(settings){
+ //set defaults
+ settings = jQuery.extend({
+ scope: 'body',
+ reverse: false
+ }, settings);
+
+ var pxVal = (this == '') ? 0 : parseFloat(this);
+ var scopeVal;
+ var getWindowWidth = function(){
+ var de = document.documentElement;
+ return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
+ };
+
+ /* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size.
+ For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size.
+ When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size)
+ to get an accurate em value. */
+
+ if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
+ var calcFontSize = function(){
+ return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
+ };
+ scopeVal = calcFontSize();
+ }
+ else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); };
+
+ var result = (settings.reverse == true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
+ return result;
+};
\ No newline at end of file
diff --git a/docs/source/.static/hover.png b/docs/source/.static/hover.png
new file mode 100644
index 0000000..dcb0bb4
Binary files /dev/null and b/docs/source/.static/hover.png differ
diff --git a/docs/source/.static/index_slide_1.jpg b/docs/source/.static/index_slide_1.jpg
new file mode 100644
index 0000000..08b0270
Binary files /dev/null and b/docs/source/.static/index_slide_1.jpg differ
diff --git a/docs/source/.static/index_slide_2.jpg b/docs/source/.static/index_slide_2.jpg
new file mode 100644
index 0000000..29d510d
Binary files /dev/null and b/docs/source/.static/index_slide_2.jpg differ
diff --git a/docs/source/.static/index_slide_3.jpg b/docs/source/.static/index_slide_3.jpg
new file mode 100644
index 0000000..bd71b53
Binary files /dev/null and b/docs/source/.static/index_slide_3.jpg differ
diff --git a/docs/source/.static/index_slide_4.jpg b/docs/source/.static/index_slide_4.jpg
new file mode 100644
index 0000000..9465301
Binary files /dev/null and b/docs/source/.static/index_slide_4.jpg differ
diff --git a/docs/source/.static/jquery.betterTooltip.js b/docs/source/.static/jquery.betterTooltip.js
new file mode 100644
index 0000000..e8b7c53
--- /dev/null
+++ b/docs/source/.static/jquery.betterTooltip.js
@@ -0,0 +1,88 @@
+/*-------------------------------------------------------------------------------
+ A Better jQuery Tooltip
+ Version 1.0
+ By Jon Cazier
+ jon at 3nhanced.com
+ 01.22.08
+-------------------------------------------------------------------------------*/
+
+$.fn.betterTooltip = function(options){
+
+ /* Setup the options for the tooltip that can be
+ accessed from outside the plugin */
+ var defaults = {
+ speed: 200,
+ delay: 300
+ };
+
+ var options = $.extend(defaults, options);
+
+ /* Create a function that builds the tooltip
+ markup. Then, prepend the tooltip to the body */
+ getTip = function() {
+ var tTip =
+ "<div class='tip'>" +
+ "<div class='tipMid'>" +
+ "</div>" +
+ "<div class='tipBtm'></div>" +
+ "</div>";
+ return tTip;
+ }
+ $("body").prepend(getTip());
+
+ /* Give each item with the class associated with
+ the plugin the ability to call the tooltip */
+ $(this).each(function(){
+
+ var $this = $(this);
+ var tip = $('.tip');
+ var tipInner = $('.tip .tipMid');
+
+ var tTitle = (this.title);
+ this.title = "";
+
+ var offset = $(this).offset();
+ var tLeft = offset.left;
+ var tTop = offset.top;
+ var tWidth = $this.width();
+ var tHeight = $this.height();
+
+ /* Mouse over and out functions*/
+ $this.hover(
+ function() {
+ tipInner.html(tTitle);
+ setTip(tTop, tLeft);
+ setTimer();
+ },
+ function() {
+ stopTimer();
+ tip.hide();
+ }
+ );
+
+ /* Delay the fade-in animation of the tooltip */
+ setTimer = function() {
+ $this.showTipTimer = setInterval("showTip()", defaults.delay);
+ }
+
+ stopTimer = function() {
+ clearInterval($this.showTipTimer);
+ }
+
+ /* Position the tooltip relative to the class
+ associated with the tooltip */
+ setTip = function(top, left){
+ var topOffset = tip.height();
+ var xTip = (left-30)+"px";
+ var yTip = (top-topOffset-60)+"px";
+ tip.css({'top' : yTip, 'left' : xTip});
+ }
+
+ /* This function stops the timer and creates the
+ fade-in animation */
+ showTip = function(){
+ stopTimer();
+ tip.animate({"top": "+=20px", "opacity": "toggle"}, defaults.speed);
+ }
+ });
+};
\ No newline at end of file
diff --git a/docs/source/.static/jquery.js b/docs/source/.static/jquery.js
new file mode 100644
index 0000000..7c24308
--- /dev/null
+++ b/docs/source/.static/jquery.js
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j); [...]
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget) [...]
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g," [...]
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua [...]
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]* [...]
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if(( [...]
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagNam [...]
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.c [...]
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:fu [...]
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.i [...]
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMConten [...]
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"construc [...]
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Functi [...]
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d) [...]
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++ [...]
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d [...]
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if [...]
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left [...]
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select [...]
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCl [...]
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="non [...]
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embe [...]
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.rem [...]
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c. [...]
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a; [...]
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|inpu [...]
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.cla [...]
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+ [...]
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);thi [...]
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j< [...]
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",t [...]
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type proper [...]
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=functi [...]
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1) [...]
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n [...]
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove [...]
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf(" [...]
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(! [...]
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.e [...]
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange at [...]
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b. [...]
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.e [...]
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type) [...]
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented [...]
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submit [...]
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialS [...]
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_ [...]
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.t [...]
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventLi [...]
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a=== [...]
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return [...]
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j| [...]
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unl [...]
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++ [...]
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?: [...]
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g]) [...]
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||( [...]
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q [...]
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.spli [...]
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG" [...]
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attr [...]
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m+ [...]
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){ [...]
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG: [...]
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m [...]
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:functio [...]
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.no [...]
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q=== [...]
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0; [...]
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m [...]
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+) [...]
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocume [...]
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createR [...]
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!= [...]
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTM [...]
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l]; [...]
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPositi [...]
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Unti [...]
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f+ [...]
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=thi [...]
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||t [...]
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"par [...]
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeNam [...]
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeTy [...]
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b, [...]
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn. [...]
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(th [...]
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChi [...]
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.pa [...]
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChi [...]
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].i [...]
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith [...]
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagNam [...]
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childN [...]
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length=== [...]
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec [...]
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.pu [...]
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b [...]
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styl [...]
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")| [...]
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c [...]
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedSty [...]
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters. [...]
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:funct [...]
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}}) [...]
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess [...]
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url: [...]
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{} [...]
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka [...]
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;i [...]
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if [...]
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.se [...]
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q== [...]
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h [...]
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status== [...]
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="st [...]
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w) [...]
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a], [...]
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!==" [...]
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacit [...]
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){ [...]
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a [...]
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.f [...]
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this [...]
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.n [...]
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.st [...]
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this. [...]
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a [...]
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClien [...]
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:fun [...]
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.cu [...]
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o. [...]
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></d [...]
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j [...]
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b= [...]
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{ [...]
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pag [...]
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return" [...]
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/docs/source/.static/jquery.nivo.slider.pack.js b/docs/source/.static/jquery.nivo.slider.pack.js
new file mode 100644
index 0000000..a3f790e
--- /dev/null
+++ b/docs/source/.static/jquery.nivo.slider.pack.js
@@ -0,0 +1,13 @@
+/*
+ * jQuery Nivo Slider v1.9
+ * http://nivo.dev7studios.com
+ *
+ * Copyright 2010, Gilbert Pellegrom
+ * Free to use and abuse under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * April 2010 - controlNavThumbs option added by Jamie Thompson (http://jamiethompson.co.uk)
+ * March 2010 - manualAdvance option added by HelloPablo (http://hellopablo.co.uk)
+ */
+
+eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('(9($){$.1h.1i=9(1T){b 4=$.2b({},$.1h.1i.21,1T);K g.F(9(){b 3={e:0,n:\'\',T:0,u:\'\',H:l,1f:l,1O:l};b 5=$(g);5.1Q(\'7:3\',3);5.f(\'2h\',\'2i\');5.w(\'1X\');5.x(\'1 [...]
diff --git a/docs/source/.static/nivo-slider.css b/docs/source/.static/nivo-slider.css
new file mode 100644
index 0000000..5dc0060
--- /dev/null
+++ b/docs/source/.static/nivo-slider.css
@@ -0,0 +1,137 @@
+/*
+ * Note: Include the nivo-slider.css file that comes
+ * with the main download before including this file.
+ */
+
+/*
+ * jQuery Nivo Slider v1.8
+ * http://nivo.dev7studios.com
+ *
+ * Copyright 2010, Gilbert Pellegrom
+ * Free to use and abuse under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * March 2010
+ */
+
+
+/* The Nivo Slider styles */
+.nivoSlider {
+ position:relative;
+}
+.nivoSlider img {
+ position:absolute;
+ top:0px;
+ left:0px;
+}
+/* If an image is wrapped in a link */
+.nivoSlider a.nivo-imageLink {
+ position:absolute;
+ top:0px;
+ left:0px;
+ width:100%;
+ height:100%;
+ border:0;
+ padding:0;
+ margin:0;
+ z-index:60;
+ display:none;
+}
+/* The slices in the Slider */
+.nivo-slice {
+ display:block;
+ position:absolute;
+ z-index:50;
+ height:100%;
+}
+/* Caption styles */
+.nivo-caption {
+ position:absolute;
+ left:0px;
+ bottom:0px;
+ background:#000;
+ color:#fff;
+ opacity:0.8; /* Overridden by captionOpacity setting */
+ width:100%;
+ z-index:89;
+}
+.nivo-caption p {
+ padding:5px;
+ margin:0;
+}
+/* Direction nav styles (e.g. Next & Prev) */
+.nivo-directionNav a {
+ position:absolute;
+ top:45%;
+ z-index:99;
+ cursor:pointer;
+}
+.nivo-prevNav {
+ left:0px;
+}
+.nivo-nextNav {
+ right:0px;
+}
+/* Control nav styles (e.g. 1,2,3...) */
+.nivo-controlNav a {
+ position:relative;
+ z-index:99;
+ cursor:pointer;
+}
+.nivo-controlNav a.active {
+ font-weight:bold;
+}
+
+#slider {
+ position:relative;
+ margin:30px 30px 60px 30px;
+ margin-left: 18%; margin-right: 10%;
+ background:#202834 url(nivo_images/loading.gif) no-repeat 50% 50%;
+ -moz-box-shadow:0px 0px 10px #333;
+ -webkit-box-shadow:0px 0px 10px #333;
+ box-shadow:0px 0px 10px #333;
+}
+#slider img {
+ position:absolute;
+ top:0px;
+ left:0px;
+ display:none;
+}
+#slider a {
+ border:0;
+}
+
+.nivo-controlNav {
+ position:absolute;
+ left:47%;
+ bottom:-30px;
+}
+.nivo-controlNav a {
+ display:block;
+ width:10px;
+ height:10px;
+ background:url(nivo_images/bullets.png) no-repeat;
+ text-indent:-9999px;
+ border:0;
+ margin-right:3px;
+ float:left;
+}
+.nivo-controlNav a.active {
+ background-position:-10px 0;
+}
+
+.nivo-directionNav a {
+ display:block;
+ width:32px;
+ height:34px;
+ background:url(nivo_images/arrows.png) no-repeat;
+ text-indent:-9999px;
+ border:0;
+}
+a.nivo-nextNav {
+ background-position:-32px 0;
+ right:10px;
+}
+a.nivo-prevNav {
+ left:10px;
+}
\ No newline at end of file
diff --git a/docs/source/.static/nivo_images/arrows.png b/docs/source/.static/nivo_images/arrows.png
new file mode 100644
index 0000000..b3507d4
Binary files /dev/null and b/docs/source/.static/nivo_images/arrows.png differ
diff --git a/docs/source/.static/nivo_images/bullets.png b/docs/source/.static/nivo_images/bullets.png
new file mode 100644
index 0000000..1a4827b
Binary files /dev/null and b/docs/source/.static/nivo_images/bullets.png differ
diff --git a/docs/source/.static/nivo_images/loading.gif b/docs/source/.static/nivo_images/loading.gif
new file mode 100644
index 0000000..2dfd9c0
Binary files /dev/null and b/docs/source/.static/nivo_images/loading.gif differ
diff --git a/docs/source/.static/pyevolve.css b/docs/source/.static/pyevolve.css
new file mode 100644
index 0000000..ba5a211
--- /dev/null
+++ b/docs/source/.static/pyevolve.css
@@ -0,0 +1,663 @@
+/**
+ * Sphinx Doc Design
+ */
+
+body {
+ font-family: sans-serif;
+ font-size: 100%;
+ background-color: #0B8185;
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+/* :::: LAYOUT :::: */
+
+/* Menu Esquerda */
+div.document {
+ background-color: #DCE8EB;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.body {
+ background-color: white;
+ padding: 0 20px 30px 20px;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.clearer {
+ clear: both;
+}
+
+div.footer {
+ color: #fff;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #fff;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #8CCCBE;
+ color: #DCE8EB;
+ width: 100%;
+ line-height: 30px;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related a {
+ color: #0B8185;
+}
+
+/* ::: TOC :::: */
+div.sphinxsidebar h3 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: #0B8185;
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: #0B8185;
+}
+
+div.sphinxsidebar h4 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: #0B8185;
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: #0B8185;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ list-style: none;
+ color: #0B8185;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar a {
+ color: #0B8185;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+/* :::: MODULE CLOUD :::: */
+div.modulecloud {
+ margin: -5px 10px 5px 10px;
+ padding: 10px;
+ line-height: 160%;
+ border: 1px solid #cbe7e5;
+ background-color: #f2fbfd;
+}
+
+div.modulecloud a {
+ padding: 0 5px 0 5px;
+}
+
+/* :::: SEARCH :::: */
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* :::: COMMON FORM STYLES :::: */
+
+div.actions {
+ padding: 5px 10px 5px 10px;
+ border-top: 1px solid #cbe7e5;
+ border-bottom: 1px solid #cbe7e5;
+ background-color: #e0f6f4;
+}
+
+form dl {
+ color: #333;
+}
+
+form dt {
+ clear: both;
+ float: left;
+ min-width: 110px;
+ margin-right: 10px;
+ padding-top: 2px;
+}
+
+input#homepage {
+ display: none;
+}
+
+div.error {
+ margin: 5px 20px 0 0;
+ padding: 5px;
+ border: 1px solid #d00;
+ font-weight: bold;
+}
+
+/* :::: INDEX PAGE :::: */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* :::: INDEX STYLES :::: */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+form.pfform {
+ margin: 10px 0 20px 0;
+}
+
+/* :::: GLOBAL STYLES :::: */
+
+.docwarning {
+ background-color: #ffe4e4;
+ padding: 10px;
+ margin: 0 -20px 0 -20px;
+ border-bottom: 1px solid #f66;
+}
+
+p.subhead {
+ font-weight: bold;
+ margin-top: 20px;
+}
+
+a {
+ color: #355f7c;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: 'Trebuchet MS', sans-serif;
+ background-color: #E3E8CF;
+ font-weight: normal;
+ color: #20435c;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+ul.fakelist {
+ list-style: none;
+ margin: 10px 0 10px 20px;
+ padding: 0;
+}
+
+.field-list ul {
+ padding-left: 1em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+/* "Footnotes" heading */
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+/* Sidebars */
+
+div.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+/* "Topics" */
+
+div.topic {
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* Admonitions */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+table.docutils {
+ border: 0;
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 0;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+dl {
+ margin-bottom: 15px;
+ clear: both;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+.refcount {
+ color: #060;
+}
+
+dt:target,
+.highlight {
+ background-color: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+pre {
+ padding: 5px;
+ background-color: #efc;
+ color: #333;
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+ overflow: auto;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.footnote:target { background-color: #ffa }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+.noBorder {
+ text-decoration: none;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+form.comment {
+ margin: 0;
+ padding: 10px 30px 10px 30px;
+ background-color: #eee;
+}
+
+form.comment h3 {
+ background-color: #326591;
+ color: white;
+ margin: -10px -30px 10px -30px;
+ padding: 5px;
+ font-size: 1.4em;
+}
+
+form.comment input,
+form.comment textarea {
+ border: 1px solid #ccc;
+ padding: 2px;
+ font-family: sans-serif;
+ font-size: 100%;
+}
+
+form.comment input[type="text"] {
+ width: 240px;
+}
+
+form.comment textarea {
+ width: 100%;
+ height: 200px;
+ margin-bottom: 10px;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+img.math {
+ vertical-align: middle;
+}
+
+div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+img.logo {
+ border: 0;
+}
+
+/* :::: PRINT :::: */
+ at media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0;
+ width : 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ div#comments div.new-comment-box,
+ #top-link {
+ display: none;
+ }
+}
diff --git a/docs/source/.static/reddit_icon.png b/docs/source/.static/reddit_icon.png
new file mode 100644
index 0000000..23a46ae
Binary files /dev/null and b/docs/source/.static/reddit_icon.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png b/docs/source/.static/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png
new file mode 100644
index 0000000..5b66315
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_flat_35_f0f0f0_40x100.png b/docs/source/.static/theme/images/ui-bg_flat_35_f0f0f0_40x100.png
new file mode 100644
index 0000000..034cd0d
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_flat_35_f0f0f0_40x100.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_glass_55_fcf0ba_1x400.png b/docs/source/.static/theme/images/ui-bg_glass_55_fcf0ba_1x400.png
new file mode 100644
index 0000000..a95fa33
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_glass_55_fcf0ba_1x400.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png b/docs/source/.static/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png
new file mode 100644
index 0000000..4fca482
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png b/docs/source/.static/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png
new file mode 100644
index 0000000..d6f3c7c
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png b/docs/source/.static/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png
new file mode 100644
index 0000000..a0810e3
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png b/docs/source/.static/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png
new file mode 100644
index 0000000..869db19
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png b/docs/source/.static/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png
new file mode 100644
index 0000000..12686a5
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png differ
diff --git a/docs/source/.static/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png b/docs/source/.static/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png
new file mode 100644
index 0000000..063d394
Binary files /dev/null and b/docs/source/.static/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png differ
diff --git a/docs/source/.static/theme/images/ui-icons_808080_256x240.png b/docs/source/.static/theme/images/ui-icons_808080_256x240.png
new file mode 100644
index 0000000..e36d0fa
Binary files /dev/null and b/docs/source/.static/theme/images/ui-icons_808080_256x240.png differ
diff --git a/docs/source/.static/theme/images/ui-icons_8DC262_256x240.png b/docs/source/.static/theme/images/ui-icons_8DC262_256x240.png
new file mode 100644
index 0000000..34cbac8
Binary files /dev/null and b/docs/source/.static/theme/images/ui-icons_8DC262_256x240.png differ
diff --git a/docs/source/.static/theme/images/ui-icons_cd0a0a_256x240.png b/docs/source/.static/theme/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..2db88b7
Binary files /dev/null and b/docs/source/.static/theme/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/docs/source/.static/theme/images/ui-icons_e7e6e4_256x240.png b/docs/source/.static/theme/images/ui-icons_e7e6e4_256x240.png
new file mode 100644
index 0000000..e7495a6
Binary files /dev/null and b/docs/source/.static/theme/images/ui-icons_e7e6e4_256x240.png differ
diff --git a/docs/source/.static/theme/images/ui-icons_eeeeee_256x240.png b/docs/source/.static/theme/images/ui-icons_eeeeee_256x240.png
new file mode 100644
index 0000000..4ab0247
Binary files /dev/null and b/docs/source/.static/theme/images/ui-icons_eeeeee_256x240.png differ
diff --git a/docs/source/.static/theme/images/ui-icons_ffffff_256x240.png b/docs/source/.static/theme/images/ui-icons_ffffff_256x240.png
new file mode 100644
index 0000000..746e6fa
Binary files /dev/null and b/docs/source/.static/theme/images/ui-icons_ffffff_256x240.png differ
diff --git a/docs/source/.static/theme/ui.accordion.css b/docs/source/.static/theme/ui.accordion.css
new file mode 100644
index 0000000..c84ad4e
--- /dev/null
+++ b/docs/source/.static/theme/ui.accordion.css
@@ -0,0 +1,9 @@
+/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion li {display: inline;}
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
+.ui-accordion .ui-accordion-content-active { display: block; }
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.all.css b/docs/source/.static/theme/ui.all.css
new file mode 100644
index 0000000..543e4c3
--- /dev/null
+++ b/docs/source/.static/theme/ui.all.css
@@ -0,0 +1,2 @@
+ at import "ui.base.css";
+ at import "ui.theme.css";
diff --git a/docs/source/.static/theme/ui.base.css b/docs/source/.static/theme/ui.base.css
new file mode 100644
index 0000000..dadf378
--- /dev/null
+++ b/docs/source/.static/theme/ui.base.css
@@ -0,0 +1,9 @@
+ at import url("ui.core.css");
+
+ at import url("ui.accordion.css");
+ at import url("ui.datepicker.css");
+ at import url("ui.dialog.css");
+ at import url("ui.progressbar.css");
+ at import url("ui.resizable.css");
+ at import url("ui.slider.css");
+ at import url("ui.tabs.css");
diff --git a/docs/source/.static/theme/ui.core.css b/docs/source/.static/theme/ui.core.css
new file mode 100644
index 0000000..d832ad7
--- /dev/null
+++ b/docs/source/.static/theme/ui.core.css
@@ -0,0 +1,37 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.datepicker.css b/docs/source/.static/theme/ui.datepicker.css
new file mode 100644
index 0000000..92986c9
--- /dev/null
+++ b/docs/source/.static/theme/ui.datepicker.css
@@ -0,0 +1,62 @@
+/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:left; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.dialog.css b/docs/source/.static/theme/ui.dialog.css
new file mode 100644
index 0000000..f10f409
--- /dev/null
+++ b/docs/source/.static/theme/ui.dialog.css
@@ -0,0 +1,13 @@
+/* Dialog
+----------------------------------*/
+.ui-dialog { position: relative; padding: .2em; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.progressbar.css b/docs/source/.static/theme/ui.progressbar.css
new file mode 100644
index 0000000..bc0939e
--- /dev/null
+++ b/docs/source/.static/theme/ui.progressbar.css
@@ -0,0 +1,4 @@
+/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.resizable.css b/docs/source/.static/theme/ui.resizable.css
new file mode 100644
index 0000000..44efeb2
--- /dev/null
+++ b/docs/source/.static/theme/ui.resizable.css
@@ -0,0 +1,13 @@
+/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.slider.css b/docs/source/.static/theme/ui.slider.css
new file mode 100644
index 0000000..0792a48
--- /dev/null
+++ b/docs/source/.static/theme/ui.slider.css
@@ -0,0 +1,17 @@
+/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: 1%; display: block; border: 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.tabs.css b/docs/source/.static/theme/ui.tabs.css
new file mode 100644
index 0000000..70ed3ef
--- /dev/null
+++ b/docs/source/.static/theme/ui.tabs.css
@@ -0,0 +1,9 @@
+/* Tabs
+----------------------------------*/
+.ui-tabs {padding: .2em;}
+.ui-tabs .ui-tabs-nav { padding: .2em .2em 0 .2em; position: relative; }
+.ui-tabs .ui-tabs-nav li { float: left; border-bottom: 0 !important; margin: 0 .2em -1px 0; padding: 0; list-style: none; }
+.ui-tabs .ui-tabs-nav li a { display:block; text-decoration: none; padding: .5em 1em; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: .1em; border-bottom: 0; }
+.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border: 0; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
\ No newline at end of file
diff --git a/docs/source/.static/theme/ui.theme.css b/docs/source/.static/theme/ui.theme.css
new file mode 100644
index 0000000..9dcb2bd
--- /dev/null
+++ b/docs/source/.static/theme/ui.theme.css
@@ -0,0 +1,245 @@
+
+
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://ui.jquery.com/themeroller/?ffDefault=segoe%20ui,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=3b3b35&bgTextureHeader=05_inset_soft.png&bgImgOpacityHeader=22&borderColorHeader=59584f&fcHeader=ffffff&iconColorHeader=e7e6e4&bgColorContent=f0efea&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=808080&bgColorDefault=327E04&bgTextureDef [...]
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: segoe ui, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: segoe ui, Arial, sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #f0efea url(images/ui-bg_highlight-soft_100_f0efea_1x100.png) 50% top repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #59584f; background: #3b3b35 url(images/ui-bg_inset-soft_22_3b3b35_1x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
+.ui-widget-header a { color: #ffffff; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #327E04; background: #327E04 url(images/ui-bg_highlight-soft_25_327E04_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; outline: none; }
+.ui-state-default a { color: #ffffff; text-decoration: none; outline: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #327E04; background: #5A9D1A url(images/ui-bg_highlight-soft_25_5A9D1A_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; outline: none; }
+.ui-state-hover a { color: #ffffff; text-decoration: none; outline: none; }
+.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #c4c5c3; background: #f0efea url(images/ui-bg_diagonals-small_100_f0efea_40x40.png) 50% 50% repeat; font-weight: bold; color: #403D38; outline: none; }
+.ui-state-active a { color: #403D38; outline: none; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #e8e1b5; background: #fcf0ba url(images/ui-bg_glass_55_fcf0ba_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #e3a345; background: #ffedad url(images/ui-bg_highlight-soft_95_ffedad_1x100.png) 50% top repeat-x; color: #cd5c0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd5c0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd5c0a; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_808080_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_808080_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_e7e6e4_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_eeeeee_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_8DC262_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_8DC262_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; }
+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }
+.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #2e2e28 url(images/ui-bg_glow-ball_25_2e2e28_600x600.png) 50% 35% repeat-x; opacity: .65;filter:Alpha(Opacity=65); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #f0f0f0 url(images/ui-bg_flat_35_f0f0f0_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }
\ No newline at end of file
diff --git a/docs/source/.static/tip_images/tipBtm.png b/docs/source/.static/tip_images/tipBtm.png
new file mode 100644
index 0000000..b0e82b3
Binary files /dev/null and b/docs/source/.static/tip_images/tipBtm.png differ
diff --git a/docs/source/.static/tip_images/tipMid.png b/docs/source/.static/tip_images/tipMid.png
new file mode 100644
index 0000000..ccc2cc1
Binary files /dev/null and b/docs/source/.static/tip_images/tipMid.png differ
diff --git a/docs/source/.static/tip_images/tipTop.png b/docs/source/.static/tip_images/tipTop.png
new file mode 100644
index 0000000..4e554f1
Binary files /dev/null and b/docs/source/.static/tip_images/tipTop.png differ
diff --git a/docs/source/.templates/layout.html b/docs/source/.templates/layout.html
new file mode 100644
index 0000000..6880aef
--- /dev/null
+++ b/docs/source/.templates/layout.html
@@ -0,0 +1,129 @@
+{% extends "!layout.html" %}
+
+{% block extrahead %}
+{{ super() }}
+
+<!-- Remove it for the htmlhelp chm -->
+<!-- script type="text/javascript" src="_static/jquery.js"></script -->
+<link type="text/css" href="_static/fg.menu.css" media="screen" rel="stylesheet" />
+<link type="text/css" href="_static/theme/ui.all.css" media="screen" rel="stylesheet" />
+<link rel="stylesheet" href="_static/nivo-slider.css" type="text/css" media="screen" />
+
+<script type="text/javascript" src="_static/fg.menu.js"></script>
+<script type="text/javascript" src="_static/jquery.betterTooltip.js"></script>
+<script src="_static/jquery.nivo.slider.pack.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ .hidden { position:absolute; top:0; left:-9999px; width:1px; height:1px; overflow:hidden; }
+ .ui-widget-content { font-size:0.9em; }
+
+ .fg-button {
+ clear:left;
+ margin:0 4px 40px 20px;
+ padding:.4em 1em;
+ text-decoration:none !important;
+ cursor:pointer;
+ position:relative;
+ text-align:center;
+ font-size:0.8em;
+ zoom:1;
+ }
+
+ .fg-button .ui-icon { position: absolute; top: 50%; margin-top: -8px; left: 50%; margin-left: -8px; }
+/* a.fg-button { float:left; }*/
+ button.fg-button { width:auto; overflow:visible; }
+
+ .fg-button-icon-left { padding-left: 2.1em; }
+ .fg-button-icon-right { padding-right: 2.1em; }
+ .fg-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; }
+ .fg-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; }
+ .fg-button-icon-solo { display:block; width:8px; text-indent: -9999px; }
+ </style>
+
+ <!-- style exceptions for IE 6 -->
+ <!--[if IE 6]>
+ <style type="text/css">
+ .fg-menu-ipod .fg-menu li { width: 95%; }
+ .fg-menu-ipod .ui-widget-content { border:0; }
+ </style>
+ <![endif]-->
+
+
+<script type="text/javascript">
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-7117443-1']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
+ })();
+</script>
+
+<script type="text/javascript">
+ $(document).ready(function(){
+ $('.fg-button').hover(
+ function(){ $(this).removeClass('ui-state-default').addClass('ui-state-focus'); },
+ function(){ $(this).removeClass('ui-state-focus').addClass('ui-state-default'); }
+ );
+
+ $('#hierarchybreadcrumb').menu({
+ content: $('#upper-menu-items').html(),
+ width: 200,
+ maxHeight: 300
+ });
+
+ $('.ttip').betterTooltip({speed: 200, delay: 50});
+ $('#slider').nivoSlider();
+
+ });
+</script>
+
+{% endblock %}
+
+{% block sidebarlogo %}
+<p align="center">
+<a href="http://del.icio.us/post?url=http://pyevolve.sourceforge.net" target="_blank">
+ <img src="_static/delicious_icon.png" border="0">
+</a>
+
+<a href="http://digg.com/submit?url=http://pyevolve.sourceforge.net" target="_blank">
+ <img src="_static/digg_icon.png" border="0">
+</a>
+
+<a href="http://www.reddit.com/submit?resubmit=true&url=http%3A%2F%2Fpyevolve.sourceforge.net%2F" target="_blank">
+ <img src="_static/reddit_icon.png" border="0">
+</a>
+
+</p>
+<br>
+{% endblock %}
+
+{% block footer %}
+{{ super() }}
+<div id="extraDiv2"><span></span></div>
+{% endblock %}
+
+{% block rootrellink %}
+{{ super() }}
+ <li class="right">
+<div id="upper-menu">
+<a tabindex="0" href="#upper-menu-items" class="fg-button fg-button-icon-right ui-widget ui-state-default ui-corner-all" id="hierarchybreadcrumb">
+ <span class="ui-icon ui-icon-triangle-1-s"></span>
+ Pyevolve Menu
+</a>
+
+<div id="upper-menu-items" class="hidden">
+<ul>
+ <a href="{{ pathto(master_doc) }}"><li>Main Index</li></a>
+ <li><a href="http://pyevolve.sourceforge.net/wordpress">Pyevolve Blog</a></li>
+ <li><a href="http://sourceforge.net/apps/trac/pyevolve">Trac System</a></li>
+ <li><a href="http://groups.google.com/group/pyevolve">Mail-list</a>
+</ul>
+</div>
+
+</div>
+</li>
+
+{% endblock %}
\ No newline at end of file
diff --git a/docs/source/README.TXT b/docs/source/README.TXT
new file mode 100644
index 0000000..30d5cbf
--- /dev/null
+++ b/docs/source/README.TXT
@@ -0,0 +1,3 @@
+To developers:
+Please use the most recent Sphinx version and just call the script to build the docs. Older versions of Sphinx have a bug while inserting example codes into the rst format. I've fixed in the patch sphinx06_code_patch.py and reported to Sphinx team which already have fixed it.
+- Christian S. Perone
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000..5c552b4
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+#
+# Pyevolve documentation build configuration file, created by
+# sphinx-quickstart on Thu Jan 15 11:05:43 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+if sys.platform[:5]:
+ sys.path.append(os.path.abspath("../../") + "/pyevolve")
+ sys.path.append(os.path.abspath("../../"))
+
+elif sys.platform[:3] == "win":
+ sys.path.append(os.path.abspath("../../") + "\\pyevolve")
+ sys.path.append(os.path.abspath("../../"))
+
+sys.path.append(os.path.abspath('ext'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.inheritance_diagram', 'pyevolve_tooltip']
+
+inheritance_node_attrs = dict(shape='rectangle', fontsize=10, height=0.40)
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Pyevolve'
+copyright = u'2010, Christian S. Perone'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.6'
+# The full version, including alpha/beta/rc tags.
+release = '0.6 final'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+#exclude_trees = [r'.static\.svn']
+
+exclude_dirnames = [".svn"]
+exclude_dirs = [".svn"]
+
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+highlight_language = 'python'
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+#html_style = 'pyevolve.css'
+html_style = 'default_patch.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Pyevolvedoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'Pyevolve.tex', ur'Pyevolve Documentation',
+ ur'Christian S. Perone', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/docs/source/contact.rst b/docs/source/contact.rst
new file mode 100644
index 0000000..659d142
--- /dev/null
+++ b/docs/source/contact.rst
@@ -0,0 +1,18 @@
+
+Contact the author
+====================================
+
+If you have any questions or suggestions, you can contact me at:
+
+christian.perone at gmail.com
+
+.. image:: imgs/brasil_flag.jpg
+
+
+Please use the word "pyevolve" in the email subject.
+
+
+Donate
+====================================
+
+Please, `donate <http://sourceforge.net/donate/index.php?group_id=251160>`_ to support the development of this project.
diff --git a/docs/source/contributors.rst b/docs/source/contributors.rst
new file mode 100644
index 0000000..58c260d
--- /dev/null
+++ b/docs/source/contributors.rst
@@ -0,0 +1,23 @@
+
+Contributors
+==============================================
+
+**Boris Gorelik**, from `Procognia Ltd <http://procognia.com>`_, `Blog inthehaystack.com <http://www.inthehaystack.com/>`_, `@boris_gorelik <http://twitter.com/boris_gorelik>`_, Ashdod, Israel.
+
+.. image:: imgs/email_boris.png
+
+**Amit Saha**, `Blog amitksaha.wordpress.com <http://amitksaha.wordpress.com/>`_, `@amitsaha <http://twitter.com/amitsaha>`_, India.
+
+.. image:: imgs/email_amit.png
+
+**Jelle Feringa**, Jelle Feringa, Tu Delft University, Netherlands.
+
+.. image:: imgs/email_jelle.png
+
+**Henrik Rudstrom**, `Blog uniqueidentifier.net <http://uniqueidentifier.net>`_, `@henrk <http://twitter.com/henrk>`_, Rotterdam, Netherlands.
+
+.. image:: imgs/email_henrik.png
+
+**Christian Kastner**, Austria.
+
+.. image:: imgs/email_christian_kastner.png
diff --git a/docs/source/examples.rst b/docs/source/examples.rst
new file mode 100644
index 0000000..93de320
--- /dev/null
+++ b/docs/source/examples.rst
@@ -0,0 +1,214 @@
+Examples
+============================================================================
+
+All the examples can be downloaded from the :ref:`download_sec` section, **they are not**
+included in the installation package.
+
+Example 1 - Simple example
+---------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex1_simple.py`
+
+This is Example #1, a very simple example:
+
+.. literalinclude:: ../../examples/pyevolve_ex1_simple.py
+
+Example 2 - Real numbers, Gaussian Mutator
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex2_realgauss.py`
+
+This example uses the :func:`Initializators.G1DListInitializatorReal` initializator
+and the :func:`Mutators.G1DListMutatorRealGaussian` mutator:
+
+.. literalinclude:: ../../examples/pyevolve_ex2_realgauss.py
+
+Example 3 - Schaffer F6 deceptive function
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex3_schaffer.py`
+
+This examples tries to minimize the Schaffer F6 function. This function is a
+deceptive function, considered a GA-hard function to optimize:
+
+.. literalinclude:: ../../examples/pyevolve_ex3_schaffer.py
+
+Example 4 - Using Sigma truncation scaling
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex4_sigmatrunc.py`
+
+This example shows the use of the sigma truncation scale method. It tries
+to minimize a function with negative results:
+
+.. literalinclude:: ../../examples/pyevolve_ex4_sigmatrunc.py
+
+Example 5 - Step callback function
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex5_callback.py`
+
+This example shows the use of the :term:`step callback function`:
+
+.. literalinclude:: ../../examples/pyevolve_ex5_callback.py
+
+
+Example 6 - The DB Adapters
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex6_dbadapter.py`
+
+This example shows the use of the DB Adapters (:mod:`DBAdapters`) :
+
+.. literalinclude:: ../../examples/pyevolve_ex6_dbadapter.py
+
+
+Example 7 - The Rastrigin function
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex7_rastrigin.py`
+
+This example minimizes the deceptive function Rastrigin with 20 variables:
+
+.. literalinclude:: ../../examples/pyevolve_ex7_rastrigin.py
+
+
+Example 8 - The Gaussian Integer Mutator
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex8_gauss_int.py`
+
+This example shows the use of the Gaussian Integer Mutator:
+(:class:`Mutators.G1DListMutatorIntegerGaussian`):
+
+.. literalinclude:: ../../examples/pyevolve_ex8_gauss_int.py
+
+Example 9 - The 2D List genome
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex9_g2dlist.py`
+
+This example shows the use of the 2D list genome (:class:`G2DList.G2DList`):
+
+.. literalinclude:: ../../examples/pyevolve_ex9_g2dlist.py
+
+Example 10 - The 1D Binary String
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex10_g1dbinstr.py`
+
+This example shows the use of the 1D Binary String genome:
+
+.. literalinclude:: ../../examples/pyevolve_ex10_g1dbinstr.py
+
+Example 11 - The use of alleles
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex11_allele.py`
+
+This example shows the use of alleles:
+
+.. literalinclude:: ../../examples/pyevolve_ex11_allele.py
+
+Example 12 - The Travelling Salesman Problem (TSP)
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex12_tsp.py`
+
+This example shows the use of Pyevolve to solve the `TSP <http://en.wikipedia.org/wiki/Traveling_salesman_problem>`_:
+
+.. literalinclude:: ../../examples/pyevolve_ex12_tsp.py
+
+This example will plot a file called :file:`tsp_result.png` in the same
+current working directory. The generated image will be the best result of the
+TSP, it looks like:
+
+ .. image:: imgs/ex_12_tsp_result.png
+ :align: center
+
+To plot this image, you will need the Python Imaging Library (PIL).
+
+.. seealso::
+
+ `Python Imaging Library (PIL) <http://www.pythonware.com/products/pil/>`_
+ The Python Imaging Library (PIL) adds image processing capabilities to your
+ Python interpreter. This library supports many file formats, and provides
+ powerful image processing and graphics capabilities.
+
+Example 13 - The sphere function
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex13_sphere.py`
+
+This is the GA to solve the sphere function:
+
+.. literalinclude:: ../../examples/pyevolve_ex13_sphere.py
+
+Example 14 - The Ackley function
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex14_ackley.py`
+
+This example minimizes the Ackley F1 function, a deceptive function:
+
+.. literalinclude:: ../../examples/pyevolve_ex14_ackley.py
+
+Example 15 - The Rosenbrock function
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex15_rosenbrock.py`
+
+This example minimizes the Rosenbrock function, another deceptive function:
+
+.. literalinclude:: ../../examples/pyevolve_ex15_rosenbrock.py
+
+Example 16 - The 2D Binary String
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex16_g2dbinstr.py`
+
+This example shows the use of the 2D Binary String genome:
+
+.. literalinclude:: ../../examples/pyevolve_ex16_g2dbinstr.py
+
+Example 17 - The Tree genome example
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex17_gtree.py`
+
+This example shows the use of the Tree genome:
+
+.. literalinclude:: ../../examples/pyevolve_ex17_gtree.py
+
+.. _pyevolve-example18:
+
+Example 18 - The Genetic Programming example
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex18_gp.py`
+
+This example shows the use of the GTreeGP genome (for Genetic Programming):
+
+.. literalinclude:: ../../examples/pyevolve_ex18_gp.py
+
+Example 21 - The n-queens problem (64x64 chess board)
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex21_nqueens.py`
+
+This example shows the use of GA to solve the n-queens problem for a
+chess board of size 64x64:
+
+.. literalinclude:: ../../examples/pyevolve_ex21_nqueens.py
+
+
+Example 22 - The Infinite Monkey Theorem
+-------------------------------------------------------------------------------
+
+Filename: :file:`examples/pyevolve_ex22_monkey.py`
+
+This example was kindly contributed by Jelle Feringa, it shows the
+`Infinite Monkey Theorem <http://en.wikipedia.org/wiki/Infinite_monkey_theorem>`_:
+
+.. literalinclude:: ../../examples/pyevolve_ex22_monkey.py
+
diff --git a/docs/source/ext/pyevolve_tooltip.py b/docs/source/ext/pyevolve_tooltip.py
new file mode 100644
index 0000000..cc7198b
--- /dev/null
+++ b/docs/source/ext/pyevolve_tooltip.py
@@ -0,0 +1,20 @@
+"""
+ Tooltip Sphinx extension
+
+ :copyright: Copyright 2010 by Christian S. Perone
+ :license: PSF, see LICENSE for details.
+
+"""
+from sphinx.util.compat import Directive
+from docutils import nodes
+import re
+
+def tip_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ matches = re.match("\<(?P<word>\w+)\> (?P<tip>.*)", text)
+ matches_tuple = matches.group("tip"), matches.group("word")
+ template = """<span class="ttip" title="%s">%s</span>""" % matches_tuple
+ node = nodes.raw('', template, format='html')
+ return [node], []
+
+def setup(app):
+ app.add_role('tip', tip_role)
\ No newline at end of file
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
new file mode 100644
index 0000000..88c9380
--- /dev/null
+++ b/docs/source/faq.rst
@@ -0,0 +1,15 @@
+
+F.A.Q.
+====================================
+
+**What is Pyevolve ?**
+
+ Pyevolve is an Evolutionary Computation framework written in pure python.
+
+**Why you have created this framework ?**
+
+ Python is a powerful language, the features of Python together
+ with the Evolutionary Algorithms (EA) can be very interesting. There
+ is no good GA library written in Python today. The main effort
+ of Pyevolve is to solve a clean solution, since the Evolutionary Computation
+ research field is growing faster.
diff --git a/docs/source/getstarted.rst b/docs/source/getstarted.rst
new file mode 100644
index 0000000..453238b
--- /dev/null
+++ b/docs/source/getstarted.rst
@@ -0,0 +1,852 @@
+
+Get Started - Tutorial
+============================================================================
+
+Pyevolve combined with the Python language can be a powerful tool. The best way to show you how Pyevolve can be used is to begin with some simple examples; later we'll show some snippets, etc. so you'll be alble to walk by yourself.
+
+First Example
+---------------------------------------------------------------------------
+
+To make the API easy to use, we have provided default values for almost every parameter in Pyevolve.
+For example, when you use the :class:`G1DList.G1DList` genome without specifying the Mutator, Crossover and Initializator, you will be using the default ones: Swap Mutator, One Point Crossover and the Integer Initialzator. All those default parameters are specified in the :mod:`Consts` module (and you are highly encouraged to take a look at source code).
+
+Let's begin with the first simple example (Ex. 1). First of all, you must know your problem: in this case, our problem is to find a simple 1D list of integers of *n*-size with zero in all positions.
+At first look, we know by intuition that the representation needed for this
+problem is a 1D List, which you can find in Pyevolve by the name of :class:`G1DList.G1DList`, which means Genome 1D List. This representation is based on a python list as you will see, and is very easy to manipulate.
+The next step is to define the :term:`evaluation function` to our Genetic Algorithm. We want all the *n* list positions with value of '0', so we can propose the evaluation function:
+
+.. image:: imgs/ex1equation.png
+ :align: center
+
+
+As you can see in the above equation, with the *x* variable representing our genome list of integers, the *f(x)* shows our evaluation function, which is the sum of '0' values in the list. For example, if we have a list with 10 elements like this: ::
+
+ x = [1, 2, 3, 8, 0, 2, 0, 4, 1, 0]
+
+
+we will get the raw score [#rawscore]_ value of 3, or *f(x)* = 3. It's very simple to understand. Now, let's code this.
+
+We will define our :term:`evaluation function` **"eval_func"** as: ::
+
+ # This function is the evaluation function, we want
+ # to give high score to more zero'ed chromosomes
+ def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome elements (items)
+ for value in chromosome:
+ if value==0:
+ score += 1.0
+
+ return score
+
+As you can see, this evaluation function tests each element in the list for equality with '0' and returns the proportional score value. The :class:`G1DList.G1DList` chromosome is not a python list by itself but it encapsulates one and exposes the methods for this list, like the iterator used in the above loop.
+The next step is the creation of a :term:`sample genome` [#samplegenome]_ for the Genetic Algorithm. We can define our genome as this: ::
+
+ # Genome instance
+ genome = G1DList.G1DList(20)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+
+This will create an instance of the :class:`G1DList.G1DList` class (which resides in the :mod:`G1DList` module) with the list *n*-size of 20 and sets the evaluation function of the genome to the evaluation function **"eval_func"** that we created before.
+
+But wait - where is the range of integers that will be used in the list ? Where are the mutator, crossover and initialization functions ? They are all in the default parameters. As you see, these parameters keep things simple.
+
+By default (and you have the **documentation** to find these defaults), the range of the integers in the :class:`G1DList.G1DList` is between the inverval [ :attr:`Consts.CDefRangeMin`, :attr:`Consts.CDefRangeMax`] inclusive, and genetic operators is the same I have cited before: Swap Mutator :func:`Mutators.G1DListMutatorSwap`, One Point Crossover :func:`Crossovers.G1DListCrossoverSinglePoint` and the Integer Initializator :func:`Initializators.G1DListInitializatorInteger`. You can chang [...]
+
+ genome.setParams(rangemin=0, rangemax=10)
+
+Right, now that we have our evaluation function and our first genome ready, the next step is to create our Genetic Algorithm Engine, the GA Core which will do the evolution, control statistics, etc...
+The GA Engine which we will use is the :class:`GSimpleGA.GSimpleGA` which resides in the :mod:`GSimpleGA` module. This GA Engine is the genetic algorithm [#ganote]_ described by Goldberg. So, let's create the engine: ::
+
+ ga = GSimpleGA.GSimpleGA(genome)
+
+Ready ! Easy, no ? We simply create our GA Engine with the previously created genome. You might be asking: "*Where is the selector method ? The number of generations ? Mutation rate ?*". Again: we have defaults. By default, the GA will evolve for 100 generations with a population size of 80 individuals, it will use the mutation rate of 2% and a crossover rate of 80%, the default selector is the Ranking Selection (:func:`Selectors.GRankSelector`) method. Those default parameters were not [...]
+
+Now, all we need to do is to evolve ! ::
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=10)
+
+ # Best individual
+ print ga.bestIndividual()
+
+.. note:: Pyevolve have the __repr__() function implemented for almost all objects, this means that you
+ can use syntax like 'print object' and the object information will be show in an
+ pretty format.
+
+Ready, now we have our first Genetic Algorithm, it looks more like a "Hello GA !" application. The code above shows the call of
+the :meth:`GSimpleGA.GSimpleGA.evolve` method, with the parameter *freq_stats=10*. This method will do the evolution and will show the statistics every 10th generation. The next method called is the :meth:`GSimpleGA.GSimpleGA.bestIndividual`, this method will return the best individual after the end of the evolution, and with the *print* python command, we will show the genome on the screen.
+
+This is what this example will produce as the result: ::
+
+ Gen. 1 (1.00%): Max/Min/Avg Fitness(Raw) [2.40(3.00) / 1.60(1.00) / 2.00(2.00)]
+ Gen. 10 (10.00%): Max/Min/Avg Fitness(Raw) [10.80(10.00) / 7.20(8.00) / 9.00(9.00)]
+ Gen. 20 (20.00%): Max/Min/Avg Fitness(Raw) [22.80(20.00) / 15.20(18.00) / 19.00(19.00)]
+ Gen. 30 (30.00%): Max/Min/Avg Fitness(Raw) [20.00(20.00) / 20.00(20.00) / 20.00(20.00)]
+ (...)
+ Gen. 100 (100.00%): Max/Min/Avg Fitness(Raw) [20.00(20.00) / 20.00(20.00) / 20.00(20.00)]
+
+ Total time elapsed: 3.375 seconds.
+
+ - GenomeBase
+ Score: 20.000000
+ Fitness: 20.000000
+
+ Slot [Evaluator] (Count: 1)
+ Name: eval_func
+ Slot [Initializator] (Count: 1)
+ Name: G1DListInitializatorInteger
+ Doc: Integer initialization function of G1DList,
+ accepts 'rangemin' and 'rangemax'
+ Slot [Mutator] (Count: 1)
+ Name: G1DListMutatorSwap
+ Doc: The mutator of G1DList, Swap Mutator
+ Slot [Crossover] (Count: 1)
+ Name: G1DListCrossoverSinglePoint
+ Doc: The crossover of G1DList, Single Point
+ - G1DList
+ List size: 20
+ List: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+
+
+This is the evolution of our Genetic Algorithm, with the best individual shown at the end of the evolution. As you can see, the population obtained the best raw score (20.00) near generation 20.
+
+
+Final source code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Here is the final source code: ::
+
+ from pyevolve import G1DList
+ from pyevolve import GSimpleGA
+
+ def eval_func(chromosome):
+ score = 0.0
+ # iterate over the chromosome
+ for value in chromosome:
+ if value==0:
+ score += 1
+ return score
+
+ genome = G1DList.G1DList(20)
+ genome.evaluator.set(eval_func)
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.evolve(freq_stats=10)
+ print ga.bestIndividual()
+
+
+
+.. rubric:: Footnotes
+
+.. [#rawscore] It is important to note that in Pyevolve, we have :term:`raw score` and :term:`fitness score`, the raw score is the return of the evaluation function and the fitness score is the scaled score or the raw score in absence of a scaling scheme.
+
+.. [#samplegenome] The term :term:`sample genome` means one genome which provides the main configuration for all individuals.
+
+.. [#ganote] This GA uses non-overlapping populations.
+
+
+The Interactive Mode
+---------------------------------------------------------------------------
+
+Pyevolve introduced the concept of the :term:`Interactive Mode` in
+the course of evolution. When you are evolving, and the Interactive Mode
+is enabled, you can press the *ESC Key* anytime during the evolution process. By
+pressing that key, you will enter the interactive mode, with a normal
+python prompt and the :mod:`Interaction` module exposed to you as the "it"
+module.
+
+.. warning:: note that the Interactive Mode for Linux/Mac was disabled in the
+ 0.6 release of Pyevolve. The cause was the platform dependant code.
+ To use it in Linux/Mac you must set the generation in wich Pyevolve
+ will enter in the Interactive Mode by using :meth:`GSimpleGA.GSimpleGA.setInteractiveGeneration`
+ method; see the :mod:`Interaction` module documentation for more information.
+
+If you want to continue the evolution, just press *CTRL-D* on Linux or *CTRL-Z*
+on Windows.
+
+See this session example: ::
+
+ # pyevolve_ex1_simple.py
+ Gen. 1 (0.20%): Max/Min/Avg Fitness(Raw) [6.18(11.00)/4.42(1.00)/5.15(5.15)]
+ Gen. 20 (4.00%): Max/Min/Avg Fitness(Raw) [11.70(15.00)/7.24(3.00)/9.75(9.75)]
+ Gen. 40 (8.00%): Max/Min/Avg Fitness(Raw) [17.99(21.00)/12.00(9.00)/14.99(14.99)]
+ Loading module pylab (matplotlib)... done!
+ Loading module numpy... done!
+
+ ## Pyevolve v.0.6 - Interactive Mode ##
+ Press CTRL-D to quit interactive mode.
+ >>>
+
+As you can see, when you press the *ESC Key*, a python prompt will be shown and
+the evolution will be paused.
+
+Now, *what you can do* with this prompt !?
+
+* See all the current population individuals
+* Change the individuals
+* Plot graphics of the current population
+* Data analysis, etc... python is your limit.
+
+.. note:: to use graphical plots you will obviously need the Matplotlib, see more information
+ in the :ref:`requirements` section for more information.
+
+Inspecting the population
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is a session example: ::
+
+ ## Pyevolve v.0.6 - Interactive Mode ##
+ Press CTRL-Z to quit interactive mode.
+ >>> dir()
+ ['__builtins__', 'ga_engine', 'it', 'population', 'pyevolve']
+ >>>
+ >>> population
+ - GPopulation
+ Population Size: 80
+ Sort Type: Scaled
+ Minimax Type: Maximize
+ Slot [Scale Method] (Count: 1)
+ Name: LinearScaling
+ Doc: Linear Scaling scheme
+
+ .. warning :: Linear Scaling is only for positive raw scores
+
+
+
+ - Statistics
+ Minimum raw score = 10.00
+ Minimum fitness = 13.18
+ Standard deviation of raw scores = 2.71
+ Maximum fitness = 19.92
+ Maximum raw score = 23.00
+ Fitness average = 16.60
+ Raw scores variance = 7.36
+ Average of raw scores = 16.60
+
+ >>> len(population)
+ 80
+ >>> individual = population[0]
+ >>> individual
+ - GenomeBase
+ Score: 23.000000
+ Fitness: 19.920000
+
+ Slot [Evaluator] (Count: 1)
+ Name: eval_func
+ Slot [Initializator] (Count: 1)
+ Name: G1DListInitializatorInteger
+ Doc: Integer initialization function of G1DList
+
+ This initializator accepts the *rangemin* and *rangemax* genome parameters.
+
+
+ Slot [Mutator] (Count: 1)
+ Name: G1DListMutatorSwap
+ Doc: The mutator of G1DList, Swap Mutator
+ Slot [Crossover] (Count: 1)
+ Name: G1DListCrossoverSinglePoint
+ Doc: The crossover of G1DList, Single Point
+
+ .. warning:: You can't use this crossover method for lists with just one element.
+
+
+
+ - G1DList
+ List size: 50
+ List: [0, 5, 6, 7, 2, 0, 8, 6, 0, 0, 8, 7, 5, 6, 6, 0, 0, 3, 0, 4, 0, 0, 9, 0, 9, 2, 0, 0, 4, 2
+ , 5, 0, 0, 2, 0, 0, 0, 1, 8, 7, 0, 8, 9, 0, 8, 0, 0, 0, 9, 0]
+
+The exposed modules and objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The :mod:`Interaction` module is imported with the name "it", you can see
+it's contents by calling the python native *dir()*: ::
+
+ >>> dir()
+ ['__builtins__', 'ga_engine', 'it', 'population', 'pyevolve']
+
+The namespace has the following modules:
+
+ *ga_engine*
+ The :class:`GSimpleGA.GSimpleGA` instance, the GA Engine.
+
+ *it*
+ The :mod:`Interaction` module, with the utilities and graph
+ plotting functions.
+
+ *population*
+ The current population.
+
+ *pyevolve*
+ The main namespace, the :mod:`pyevolve` module.
+
+**Using the "it" module**
+
+ *Plotting the current population raw scores histogram*
+
+ >>> it.plotHistPopScore(population)
+
+ .. image:: imgs/iteract_histogram.png
+ :align: center
+
+ *Plotting the current population raw scores distribution*
+
+ >>> it.plotPopScore(population)
+
+ .. image:: imgs/iteract_plotraw.png
+ :align: center
+
+ *Get all the population raw scores*
+
+ >>> popScores = it.getPopScores(population)
+ >>> popScores
+ [17.0, 17.0, 16.0, 15.0, 13.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 9.0,
+ 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0,
+ 8.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 6.0, 6.0, 6.0, 6.0, 6.0, 5.0, 5.0
+ , 5.0, 5.0, 5.0, 5.0, 5.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 3.0, 3.0, 3.0, 3.0]
+
+Extending Pyevolve
+---------------------------------------------------------------------------
+
+
+Creating the representation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The first thing you must do is to view the source code of the :class:`GenomeBase.GenomeBase` class
+or the source of the :class:`G1DBinaryString.G1DBinaryString` class; they are very
+simple to understand.
+
+These are the steps to extend Pyevolve with a new representation:
+
+ 1) Create the chromosome representation class
+ 2) Create the initializator for your chromosome
+ 3) Create the genetic operators
+
+ 4) Create the Mutator
+ 5) Create the Crossover
+
+Well, let's begin with the creation of the elegant **1D Binary String** chromosome. This
+chromosome is nothing more than a simple array of '0's or '1's, like so: *"001001000"*.
+
+.. note:: This 1D Binary String chromosome is an Pyevolve existing chromosome, of course, in the
+ Pyevolve implementation we have more features that we will implement here in this simple
+ example.
+
+All of our new chromosomes **must** extend the base class called :class:`GenomeBase.GenomeBase`,
+this class contains the basic slots for the genetic operators and all the internal stuff that
+you don't need to care about.
+
+Let's code the initial draft of our chromosome class: ::
+
+ from GenomeBase import GenomeBase
+
+ class G1DBinaryString(GenomeBase):
+ pass
+
+
+As you can see, we have imported the :class:`GenomeBase.GenomeBase` class from the :mod:`GenomeBase`
+module and we have created the *G1DBinaryString* class extending the base class.
+
+The next step is to create our constructor method for our class. I'll show it first and explain later: ::
+
+ def __init__(self, length=10):
+ GenomeBase.__init__(self)
+ self.genomeString = []
+ self.stringLength = length
+ self.initializator.set(Consts.CDefG1DBinaryStringInit)
+ self.mutator.set(Consts.CDefG1DBinaryStringMutator)
+ self.crossover.set(Consts.CDefG1DBinaryStringCrossover)
+
+
+Well, we start by calling the base class constructor and then creating an internal list to hold
+our '0's and '1's. It is important to note that we don't initialize the list, this will be done
+by our initializator function, and it is because of this that we must keep as an internal attribute
+the length of your 1D Binary String.
+
+Next, we set our initializator, mutator and crossover to constants. These constants have just
+the functions of our genetic operators, but if you want, you can set them later. In this example,
+we will use the defaults for the G1D Binary String.
+
+.. note:: The attributes self.initializator, self.mutator and self.crossover are all inherited
+ from the GenomeBase class. They are all function slots (:class:`FunctionSlot.FunctionSlot`).
+
+Now, you *must* provide the **copy()** and **clone()** methods for your chromosome, because they
+are used to replicate the chromosome over the population or when needed by some genetic operators
+such as reproduction.
+
+The *copy()* method is very simple. What you need to do is to create a method that copy the
+contents of your chromosome to another chromosome of the G1DBinaryString class.
+
+Here is our *copy()* method: ::
+
+ def copy(self, g):
+ """ Copy genome to 'g' """
+ GenomeBase.copy(self, g)
+ g.stringLength = self.stringLength
+ g.genomeString = self.genomeString[:]
+
+As you can see, we first call the base class *copy()* method and later we copy
+our string length attribute and our internal *genomeString*, which is our list
+of '0's and '1's.
+
+.. warning:: It is very important to note that you must **COPY** and not just create
+ a reference to the object. On the line that we have the *self.genomeString[:]*,
+ if you use just *self.genomeString*, you will create a **REFERENCE** to this
+ object and not a copy. This a simple warning, but can avoid many headaches.
+
+The next step is to create our *clone()* method. The clone method, as the name says, is a
+method which return another instance of the current chromosome with the same contents.
+
+Let's code it: ::
+
+ def clone(self):
+ """ Return a new instace copy of the genome """
+ newcopy = G1DBinaryString(self.stringLength)
+ self.copy(newcopy)
+ return newcopy
+
+We simply create a new instance and use the *copy()* method that we have created to copy
+the instance contents.
+
+Ready ! We have our first representation chromosome. You can add many more features by
+implementing python operators such as *__getitem__*, *__setitem__*.
+
+Creating the initializator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sorry, not written yet.
+
+Creating the mutator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sorry, not written yet.
+
+Creating the crossover
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The file Crossovers.py implements the crossover methods available in
+Pyevolve. So, that is where you should look to implement your new
+crossover method. The process of adding a new crossover method is as
+follows:
+
+1) Create a new method such that the name reflects the type of chromosome
+ representation it works with, and the crossover method name. For example,
+ :func:`Crossovers.G1DListCrossoverRealSBX`, can work with 1D List representations
+ and it operates on real values and it is the SBX crossover operator.
+
+2) The method must accept two parameters, 'genome' and 'args'.
+
+3) From 'args', get the two parents which will take part in the crossover,
+ gMom and gDad.
+
+4) Once you have gMom and gDad, use them to create the two children, sister
+ and brother.
+
+5) Simply return the sister and brother.
+
+Any constants that your crossover method uses should be defined in Consts.py (:mod:`Consts`).
+
+Genetic Programming Tutorial
+---------------------------------------------------------------------------
+
+In the release 0.6 of Pyevolve, the new Genetic Programming core was added to the framework.
+In the :ref:`pyevolve-example18` you'll see how simple and easy the Pyevolve GP core is
+when compared with other statically-typed languages.
+
+Here is a simple example: ::
+
+ from pyevolve import Util
+ from pyevolve import GTree
+ from pyevolve import GSimpleGA
+ from pyevolve import Consts
+ import math
+
+ rmse_accum = Util.ErrorAccumulator()
+
+ def gp_add(a, b): return a+b
+ def gp_sub(a, b): return a-b
+ def gp_mul(a, b): return a*b
+ def gp_sqrt(a): return math.sqrt(abs(a))
+
+ def eval_func(chromosome):
+ global rmse_accum
+ rmse_accum.reset()
+ code_comp = chromosome.getCompiledCode()
+
+ for a in xrange(0, 5):
+ for b in xrange(0, 5):
+ evaluated = eval(code_comp)
+ target = math.sqrt((a*a)+(b*b))
+ rmse_accum += (target, evaluated)
+
+ return rmse_accum.getRMSE()
+
+ def main_run():
+ genome = GTree.GTreeGP()
+ genome.setParams(max_depth=4, method="ramped")
+ genome.evaluator += eval_func
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_prefix = "gp")
+
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(50)
+ ga.setCrossoverRate(1.0)
+ ga.setMutationRate(0.25)
+ ga.setPopulationSize(800)
+
+ ga(freq_stats=10)
+ best = ga.bestIndividual()
+ print best
+
+ if __name__ == "__main__":
+ main_run()
+
+Let's work now step by step on the code to learn what each building block means. The
+first part you see the imports: ::
+
+ from pyevolve import Util
+ from pyevolve import GTree
+ from pyevolve import GSimpleGA
+ from pyevolve import Consts
+ import math
+
+The :mod:`Util` module is where we'll find many utilities functions and classes like :class:`Util.ErrorAccumulator`.
+The :mod:`GTree` is where the :class:`GTree.GTreeGP` class resides, which is the main genome used by the GP core of Pyevolve.
+Note that we are importing the :mod:`GSimpleGA` module, in fact, the GA core will detect when you use a Genetic Programming
+genome and will act as the GP core. The modules :mod:`Consts` and :mod:`math` imported here are for auxiliary use only.
+Next we have: ::
+
+ rmse_accum = Util.ErrorAccumulator()
+
+Here we instantiate the :class:`Util.ErrorAccumulator`, which is a simple accumulator for errors. It has methods for getting
+:term:`Adjusted Fitness`, `Mean Square Error <http://en.wikipedia.org/wiki/Mean_squared_error>`_,
+`Root Mean Square Error <http://en.wikipedia.org/wiki/Root_mean_squared_error>`_, mean, squared or non-squared error measures.
+In the next block we define some GP operators: ::
+
+ def gp_add(a, b): return a+b
+ def gp_sub(a, b): return a-b
+ def gp_mul(a, b): return a*b
+ def gp_sqrt(a): return math.sqrt(abs(a))
+
+Observe that they are simple Python functions starting with the "gp" prefix. This is important if you want
+Pyevolve to automatically add them as non-terminals of the GP core. As you can note, the square root is a protected
+square root, since it uses the absolute value of "a" (we don't have square root of negative numbers, except in the
+complex analysis). You can define any other function you want.
+Later we have the declaration of the :term:`Evaluation function` for the GP core: ::
+
+ def eval_func(chromosome):
+ global rmse_accum
+ rmse_accum.reset()
+ code_comp = chromosome.getCompiledCode()
+
+ for a in xrange(0, 5):
+ for b in xrange(0, 5):
+ evaluated = eval(code_comp)
+ target = math.sqrt((a*a)+(b*b))
+ rmse_accum += (target, evaluated)
+
+ return rmse_accum.getRMSE()
+
+
+As you see, the :func:`eval_func` receives one parameter, the chromosome (the GP Tree in our case, an instance of the
+:class:`GTree.GTreeGP` class). We first declare the global error accumulator and reset it, since we'll start to evaluate
+a new individual, a new "program". In the line where we call :meth:`GTree.GTreeGP.getCompiledCode()`, here is what
+happens: Pyevolve will get the pre-ordered expression of the GP Tree and then will compile it into Python bytecode,
+and will return to you an object of the type "code". This object can then be executed using the Python native :func:`eval`
+function. Why compile it to bytecode ? Because if we don't compile the program into Python bytecode, we will need
+to parse the Tree every time we want to evaluate our program using defined variables, and since this is a commom use
+of the GP program, this is the fastest way we can do it in pure Python.
+
+
+In the next block, we simply iterate using two variables "a" and "b".
+
+.. note:: Please note that the variable names here is the same that we will use as terminals later.
+
+What you see now is the evaluation of the "code_comp" (which is the GP individual) and the evaluation of the objective
+function in which we want to fit (the Pythagorean theorem). Next we simply add the "target" value we got from the
+Pythagorean theorem and the "evaluated" value of the individual to the Error Accumulator.
+In the end of the evaluation function, we return the `Root Mean Square Error <http://en.wikipedia.org/wiki/Root_mean_squared_error>`_.
+If you don't like to add the evaluated and the target values using a tuple, you can use the :meth:`Util.ErrorAccumulator.append`
+method, which will give the same results.
+
+Next we start to define our :func:`main_run` function: ::
+
+ def main_run():
+ genome = GTree.GTreeGP()
+ genome.setParams(max_depth=4, method="ramped")
+ genome.evaluator.set(eval_func)
+
+The first thing we instantiate here is the :class:`GTree.GTreeGP` class (the GP individual, the Tree). Next
+we set some parameters of the GTreeGP. The first is the "max_depth", which is used by genetic operators
+and initializators to control bloat; in this case, we use 4, which means that no Tree with a height > 4 will
+grow. Next we set the "method", this is the initialization method, and the values accepted here depends of
+the initialization method used, since we do not have specified the initialization method, Pyevolve will
+use the default, which is the :func:`Initializators.GTreeGPInitializator` (it accepts "grow", "full" and "ramped"
+methods for Tree initialization. And in the last line of this block, we set the previously defined evaluation
+function called :func:`eval_func`.
+In the next block we then instantiate the GSimpleGA core and set some parameters: ::
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_prefix = "gp")
+
+The "ga" object will hold an instance of the :class:`GSimpleGA.GSimpleGA` class, which is the core for both
+Genetic Algorithms and Genetic Programming. Pyevolve will automatically detect if you are creating a environment
+for a GP or for a GA. Next we set some parameters of the core, the first is a list called "gp_terminals".
+The "gp_terminals" will hold the "variables" or in GP vocabulary . Note that the
+name of the terminals are the same we used in our evaluation function called :func:`eval_func`. The next step
+is to define the prefix of the GP operators (functions) or the :term:`Non-terminal node`. Pyevolve will automatically
+search for all functions defined in the module which starts with "gp" (example: gp_sub, gp_add, gp_IHateJava, etc...)
+and will add these functions as the non-terminal nodes of the GP core.
+
+The next part of the code is almost the same as used in the Genetic Algorithms applications, they are the EA parameters
+to setup and start the evolution: ::
+
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(50)
+ ga.setCrossoverRate(1.0)
+ ga.setMutationRate(0.25)
+ ga.setPopulationSize(800)
+
+ ga(freq_stats=10)
+ best = ga.bestIndividual()
+ print best
+
+And in the last part of the source code, we have: ::
+
+ if __name__ == "__main__":
+ main_run()
+
+
+This part is important, since Pyevolve needs to know some information about objects in the main module using instrospection.
+You **NEED** to declare this check, the :mod:`multiprocessing` module of Python only works with this too, so if
+you're planning to use it, please do not forget it.
+
+And that's it, you have completed your first GP program.
+
+Visualizing individuals
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Pyevolve comes with a plotting utility to create images of your GP individuals. It uses
+"pydot" and "Graphviz" to create those images. For more information, see the :ref:`requirements` section.
+What you need to change to see, for example, the first 3 best individuals of your first generation is to
+add a :term:`Step callback function` into the code. Let's first define the callback function: ::
+
+ def step_callback(gp_engine):
+ if gp_engine.getCurrentGeneration() == 0:
+ GTree.GTreeGP.writePopulationDot(gp_engine, "trees.jpg", start=0, end=3)
+
+The code is self-explanatory, the parameter is the GP core, first we check if it is the first generation and
+then we use the :meth:`GTree.GTreeGP.writePopulationDot` method to write to the "trees.jpg" file, the
+range from 0 and 3 individuals of the population. Then in the main function where we instantiate the GP core,
+we simply use: ::
+
+ ga.stepCallback.set(step_callback)
+
+And the result will be:
+
+.. image:: imgs/gp_trees_img1.jpg
+ :align: center
+
+Snippets
+---------------------------------------------------------------------------
+
+Here are some snippets to help you.
+
+Using two mutators at same time
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ To use two mutators at same time, you simple add one more to the mutator
+ function slot, like this:
+
+ >>> genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+ >>> genome.mutator.add(Mutators.G1DListMutatorSwap)
+
+ The first line will set the :func:`Mutators.G1DListMutatorRealGaussian`, and the second line
+ add one more mutator, the :func:`Mutators.G1DListMutatorSwap`.
+
+ As you can see, it's very simple and easy, and you will have two mutation
+ operators at same time.
+
+ If you want just one of these mutators (picked at random) to be executed at
+ the mutation process, set the *random apply* parameter of the :class:`FunctionSlot.FunctionSlot`
+ class to True ::
+
+ >>> genome.mutator.setRandomApply(true)
+
+Using one allele for all list (chromosome) elements (genes)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Sometimes you want to use just one allele type for all genes
+ on the 1D List or other chromosomes. You simply add one allele type
+ and set the *homogeneous* flag to **True**:
+
+ >>> setOfAlleles = GAllele.GAlleles(homogeneous=True)
+ >>> lst = [ "1", "two", 0, 777 ]
+ >>> a = GAllele.GAlleleList(lst)
+ >>> setOfAlleles.add(a)
+
+ Done. Your setOfAlleles is the :class:`GAllele.GAlleles` class instance with
+ the *lst* ([ "1", "two", 0, 777 ]) as alleles in all genes.
+
+
+Changing the selection method
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ To change the default selection method, you must do this:
+
+ >>> ga = GSimpleGA.GSimpleGA(genome)
+ >>> ga.selector.set(Selectors.GTournamentSelector)
+
+ In this example, we change the selection method to the
+ :func:`Selectors.GTournamentSelector`, the Tournament Selector.
+
+
+Repeating an evolution with a specific seed
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Using a specific seed, you can guarantee that the evolution will be always
+ the same, no matter the number of executions you make.
+ To initialize the GA Engine with the specific seed, use the *seed* parameter
+ when instantiating the :class:`GSimpleGA.GSimpleGA` class: ::
+
+ ga_engine = GSimpleGA(genome, 123)
+ # or
+ ga_engine = GSimpleGA(genome, seed=123)
+
+ The value *123* will be passed as the seed to the random function of the GA Engine.
+
+Writing the evolution statistics to a CSV File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ You can write all the statistics of an evolution to a CSV (Comma Separated Values)
+ file using the DB Adapter called :class:`DBAdapters.DBFileCSV`, just create
+ an instance of the adapter and attach it to the GA Engine: ::
+
+ csv_adapter = DBFileCSV(identify="run1", filename="stats.csv")
+ ga_engine.setDBAdapter(csv_adapter)
+
+ Now ! Now, when you run your GA, all the stats will be dumped to the CSV file.
+ You can set the frequency in which the stats will be dumped, just use the parameter
+ *frequency* of the DBFileCSV.
+
+
+Use the HTTP Post to dump GA statistics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ With the :class:`DBAdapters.DBURLPost`, you can call an URL with the
+ population statistics in every generation or at specific generation
+ of the evolution: ::
+
+ urlpost_adapter = DBURLPost("http://localhost/post.py", identify="run1", frequency=100)
+ ga_engine.setDBAdapter(urlpost_adapter)
+
+ Now, the URL "http://localhost/post.py" will be called with the statistics params in
+ every 100 generations. By default, the adapter will use the HTTP POST method to send
+ the parameters, but you can use GET method setting the *post* paramter to *False*.
+
+ See the mod:`Statistics` and :class:`DBAdapters.DBURLPost` documentation.
+
+Using two or more :term:`evaluation function`
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ To use two or more :term:`evaluation function`, you can just add all
+ the evaluators to the slot: ::
+
+ genome.evaluator.set(eval_func1)
+ genome.evaluator.add(eval_func2)
+
+ The resulting raw score of the genome, when evaluated using more than
+ one evaluation function, will be the sum of all returned scores.
+
+ .. note:: the method *set* of the function slot remove all previous
+ functions added to the slot.
+
+Real-time statistics visualization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ You have three options to view the statistics while in the course
+ of the evolution:
+
+ **Console statistics**
+
+ You can view the statistics by setting the *freq_stats* parameter
+ of the :meth:`GSimpleGA.GSimpleGA.evolve` method. It will dump
+ the statistics in the console.
+
+ **Using the sqlite3 DB Adapter**
+
+ You can use the :class:`DBAdapters.DBSQLite` DB Adapter and set
+ the *commit_freq* to a low value, so you can use the Graphical
+ Plotting Tool of Pyevolve to create graphics while evolving.
+
+
+ **Using the VPython DB Adapter**
+
+ Use the :class:`DBAdapters.DBVPythonGraph` DB Adapter, this DB
+ Adapter will show four statistical graphs, it is fast and
+ easy to use.
+
+.. _snippet_gp_explicit:
+
+How to manually add non-terminal functions to Genetic Programming core
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+When you set Pyevolve to automatically catch non-terminal functions for your GP
+core you do something like this: ::
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_prefix = "gp")
+
+The "gp_function_prefix" parameter tells Pyevolve to catch any functions starting
+with "gp". But there are times that you want to add each function manually, so
+you just need to add a dictionary parameter called "gp_function_set", like this: ::
+
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_set = {"gp_add" :2,
+ "gp_sub" :2,
+ "gp_sqrt":1})
+
+Note the "gp_function_set" dictionary parameter which holds as key the function
+name and for the value, the number of arguments from that function, in this case
+we have "gp_add" with 2 parameters, "gp_sub" with 2 and "gp_sqrt" with just one.
+
+
+Passing extra parameters to the individual
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Sometimes we want to add extra parameters which we need the individuals must
+carry, in this case, we can use the method :meth:`GenomeBase.GenomeBase.setParams`
+to set internal parameters of the individual and the method :meth:`GenomeBase.GenomeBase.getParam`
+to get it's parameters back, see an example: ::
+
+ def evaluation_function(genome):
+ parameter_a = genome.getParam("parameter_a")
+
+ def main():
+ # (...)
+ genome = G1DList.G1DList(20)
+ genome.setParams(rangemin=-5.2, rangemax=5.30, parameter_a="my_value")
+ # (...)
+
+.. note:: Due to performance issues, Pyevolve doesn't copy the internal parameters
+ into each new created individual, it simple references the original
+ parameters, this reduces memory and increases speed.
+
+Using ephemeral constants in Genetic Programming
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+You can use an ephemeral constant in Pyevolve GP core by using the "ephemeral:"
+prefix in your GP terminals, like in: ::
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setParams(gp_terminals = ['a', 'b', 'ephemeral:random.randint(1,10)'],
+ gp_function_prefix = "gp")
+
+In this example, the ephemeral constant will be an integer value between 1 and 10. You
+can use any method of the Python :mod:`random` module to specify the ephemeral constant.
+
+
diff --git a/docs/source/graphs.rst b/docs/source/graphs.rst
new file mode 100644
index 0000000..7b0a529
--- /dev/null
+++ b/docs/source/graphs.rst
@@ -0,0 +1,329 @@
+
+Graphical Analysis - Plots
+============================================================================
+
+Pyevolve comes with an Graphical Plotting Tool. This utility uses the great
+python plotting library called Matplotlib.
+
+.. seealso::
+
+ :ref:`requirements` section.
+
+You can find the Pyevolve plotting tool in your python Scripts directory, the
+tool is named **pyevolve_graph.py**.
+
+Graphical Plotting Tool Options
+---------------------------------------------------------------------------
+
+**pyevolve_graph.py**, installed in :file:`\\Python2{x}\\Scripts\\pyevolve_graph.py`.
+
+This is the documentation you get by calling the *--help* option: ::
+
+ Pyevolve 0.6rc1 - Graph Plot Tool
+ By Christian S. Perone
+
+ Usage: pyevolve_graph.py [options]
+
+ Options:
+ -h, --help show this help message and exit
+ -f FILENAME, --file=FILENAME
+ Database file to read (default is 'pyevolve.db').
+ -i IDENTIFY, --identify=IDENTIFY
+ The identify of evolution.
+ -o OUTFILE, --outfile=OUTFILE
+ Write the graph image to a file (don't use extension,
+ just the filename, default is png format, but you can
+ change using --extension (-e) parameter).
+ -e EXTENSION, --extension=EXTENSION
+ Graph image file format. Supported options (formats)
+ are: emf, eps, pdf, png, ps, raw, rgba, svg, svgz.
+ Default is 'png'.
+ -g GENRANGE, --genrange=GENRANGE
+ This is the generation range of the graph, ex: 1:30
+ (interval between 1 and 30).
+ -l LINDRANGE, --lindrange=LINDRANGE
+ This is the individual range of the graph, ex: 1:30
+ (individuals between 1 and 30), only applies to
+ heatmaps.
+ -c COLORMAP, --colormap=COLORMAP
+ Sets the Color Map for the graph types 8 and 9. Some
+ options are: summer, bone, gray, hot, jet, cooper,
+ spectral. The default is 'jet'.
+ -m, --minimize Sets the 'Minimize' mode, default is the Maximize
+ mode. This option makes sense if you are minimizing
+ your evaluation function.
+
+ Graph types:
+ This is the supported graph types
+
+ -0 Write all graphs to files. Graph types: 1, 2, 3, 4 and
+ 5.
+ -1 Error bars graph (raw scores).
+ -2 Error bars graph (fitness scores).
+ -3 Max/min/avg/std. dev. graph (raw scores).
+ -4 Max/min/avg graph (fitness scores).
+ -5 Raw and Fitness min/max difference graph.
+ -6 Compare best raw score of two or more evolutions (you
+ must specify the identify comma-separed list with
+ --identify (-i) parameter, like 'one, two, three'),
+ the maximum is 6 items.
+ -7 Compare best fitness score of two or more evolutions
+ (you must specify the identify comma-separed list with
+ --identify (-i) parameter, like 'one, two, three'),
+ the maximum is 6 items.
+ -8 Show a heat map of population raw score distribution
+ between generations.
+ -9 Show a heat map of population fitness score
+ distribution between generations.
+
+Usage
+---------------------------------------------------------------------------
+
+To use this graphical plotting tool, you need to use the :class:`DBAdapters.DBSQLite`
+adapter and create the database file. Pyevolve uses the "identify" concept. The value
+of this parameter means the same value used in the "identify" parameter of the DB Adapter.
+
+See this example: ::
+
+ sqlite_adapter = DBAdapters.DBSQLite(identify="ex1")
+ ga.setDBAdapter(sqlite_adapter)
+
+This DB Adapter attached to the GA Engine will create the database file named "pyevolve.db".
+
+.. seealso::
+
+ `Sqliteman, a tool for sqlite3 databases <http://sqliteman.com/>`_
+ I recommend the Sqliteman tool to open the database and see the contents or structure, if
+ you are interested.
+
+When you run your GA, all the statistics will be dumped to this database, and you will have an ID
+for this run, which is the identify parameter. So when you use the graph tool, it will read
+the statistics from this database file. The "identify" parameter is passed to the tool using
+the "-i" option, like this: ::
+
+ pyevolve_graph.py -i ex1 -1
+
+By default, this tool will use the database file named *pyevolve.db*, but you can change that
+using the "-f" option like this: ::
+
+ pyevolve_graph.py -i ex1 -1 -f another_db.db
+
+
+Usage Examples
+---------------------------------------------------------------------------
+
+**Writing graph to a file**
+
+ PDF File: ::
+
+ pyevolve_graph.py -i ex1 -1 -o graph_ex1 -e pdf
+
+ PNG File (default extension when using "-o" option): ::
+
+ pyevolve_graph.py -i ex1 -1 -o graph_ex1
+
+**Using the generation range** ::
+
+ # this command wil plot the evolution of the generations between 10 and 20.
+ pyevolve_graph.py -i ex1 -1 -g 10:20
+
+**When you have minimized the evaluation function** ::
+
+ pyevolve_graph.py -i ex1 -1 -m
+
+**To specify an identify list (graphs "-6" and "-7")** ::
+
+ pyevolve_graph.py -i ex1_run1,ex1_run2,ex1_run3 -6
+
+.. _graphs_screens:
+
+Graph Types and Screenshots
+---------------------------------------------------------------------------
+
+Here are described all the graph types and some screenshots.
+
+Error bars graph (raw scores) / "-1" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In this graph, you will find the generations on the x-axis and the raw scores on
+the y-axis. The green vertical bars represent the **maximum and the minimum raw
+scores** of the current population at generation indicated in the x-axis. The blue
+line between them is the **average raw score** of the population.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -1
+
+.. image:: imgs/graph_1_ex1.png
+ :align: center
+
+Error bars graph (fitness scores) / "-2" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The difference between this graph option and the "-1" option is that we
+use the **fitness scores** instead of the raw scores.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -2
+
+.. image:: imgs/graph_2_ex1.png
+ :align: center
+
+.. note:: This graph is from a GA using the **Linear Scaling** scheme and the **Roulette
+ Wheel** selection method.
+
+Max/min/avg/std. dev. graph (raw scores) / "-3" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In this graph we have the green line showing the maximum raw score at the
+generation in the x-axis, the red line shows the minimum raw score, and the
+blue line shows the average raw scores. The green shaded region represents
+the difference between our max. and min. raw scores. The black line shows the
+standard deviation of the average raw scores.
+We also have some annotations like the maximum raw score, maximum std. dev.
+and the min std. dev.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -3
+
+.. image:: imgs/graph_3_ex1.png
+ :align: center
+
+.. note:: We can see in this graph the minimum standard deviation at the
+ convergence point. The GA Engine stopped the evolution
+ using these criteria.
+
+
+Max/min/avg graph (fitness scores) / "-4" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This graph shows the maximum fitness score from the population at the
+x-axis generation using the green line. The red line shows the minimum
+fitness score and the blue line shows the average fitness score from
+the population. The green shaded region between the green and red line
+shows the difference between the best and worst individual of population.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -4
+
+.. image:: imgs/graph_4_ex1.png
+ :align: center
+
+.. note:: This graph is from a GA using the **Linear Scaling** scheme and the **Roulette
+ Wheel** selection method.
+
+Min/max difference graph, raw and fitness scores / "-5" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In this graph, we have two subplots, the first is the difference between
+the best individual raw score and the worst individual raw score. The
+second graph shows the difference between the best individual fitness score
+and the worst individual fitness score
+Both subplots show the generation on the x-axis and the score difference
+in the y-axis.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -5
+
+.. image:: imgs/graph_5_ex1.png
+ :align: center
+
+
+Compare best raw score of two or more evolutions / "-6" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This graph is used to compare two or more evolutions (the max is 6 evolutions)
+of the same or different GA.
+
+It uses a different color for each identify you use, in the example, you can
+see the three evolutions (green, blue and red lines) of the same GA.
+
+All the lines have a shaded transparent region of the same line color, they
+represent the difference between the maximum and the minimum raw scores of
+the evolution.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1_run1,ex1_run2,ex1_run3 -6
+
+.. image:: imgs/graph_6_ex1.png
+ :align: center
+
+.. note:: The evolution identified by "ex1_run3" (red color) is the
+ evolution in which the best raw score (20) was got first at the
+ generation 80, compared to the other runs.
+
+Compare best fitness score of two or more evolutions / "-7" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The difference between this graph option and the "-6" option is that we are
+using the **fitness scores** instead of the raw scores.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1_run1,ex1_run2,ex1_run3 -7
+
+.. image:: imgs/graph_7_ex1.png
+ :align: center
+
+Heat map of population raw score distribution / "-8" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The heat map graph is a plot with the population individual plotted as the
+x-axis and the generation plotted in the y-axis. On the right side we have
+a legend with the color/score relation. As you can see, on the initial
+populations, the last individals scores are the worst (represented in this
+colormap with the dark blue). To create this graph, we use the Gaussian
+interpolation method.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -8
+
+.. image:: imgs/graph_8_ex1.png
+ :align: center
+
+Using another colormap like the "spectral", we can see more interesting
+patterns:
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -8 -c spectral
+
+.. image:: imgs/graph_8_ex1_spec.png
+ :align: center
+
+.. warning:: This graph generation can be very slow if you have too many generations.
+ You can use the "-g" option to limit your generations.
+
+Heat map of population fitness score distribution / "-9" option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The difference between this graph option and the "-8" option is that we are
+using the **fitness scores** instead of the raw scores.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -9
+
+.. image:: imgs/graph_9_ex1.png
+ :align: center
+
+.. note:: Here you can note some interesting things, in this graph of the scaled
+ score, the individual's fitnesses seem almost equaly distributed in the
+ population.
+
+Now, the same plot using the "hot" colormap.
+
+This graph was generated using: ::
+
+ pyevolve_graph.py -i ex1 -9 -c hot
+
+.. image:: imgs/graph_9_ex1_hot.png
+ :align: center
+
+.. warning:: This graph generation can be very slow if you have too many generations.
+ You can use the "-g" option to limit your generations.
\ No newline at end of file
diff --git a/docs/source/imgs/Thumbs.db b/docs/source/imgs/Thumbs.db
new file mode 100644
index 0000000..e681c66
Binary files /dev/null and b/docs/source/imgs/Thumbs.db differ
diff --git a/docs/source/imgs/brasil_flag.jpg b/docs/source/imgs/brasil_flag.jpg
new file mode 100644
index 0000000..d3d01b6
Binary files /dev/null and b/docs/source/imgs/brasil_flag.jpg differ
diff --git a/docs/source/imgs/email_amit.png b/docs/source/imgs/email_amit.png
new file mode 100644
index 0000000..2c9c609
Binary files /dev/null and b/docs/source/imgs/email_amit.png differ
diff --git a/docs/source/imgs/email_boris.png b/docs/source/imgs/email_boris.png
new file mode 100644
index 0000000..071d16b
Binary files /dev/null and b/docs/source/imgs/email_boris.png differ
diff --git a/docs/source/imgs/email_christian_kastner.png b/docs/source/imgs/email_christian_kastner.png
new file mode 100644
index 0000000..1290f8d
Binary files /dev/null and b/docs/source/imgs/email_christian_kastner.png differ
diff --git a/docs/source/imgs/email_henrik.png b/docs/source/imgs/email_henrik.png
new file mode 100644
index 0000000..cb942c6
Binary files /dev/null and b/docs/source/imgs/email_henrik.png differ
diff --git a/docs/source/imgs/email_jelle.png b/docs/source/imgs/email_jelle.png
new file mode 100644
index 0000000..0b8516f
Binary files /dev/null and b/docs/source/imgs/email_jelle.png differ
diff --git a/docs/source/imgs/ex1equation.png b/docs/source/imgs/ex1equation.png
new file mode 100644
index 0000000..48fa386
Binary files /dev/null and b/docs/source/imgs/ex1equation.png differ
diff --git a/docs/source/imgs/ex_12_tsp_result.png b/docs/source/imgs/ex_12_tsp_result.png
new file mode 100644
index 0000000..4944212
Binary files /dev/null and b/docs/source/imgs/ex_12_tsp_result.png differ
diff --git a/docs/source/imgs/gp_trees_img1.jpg b/docs/source/imgs/gp_trees_img1.jpg
new file mode 100644
index 0000000..53a8813
Binary files /dev/null and b/docs/source/imgs/gp_trees_img1.jpg differ
diff --git a/docs/source/imgs/graph_1_ex1.png b/docs/source/imgs/graph_1_ex1.png
new file mode 100644
index 0000000..443eba3
Binary files /dev/null and b/docs/source/imgs/graph_1_ex1.png differ
diff --git a/docs/source/imgs/graph_2_ex1.png b/docs/source/imgs/graph_2_ex1.png
new file mode 100644
index 0000000..570e5a1
Binary files /dev/null and b/docs/source/imgs/graph_2_ex1.png differ
diff --git a/docs/source/imgs/graph_3_ex1.png b/docs/source/imgs/graph_3_ex1.png
new file mode 100644
index 0000000..d71005e
Binary files /dev/null and b/docs/source/imgs/graph_3_ex1.png differ
diff --git a/docs/source/imgs/graph_4_ex1.png b/docs/source/imgs/graph_4_ex1.png
new file mode 100644
index 0000000..4013ee8
Binary files /dev/null and b/docs/source/imgs/graph_4_ex1.png differ
diff --git a/docs/source/imgs/graph_5_ex1.png b/docs/source/imgs/graph_5_ex1.png
new file mode 100644
index 0000000..7d1679a
Binary files /dev/null and b/docs/source/imgs/graph_5_ex1.png differ
diff --git a/docs/source/imgs/graph_6_ex1.png b/docs/source/imgs/graph_6_ex1.png
new file mode 100644
index 0000000..d1971c5
Binary files /dev/null and b/docs/source/imgs/graph_6_ex1.png differ
diff --git a/docs/source/imgs/graph_7_ex1.png b/docs/source/imgs/graph_7_ex1.png
new file mode 100644
index 0000000..565f634
Binary files /dev/null and b/docs/source/imgs/graph_7_ex1.png differ
diff --git a/docs/source/imgs/graph_8_ex1.png b/docs/source/imgs/graph_8_ex1.png
new file mode 100644
index 0000000..b6aa260
Binary files /dev/null and b/docs/source/imgs/graph_8_ex1.png differ
diff --git a/docs/source/imgs/graph_8_ex1_spec.png b/docs/source/imgs/graph_8_ex1_spec.png
new file mode 100644
index 0000000..91019de
Binary files /dev/null and b/docs/source/imgs/graph_8_ex1_spec.png differ
diff --git a/docs/source/imgs/graph_9_ex1.png b/docs/source/imgs/graph_9_ex1.png
new file mode 100644
index 0000000..a21c526
Binary files /dev/null and b/docs/source/imgs/graph_9_ex1.png differ
diff --git a/docs/source/imgs/graph_9_ex1_hot.png b/docs/source/imgs/graph_9_ex1_hot.png
new file mode 100644
index 0000000..02a164c
Binary files /dev/null and b/docs/source/imgs/graph_9_ex1_hot.png differ
diff --git a/docs/source/imgs/iteract_histogram.png b/docs/source/imgs/iteract_histogram.png
new file mode 100644
index 0000000..41e2e04
Binary files /dev/null and b/docs/source/imgs/iteract_histogram.png differ
diff --git a/docs/source/imgs/iteract_plotraw.png b/docs/source/imgs/iteract_plotraw.png
new file mode 100644
index 0000000..be6b5fc
Binary files /dev/null and b/docs/source/imgs/iteract_plotraw.png differ
diff --git a/docs/source/imgs/logo.png b/docs/source/imgs/logo.png
new file mode 100644
index 0000000..05e6267
Binary files /dev/null and b/docs/source/imgs/logo.png differ
diff --git a/docs/source/imgs/original/Thumbs.db b/docs/source/imgs/original/Thumbs.db
new file mode 100644
index 0000000..c2f3a0f
Binary files /dev/null and b/docs/source/imgs/original/Thumbs.db differ
diff --git a/docs/source/imgs/original/graph_1_ex1.png b/docs/source/imgs/original/graph_1_ex1.png
new file mode 100644
index 0000000..e9cc194
Binary files /dev/null and b/docs/source/imgs/original/graph_1_ex1.png differ
diff --git a/docs/source/imgs/original/graph_2_ex1.png b/docs/source/imgs/original/graph_2_ex1.png
new file mode 100644
index 0000000..f756756
Binary files /dev/null and b/docs/source/imgs/original/graph_2_ex1.png differ
diff --git a/docs/source/imgs/original/graph_3_ex1.png b/docs/source/imgs/original/graph_3_ex1.png
new file mode 100644
index 0000000..26fa801
Binary files /dev/null and b/docs/source/imgs/original/graph_3_ex1.png differ
diff --git a/docs/source/imgs/original/graph_4_ex1.png b/docs/source/imgs/original/graph_4_ex1.png
new file mode 100644
index 0000000..1f5d987
Binary files /dev/null and b/docs/source/imgs/original/graph_4_ex1.png differ
diff --git a/docs/source/imgs/original/graph_5_ex1.png b/docs/source/imgs/original/graph_5_ex1.png
new file mode 100644
index 0000000..19cfb58
Binary files /dev/null and b/docs/source/imgs/original/graph_5_ex1.png differ
diff --git a/docs/source/imgs/original/graph_6_ex1.png b/docs/source/imgs/original/graph_6_ex1.png
new file mode 100644
index 0000000..501e163
Binary files /dev/null and b/docs/source/imgs/original/graph_6_ex1.png differ
diff --git a/docs/source/imgs/original/graph_7_ex1.png b/docs/source/imgs/original/graph_7_ex1.png
new file mode 100644
index 0000000..05451d6
Binary files /dev/null and b/docs/source/imgs/original/graph_7_ex1.png differ
diff --git a/docs/source/imgs/original/graph_8_ex1.png b/docs/source/imgs/original/graph_8_ex1.png
new file mode 100644
index 0000000..720b634
Binary files /dev/null and b/docs/source/imgs/original/graph_8_ex1.png differ
diff --git a/docs/source/imgs/original/graph_8_ex1_spec.png b/docs/source/imgs/original/graph_8_ex1_spec.png
new file mode 100644
index 0000000..2a26e91
Binary files /dev/null and b/docs/source/imgs/original/graph_8_ex1_spec.png differ
diff --git a/docs/source/imgs/original/graph_9_ex1.png b/docs/source/imgs/original/graph_9_ex1.png
new file mode 100644
index 0000000..f4f0141
Binary files /dev/null and b/docs/source/imgs/original/graph_9_ex1.png differ
diff --git a/docs/source/imgs/original/graph_9_ex1_hot.png b/docs/source/imgs/original/graph_9_ex1_hot.png
new file mode 100644
index 0000000..3b1d47a
Binary files /dev/null and b/docs/source/imgs/original/graph_9_ex1_hot.png differ
diff --git a/docs/source/imgs/original/iteract_histogram.png b/docs/source/imgs/original/iteract_histogram.png
new file mode 100644
index 0000000..1f37e83
Binary files /dev/null and b/docs/source/imgs/original/iteract_histogram.png differ
diff --git a/docs/source/imgs/original/iteract_plotraw.png b/docs/source/imgs/original/iteract_plotraw.png
new file mode 100644
index 0000000..23aee04
Binary files /dev/null and b/docs/source/imgs/original/iteract_plotraw.png differ
diff --git a/docs/source/imgs/pyevolve_logo_new.png b/docs/source/imgs/pyevolve_logo_new.png
new file mode 100644
index 0000000..b714245
Binary files /dev/null and b/docs/source/imgs/pyevolve_logo_new.png differ
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..fb38723
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,71 @@
+
+
+Welcome to Pyevolve documentation !
+=================================================
+
+.. raw:: html
+
+ <div id="slider">
+ <img src="_static/index_slide_1.jpg" alt="" />
+ <img src="_static/index_slide_2.jpg" alt="" />
+ <img src="_static/index_slide_3.jpg" alt="" />
+ <img src="_static/index_slide_4.jpg" alt="" />
+ </div>
+
+"*We can allow satellites, planets, suns, universe, nay whole systems of universe, to
+be governed by laws, but the smallest insect, we wish to be created at once by special act.*"
+
+\- **Charles R. Darwin, 1838**
+
+Pyevolve was developed to be a *complete genetic algorithm framework written in pure python*, but since the version 0.6,
+the framework also supports Genetic Programming, so in the near future, the framework will be more of an Evolutionary
+Computation framework than a simple GA framework.
+
+See the changes in the :ref:`whatsnew` section of this documentation.
+
+This is the documentation for the release v.\ |release|.
+
+See some plot screenshots on the :ref:`graphs_screens` section.
+
+You can download this manual also in other formats:
+
+`Pyevolve PDF Manual <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1-manual.pdf>`__ v.\ |release| (*PDF*)
+ *This is a PDF file version with this manual*
+
+`Pyevolve CHM Manual <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1-manual.chm>`__ v.\ |release| (*CHM - Windows Help*)
+ *This is the CHM (Windows Help) version of this manual*
+
+Get Involved !
+--------------------
+Join with us in `Pyevolve mail-list <http://groups.google.com/group/pyevolve>`_.
+
+Development information and bug reports are in the `Trac <http://sourceforge.net/apps/trac/pyevolve>`_,
+and please, feel free to create new tickets with criticisms or suggestions.
+
+Visit the project `blog site <http://pyevolve.sourceforge.net/wordpress>`_ and leave your comment.
+
+Contents
+--------------------------------------------------
+
+.. toctree::
+ :maxdepth: 4
+
+ whatsnew
+ intro
+ getstarted
+ modules
+ graphs
+ examples
+ faq
+ contributors
+ license
+ contact
+
+
+Index
+-----------------------------------
+
+* :ref:`genindex`
+* :ref:`modindex`
+
+This documentation was updated on |today|.
diff --git a/docs/source/intro.rst b/docs/source/intro.rst
new file mode 100644
index 0000000..1d819ff
--- /dev/null
+++ b/docs/source/intro.rst
@@ -0,0 +1,506 @@
+
+Introduction
+============================================================
+
+This is the documentation for Pyevolve release |release|. Since version 0.5, Pyevolve has changed in many aspects - many new features were added and **many** bugs were fixed. This documentation describes those changes, the new API and new features.
+
+Pyevolve was developed to be a *complete genetic algorithm framework written in pure python*. The main objectives of Pyevolve are:
+
+* **written in pure python**, to maximize the cross-platform aspect;
+* **easy to use API**, the API must be simple to use to the end-user;
+* **see the evolution**, the user must be able to see and *interact* with the evolution statistics, *graphs* and etc;
+* **extensible**, the API must be extensible, the user must be able to create new representations, genetic operators like crossover, mutation and etc;
+* **fast**, the design must be optimized for performance;
+* **common features**, the framework must implement the most common features of GA: selectors like roulette wheel, tournament, ranking, uniform. Scaling schemes like linear scaling, etc;
+* **default parameters**, There must be sensible defaults for all operators, settings, etc.
+* **open-source**, the source must be available to everyone.
+
+.. _requirements:
+
+Requirements
+-----------------------------------
+
+Pyevolve can be executed on **Windows**, **Linux** and **Mac** platforms.
+
+.. note:: On the Mac platform, it's reported that *Pyevolve 0.5* can't enter the
+ :term:`Interactive Mode`.
+
+Pyevolve can be executed under `Jython 2.5b1+ <http://www.jython.org>`_, but with some restrictions:
+ * You can't use some features like the *SQLite3* adapter to dump statistics and *graphs*
+ (unless you install Matplotlib on Jython, but I think that still isn't possible).
+
+Pyevolve can be executed under `IronPython 2.x <http://www.codeplex.com/IronPython>`_, but with some restrictions:
+ * You can't use some features like the *SQLite3* adapter to dump statistics and *graphs*
+ (unless you install Matplotlib on Jython, but I think that still is not possible).
+ * You must install a `zlib module <https://svn.sourceforge.net/svnroot/fepy/trunk/lib/zlib.py>`_ for IronPython.
+
+Pyevolve requires the following modules:
+
+* `Python 2.5+, v.2.6 is recommended <http://www.python.org>`_
+
+* **Optional, for graph plotting**: `Matplotlib 0.98.4+ <http://matplotlib.sourceforge.net/>`_
+ Matplotlib [#matplotlib]_ is required to plot the graphs.
+
+* **Optional, for real-time statistics visualization**: `VPython <http://vpython.org/index.html>`_
+ VPython [#vvpython]_ is required to see real-time statistics visualization.
+
+* **Optional, for drawing GP Trees**: `Pydot 1.0.2+ <http://code.google.com/p/pydot/>`_
+ Pydot [#pydot]_ is used to plot the Genetic Programming Trees.
+
+* **Optional, for MySQL DB Adapter**: `MySQL for Python <http://sourceforge.net/projects/mysql-python/>`_
+ MySQL-python [#mysqldb]_ is used by the MySQL DB Adapter.
+
+.. rubric:: Footnotes
+
+.. [#matplotlib] Matplotlib is Copyright (c) 2002-2008 John D. Hunter; All Rights Reserved
+.. [#vvpython] VPython was originated by David Scherer in 2000.
+.. [#pydot] Pydot was developed by Ero Carrera.
+.. [#mysqldb] MySQLdb was developed by Andy Dustman and contributors.
+
+.. _download_sec:
+
+Downloads
+----------------------------------------------
+
+Windows
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Installers for Microsoft Windows platform:
+
+`Pyevolve <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1.win32-py2.5.exe>`__ v.\ |release| (*installer*) for Python 2.5
+ *This is an .exe installer for Microsoft Windows XP/Vista*
+
+`Pyevolve <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1.win32-py2.6.exe>`__ v.\ |release| (*installer*) for Python 2.6
+ *This is an .exe installer for Microsoft Windows XP/Vista*
+
+`Pyevolve <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1.tar.gz>`__ v.\ |release| (*source code*) for Python 2.x
+ *This is the source code*
+
+Linux
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Installation package for Linux platform:
+
+`Pyevolve <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1.tar.gz>`__ v.\ |release| (*source code*) for Python 2.x
+ *This is the source code*
+
+Examples package
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Examples package for Pyevolve v.\ |release|:
+
+`Pyevolve examples <http://pyevolve.sourceforge.net/distribution/0_6rc1/Pyevolve-0.6rc1-examples.zip>`__ v.\ |release| (*examples*)
+ *This is an package with the Pyevolve source code*
+
+
+Installation
+-----------------------------------
+
+You can download the specific Pyevolve version from the :ref:`download_sec` section, or by using *easy_install*.
+
+The installation can be done the most easiest by using the *easy_install*: ::
+
+ easy_install pyevolve
+
+You can upgrade your older version, too: ::
+
+ easy_install --upgrade pyevolve
+
+
+or install a downloaded *egg package*: ::
+
+ easy_install /downloads/downloaded_package.egg
+
+or install from an URL: ::
+
+ easy_install http://site/package.egg
+
+This command will automatically search, download and install a suitable version of Pyevolve; once you have installed it, you can perform test for success: ::
+
+ >>> import pyevolve
+ >>> print pyevolve.__version__
+ 'v.0.6rc1'
+
+The *easy_install* utility is part of `setuptools <http://pypi.python.org/pypi/setuptools>`_. Once you have installed setuptools, you will find the easy_install.exe program in your Python Scripts subdirectory.
+
+
+Genetic Algorithm Features
+-----------------------------------
+
+**Chromosomes / Representations**
+ **1D List**, **2D List**, **1D Binary String**, **2D Binary String** and **Tree**
+
+ .. note:: it is important to note that the 1D List, 2D List and Tree can carry
+ any type of python objects or primitives.
+
+**Crossover Methods**
+
+ **1D Binary String**
+ Single Point Crossover, Two Point Crossover, Uniform Crossover
+
+ **1D List**
+ Single Point Crossover, Two Point Crossover, Uniform Crossover, OX Crossover, Edge Recombination
+ Crossover, Cut and Crossfill Crossover, Real SBX Crossover
+
+ **2D List**
+ Uniform Crossover, Single Vertical Point Crossover, Single Horizontal Point Crossover
+
+ **2D Binary String**
+ Uniform Crossover, Single Vertical Point Crossover, Single Horizontal Point Crossover
+
+ **Tree**
+ Single Point Crossover, Strict Single Point Crossover
+
+**Mutator Methods**
+
+ **1D Binary String**
+ Swap Mutator, Flip Mutator
+
+ **2D Binary String**
+ Swap Mutator, Flip Mutator
+
+ **1D List**
+ Swap Mutator, Integer Range Mutator, Real Range Mutator, Integer Gaussian Mutator,
+ Real Gaussian Mutator, Integer Binary Mutator, Allele Mutator, Simple Inversion Mutator
+
+ **2D List**
+ Swap Mutator, Integer Gaussian Mutator, Real Gaussian Mutator, Allele Mutator,
+ Integer Range Mutator
+
+ **Tree**
+ Swap Mutator, Integer Range Mutator, Real Range Mutator, Integer Gaussian Mutator,
+ Real Gaussian Mutator
+
+**Initializators**
+
+ **1D Binary String**
+ Binary String Initializator
+
+ **2D Binary String**
+ Binary String Initializator
+
+ **1D List**
+ Allele Initializator, Integer Initializator, Real Initializator
+
+ **2D List**
+ Allele Initializator, Integer Initializator, Real Initializator
+
+ **Tree**
+ Integer Initializator, Allele Initializator
+
+**Scaling Methods**
+
+ Linear Scaling, Sigma Truncation Scaling and Power Law Scaling, Raw Scaling,
+ Boltzmann Scaling, Exponential Scaling, Saturated Scaling
+
+**Selection Methods**
+
+ Rank Selection, Uniform Selection, Tournament Selection, Tournament Selection
+ Alternative (doesn't uses the Roulette Wheel), Roulette Wheel Selection
+
+
+Genetic Programming Features
+-----------------------------------
+
+**Chromosomes / Representations**
+
+ **Tree**
+
+ .. warning:: the Tree of Genetic Programming is the class :class:`GTree.GTreeGP`
+ and not the :class:`GTree.GTree` class of the Genetic Algorithm representation.
+
+**Crossover Methods**
+
+ **Tree**
+ Single Point Crossover
+
+**Mutator Methods**
+
+ **Tree**
+ Operation Mutator, Subtree mutator
+
+**Initializators**
+
+ **Tree**
+ Grow Initializator, Full Initializator, Ramped Half-n-Half
+
+**Scaling Methods**
+
+ Linear Scaling, Sigma Truncation Scaling and Power Law Scaling, Raw Scaling,
+ Boltzmann Scaling, Exponential Scaling, Saturated Scaling
+
+**Selection Methods**
+
+ Rank Selection, Uniform Selection, Tournament Selection, Tournament Selection
+ Alternative (doesn't uses the Roulette Wheel), Roulette Wheel Selection
+
+
+Genetic Algorithms Literature
+------------------------------------
+
+In this section, you will find study material to learn more about Genetic Algorithms.
+
+Books
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**Goldberg, David E (1989)**, *Genetic Algorithms in Search, Optimization and Machine Learning*, Kluwer Academic Publishers, Boston, MA.
+
+**Goldberg, David E (2002)**, *The Design of Innovation: Lessons from and for Competent Genetic Algorithms*, Addison-Wesley, Reading, MA.
+
+**Fogel, David B (2006)**, *Evolutionary Computation: Toward a New Philosophy of Machine Intelligence*, IEEE Press, Piscataway, NJ. Third Edition
+
+**Holland, John H (1975)**, *Adaptation in Natural and Artificial Systems*, University of Michigan Press, Ann Arbor
+
+**Michalewicz, Zbigniew (1999)**, *Genetic Algorithms + Data Structures = Evolution Programs*, Springer-Verlag.
+
+.. seealso::
+
+ `Wikipedia: Genetic Algorithms <http://en.wikipedia.org/wiki/Genetic_algorithm>`_
+ The Wikipedia article about Genetic Algorithms.
+
+Sites
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+`Introduction to Genetic Algorithms <http://www.obitko.com/tutorials/genetic-algorithms/index.php>`_
+ A nice introduction by Marek Obitko.
+
+`A Field Guide to Genetic Programming <http://www.gp-field-guide.org.uk/p>`_
+ A book, freely downloadable under a Creative Commons license.
+
+`A Genetic Algorithm Tutorial by Darrell Whitley Computer Science Department Colorado State University <http://samizdat.mines.edu/ga_tutorial/ga_tutorial.ps>`_
+ An excellent tutorial with lots of theory
+
+
+Genetic Programming Literature
+------------------------------------
+
+In this section, you will find study material to learn more about Genetic Programming.
+
+Books
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**Poli, Riccardo; Langdon, William B.; McPhee, Nicholas F.**, *A Field Guide to Genetic Programming*,
+this book is also available online (a GREAT initiative from authors) in `Book Site <http://www.gp-field-guide.org.uk/>`_
+
+**Koza, John R.**, *Genetic Programming: On the Programming of Computers by Means of Natural Selection*, MIT Press, 1992.
+
+.. seealso::
+
+ `Wikipedia: Genetic Programming <http://en.wikipedia.org/wiki/Genetic_programming>`_
+ The Wikipedia article about Genetic Programming.
+
+Sites
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+`Introduction to Genetic Programming <http://www.genetic-programming.org/>`_
+ A nice collection of GP related content !
+
+`A Field Guide to Genetic Programming <http://www.gp-field-guide.org.uk/p>`_
+ A book, freely downloadable under a Creative Commons license.
+
+`The Genetic Programming Bibliography <http://www.cs.bham.ac.uk/~wbl/biblio/README.html>`_
+ A very interesting initiative mantained by William Langdon, Steven Gustafson, and John Koza.
+ Over than 6000 GP references !
+
+
+Glossary / Concepts
+----------------------------------
+
+.. glossary::
+
+ Raw score
+ The raw score represents the score returned by the :term:`Evaluation function`. This score
+ is not scaled.
+
+ Fitness score
+ The fitness score is the scaled raw score. For example, if you use Linear Scaling (:func:`Scaling.LinearScaling`),
+ the fitness score will be the raw score scaled with the Linear Scaling method. The fitness score represents
+ how good the individual is relative to our population.
+
+ Evaluation function
+ Also called *Fitness Function* or *Objective Function*, the evaluation function is the function which
+ evaluates the genome, giving it a raw score. The objective of this function is to quantify the
+ solutions (individuals, chromosomes)
+
+ .. seealso::
+
+ `Wikipedia: Fitness Function <http://en.wikipedia.org/wiki/Fitness_function>`_
+ An article talking about the Evaluation function, or the "Fitness Function".
+
+ Sample genome
+ The sample genome is the genome which is used as a configuration base for all the new replicated
+ genomes.
+
+ Interactive mode
+ Pyevolve has an interactive mode. You can enter in this mode by pressing ESC key before the end of
+ the evolution. When you press ESC, a python environment will load. In this environment, you
+ are provided with some analysis functions and you can interact with the population of individuals at the
+ specific generation.
+
+ .. seealso::
+
+ Module :mod:`Interaction`
+ The Interaction module.
+
+ Step callback function
+ This function, when attached to the GA Engine (:class:`GSimpleGA.GSimpleGA`), will be called
+ every generation. It receives one parameter, the GA Engine by itself.
+
+ Data Type Independent
+ When a genetic operator is data type idependent, it will operate on different
+ data types but not with different chromosome representations. For example, the
+ :func:`Mutators.G1DListMutatorSwap` mutator will operate on Real, Allele or
+ Integer :class:`G1DList.G1DList` chromosome, but not on :class:`G2DList.G2DList`
+ chromosome.
+
+
+ Standardized Fitness
+ The standardized fitness restates the raw score so that a lower numerical value is
+ always a better value.
+
+ .. seealso::
+
+ `Genetic Programming: On the Programming of Computers by Means of Natural Selection <http://www.amazon.com/Genetic-Programming-Computers-Selection-Adaptive/dp/0262111705>`_
+ A book from John R. Koza about Genetic Programming.
+
+
+ Adjusted Fitness
+ The adjusted fitness is a measure computed from the Standardized Fitness. The Adjusted Fitness is always
+ between 0 and 1 and it's always larger for better individuals.
+
+ .. seealso::
+
+ `Genetic Programming: On the Programming of Computers by Means of Natural Selection <http://www.amazon.com/Genetic-Programming-Computers-Selection-Adaptive/dp/0262111705>`_
+ A book from John R. Koza about Genetic Programming.
+
+ Non-terminal node
+ The non-terminal node or non-terminal function is a function in a parse tree which is either a root
+ or a branch in that tree. In GP, we call non-terminal nodes as "functions", the opposite of
+ terminal nodes, which are the variables of the GP.
+
+.. seealso::
+
+ `Wikipedia: Genetic Algorithm <http://en.wikipedia.org/wiki/Genetic_algorithm>`_
+ An article talking about Genetic Algorithms.
+
+ `Wikipedia: Genetic Programming <http://en.wikipedia.org/wiki/Genetic_programming>`_
+ The Wikipedia article about Genetic Programming.
+
+
+Other platforms and performance
+============================================================
+
+Running Pyevolve on Symbian OS (PyS60)
+---------------------------------------------------------------------------
+Pyevolve is compatible with PyS60 2.0 (but older versions of the 1.9.x trunk should work fine too); PyS60
+2.0 is a port of Python 2.5.4 core to the S60 smartphones, it was made by Nokia and it's Open Source.
+All smartphones based on the `S60 2nd and 3rd editions <http://en.wikipedia.org/wiki/Nokia_S60_and_Symbian_OS#S60_editions>`_
+should run PyS60, you can download it from the `Maemo garage project home <https://garage.maemo.org/projects/pys60/>`_.
+
+To install Pyevolve in PyS60 you simple need to copy the "pyevolve" package (you can use the sources of Pyevolve
+or even the "pyevolve" of your Python installation to the smartphone in a place that PyS60 can find it, usually
+in :file:`c:\\resource\\Python25`, for more information read the PyS60 documentation. The Genetic Algorithms and the
+Genetic Programming cores of Pyevolve was tested with PyS60 2.0, but to use Genetic Programming, you must
+explicitly define the funtions of the GP, like in :ref:`snippet_gp_explicit`.
+
+Of course not all features of Pyevolve are supported in PyS60, for example some DBAdapters and the graphical
+plotting tool, since no matplotlib port is available to PyS60 at the moment. Pyevolve was tested with PyS60 2.0
+in a Nokia N78 and in a Nokia N73 smartphones.
+
+.. seealso::
+
+ `Croozeus.com - home to PyS60 developers <http://croozeus.com/>`_
+ A lot of information and tutorials about PyS60, very recommended.
+
+ `Python for S60 - OpenSource <http://wiki.opensource.nokia.com/projects/PyS60>`_
+ The PyS60 project wiki.
+
+Running Pyevolve on Jython
+---------------------------------------------------------------------------
+Jython is an implementation of Python language and its modules (not all unfortunatelly) which
+is designed to run over the Java platform.
+Pyevolve was tested against Jython 2.5.x and worked well, except for the Genetic Programming
+core which is taking a lot of memory, maybe a Jython issue with the Java JVM.
+
+You're highly encouraged to run Jython with the JVM "-server" option; this option will enable
+another VM JIT which is optimal for applications where the fast startup times isn't important,
+and the overall performance is what matters. This JIT of the "Server mode" has different
+policies to compile your code into native code, and it's well designed for long running
+applications, where the VM can profile and optimize better than the JIT of "Client mode".
+
+Pyevolve was tested against Jython 2.5.1 in Java v.1.6.0_18
+Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
+Java HotSpot(TM) Client VM (build 16.0-b13, mixed mode, sharing)
+
+.. seealso::
+
+ `Jython <http://www.jython.org/>`_
+ Official Jython project home.
+
+ `Java HotSpot <http://java.sun.com/products/hotspot/whitepaper.html#1>`_
+ The Java HotSpot Performance Engine Architecture.
+
+
+Running Pyevolve on IronPython
+---------------------------------------------------------------------------
+IronPython is an open-source implementation of the Python programming language targeting
+the .NET Framework and Mono, written entirely in C# and created by Jim Hugunin.
+IronPython is currently language-compatible with Python 2.6.
+
+Pyevolve was tested against the IronPython 2.6 (2.6.10920.0) in a Windows XP SP3
+with .NET 2.0.50727.3603.
+
+.. seealso::
+
+ `Official IronPython project home <http://www.ironpython.net>`_
+ Official IronPython project home.
+
+ `Differences between IronPython and CPython <http://ironpython.codeplex.com/wikipage?title=Differences>`_
+ Documents with differences between IronPython and CPython (the official Python interepreter).
+
+ `IronPython performance benchmarks <http://ironpython.codeplex.com/wikipage?title=IP26RC1VsCPy26Perf&referringTitle=Home&ProjectName=ironpython>`_
+ A lot of benchmarks and comparisons between IronPython and CPython.
+
+
+Running Pyevolve on iPod/iPhone
+---------------------------------------------------------------------------
+The Genetic Algorithm core of Pyevolve was tested on iPod Touch 2G with the
+firmware v.3.1.2. To use it, you first must install the port of Python 2.5+ to the
+OS of iPod. You just need to put the Pyevolve package inside the directory where
+you'll call your application or just put it inside another place where the Python
+from iPod/iPhone can found in path.
+
+.. seealso::
+
+ `Miniguide to install Python on iPhone <http://coding.derkeiler.com/Archive/Python/comp.lang.python/2008-11/msg00252.html>`_
+ Miniguide on how to install Python on iPhone
+
+
+Improving Pyevolve performance
+---------------------------------------------------------------------------
+Pyevolve, at least for versions <= 0.6, has all modules written in pure Python, which enables some
+very useful features and portability, but sometimes at a cost to performance. Here are some
+ways users and developers uses to increase the performance of Pyevolve:
+
+ **Psyco**
+ Psyco is the well known Python specializing compiler, created by Armin Rigo. Psyco
+ is very easy to use and can greatly speed up execution.
+
+ **Cython**
+ Cython is a specific language used to create C/C++ extensions for Python, it is based
+ on the Python language itself, so if you think Psyco is not enought or aren't giving
+ too much optimizations, you can use Cython to create your own C/C++ extensions; the
+ best approach is to use Cython to build your :term:`Evaluation function`, which is
+ usually the most consuming part of Genetic Algorithms.
+
+.. seealso::
+
+ `Psyco at Sourceforge.net <http://psyco.sourceforge.net/>`_
+ The official site of Psyco at Sourceforge.net
+
+ `Psyco 2.0 binaries for Windows <http://www.voidspace.org.uk/python/modules.shtml#psyco>`_
+ Development of psyco was recently done by Christian Tismer. Here you'll find the
+ binaries of Psyco 2.0 (Python 2.4, 2.5 and 2.6) for Windows.
+
+ `Cython - C-Extensions for Python <http://www.cython.org/>`_
+ Official Cython project home.
diff --git a/docs/source/license.rst b/docs/source/license.rst
new file mode 100644
index 0000000..d4e1fbc
--- /dev/null
+++ b/docs/source/license.rst
@@ -0,0 +1,63 @@
+
+License
+==============================================
+
+The Pyevolve license is based on the `PSF <http://www.python.org/psf/license>`_
+license, which is GPL compatible license.
+
+.. centered:: LICENSE AGREEMENT FOR PYEVOLVE |version|
+
+1. This LICENSE AGREEMENT is between Christian S. Perone ("CSP"), and the
+Individual or Organization ("Licensee") accessing and otherwise using
+Pyevolve software in source or binary form and its associated
+documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CSP
+hereby grants Licensee a nonexclusive, royalty-free, world-wide license
+to reproduce, analyze, test, perform and/or display publicly, prepare
+derivative works, distribute, and otherwise use Pyevolve |version|
+alone or in any derivative version, provided, however, that CSP's
+License Agreement and CSP's notice of copyright, i.e., "Copyright (c)
+2007-2010 Christian S. Perone; All Rights Reserved" are retained in
+Pyevolve |version| alone or in any derivative version prepared by
+Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+incorporates Pyevolve |version| or any part thereof, and wants to
+make the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Pyevolve |version|.
+
+4. CSP is making Pyevolve |version| available to Licensee on an "AS
+IS" basis. CSP MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CSP MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF Pyevolve |version|
+WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CSP SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF Pyevolve
+|version| FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
+LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING
+Pyevolve |version|, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF
+THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between CSP and
+Licensee. This License Agreement does not grant permission to use CSP
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Pyevolve |version|,
+Licensee agrees to be bound by the terms and conditions of this License
+Agreement.
+
+Credits
+==============================================
+
+Pyevolve was written by Christian S. Perone and is currently
+maintained by himself and it's contributors.
+
+
diff --git a/docs/source/module_allele.rst b/docs/source/module_allele.rst
new file mode 100644
index 0000000..69a809e
--- /dev/null
+++ b/docs/source/module_allele.rst
@@ -0,0 +1,6 @@
+
+
+
+.. automodule:: GAllele
+ :members:
+
diff --git a/docs/source/module_const.rst b/docs/source/module_const.rst
new file mode 100644
index 0000000..5021718
--- /dev/null
+++ b/docs/source/module_const.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: Consts
+ :members:
+
diff --git a/docs/source/module_crossovers.rst b/docs/source/module_crossovers.rst
new file mode 100644
index 0000000..9d4755b
--- /dev/null
+++ b/docs/source/module_crossovers.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: Crossovers
+ :members:
+
diff --git a/docs/source/module_dbadapters.rst b/docs/source/module_dbadapters.rst
new file mode 100644
index 0000000..59d0a0a
--- /dev/null
+++ b/docs/source/module_dbadapters.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: DBAdapters
+ :members:
+ :inherited-members:
diff --git a/docs/source/module_functionslot.rst b/docs/source/module_functionslot.rst
new file mode 100644
index 0000000..bf40c33
--- /dev/null
+++ b/docs/source/module_functionslot.rst
@@ -0,0 +1,4 @@
+
+
+.. automodule:: FunctionSlot
+ :members:
diff --git a/docs/source/module_g1dbinarystring.rst b/docs/source/module_g1dbinarystring.rst
new file mode 100644
index 0000000..6a03a25
--- /dev/null
+++ b/docs/source/module_g1dbinarystring.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: G1DBinaryString
+ :members:
+ :inherited-members:
+
+
diff --git a/docs/source/module_g1dlist.rst b/docs/source/module_g1dlist.rst
new file mode 100644
index 0000000..4498e2c
--- /dev/null
+++ b/docs/source/module_g1dlist.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: G1DList
+ :members:
+ :inherited-members:
+
+
diff --git a/docs/source/module_g2dbinarystring.rst b/docs/source/module_g2dbinarystring.rst
new file mode 100644
index 0000000..e5f5f70
--- /dev/null
+++ b/docs/source/module_g2dbinarystring.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: G2DBinaryString
+ :members:
+ :inherited-members:
+
+
diff --git a/docs/source/module_g2dlist.rst b/docs/source/module_g2dlist.rst
new file mode 100644
index 0000000..8116e74
--- /dev/null
+++ b/docs/source/module_g2dlist.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: G2DList
+ :members:
+ :inherited-members:
+
+
diff --git a/docs/source/module_genomebase.rst b/docs/source/module_genomebase.rst
new file mode 100644
index 0000000..bd92115
--- /dev/null
+++ b/docs/source/module_genomebase.rst
@@ -0,0 +1,5 @@
+
+
+.. automodule:: GenomeBase
+ :members:
+ :inherited-members:
diff --git a/docs/source/module_gpopulation.rst b/docs/source/module_gpopulation.rst
new file mode 100644
index 0000000..2317880
--- /dev/null
+++ b/docs/source/module_gpopulation.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: GPopulation
+ :members:
+
+
+
diff --git a/docs/source/module_gsimplega.rst b/docs/source/module_gsimplega.rst
new file mode 100644
index 0000000..d4d4475
--- /dev/null
+++ b/docs/source/module_gsimplega.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: GSimpleGA
+ :members:
+
diff --git a/docs/source/module_gtree.rst b/docs/source/module_gtree.rst
new file mode 100644
index 0000000..416ee5e
--- /dev/null
+++ b/docs/source/module_gtree.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: GTree
+ :members:
+ :inherited-members:
+
+
diff --git a/docs/source/module_initializators.rst b/docs/source/module_initializators.rst
new file mode 100644
index 0000000..db02415
--- /dev/null
+++ b/docs/source/module_initializators.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: Initializators
+ :members:
+
diff --git a/docs/source/module_interaction.rst b/docs/source/module_interaction.rst
new file mode 100644
index 0000000..d6c3b24
--- /dev/null
+++ b/docs/source/module_interaction.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: Interaction
+ :members:
+
diff --git a/docs/source/module_migration.rst b/docs/source/module_migration.rst
new file mode 100644
index 0000000..1bd2303
--- /dev/null
+++ b/docs/source/module_migration.rst
@@ -0,0 +1,6 @@
+
+.. automodule:: Migration
+ :members:
+ :inherited-members:
+
+
diff --git a/docs/source/module_mutators.rst b/docs/source/module_mutators.rst
new file mode 100644
index 0000000..bcc9322
--- /dev/null
+++ b/docs/source/module_mutators.rst
@@ -0,0 +1,4 @@
+
+
+.. automodule:: Mutators
+ :members:
diff --git a/docs/source/module_network.rst b/docs/source/module_network.rst
new file mode 100644
index 0000000..daa7ec7
--- /dev/null
+++ b/docs/source/module_network.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: Network
+ :members:
+ :inherited-members:
diff --git a/docs/source/module_pyevolve.rst b/docs/source/module_pyevolve.rst
new file mode 100644
index 0000000..d527b93
--- /dev/null
+++ b/docs/source/module_pyevolve.rst
@@ -0,0 +1,54 @@
+.. automodule:: pyevolve
+
+General Modules
+----------------------------------------------------------------------
+
+Contents:
+
+.. toctree::
+ :maxdepth: 3
+
+ module_const
+ module_util
+ module_network
+ module_migration
+ module_interaction
+ module_dbadapters
+ module_functionslot
+ module_statistics
+
+Genetic Algorithm Core Modules
+----------------------------------------------------------------------
+
+.. toctree::
+ :maxdepth: 3
+
+ module_gsimplega
+ module_gpopulation
+
+Genetic Operators Modules
+----------------------------------------------------------------------
+
+.. toctree::
+ :maxdepth: 3
+
+ module_mutators
+ module_crossovers
+ module_initializators
+ module_selectors
+ module_scaling
+
+Chromosomes/Representation Modules
+----------------------------------------------------------------------
+
+.. toctree::
+ :maxdepth: 3
+
+ module_genomebase
+ module_allele
+ module_g1dbinarystring
+ module_g2dbinarystring
+ module_g1dlist
+ module_g2dlist
+ module_gtree
+
diff --git a/docs/source/module_scaling.rst b/docs/source/module_scaling.rst
new file mode 100644
index 0000000..bfcd568
--- /dev/null
+++ b/docs/source/module_scaling.rst
@@ -0,0 +1,6 @@
+
+
+
+.. automodule:: Scaling
+ :members:
+
diff --git a/docs/source/module_selectors.rst b/docs/source/module_selectors.rst
new file mode 100644
index 0000000..16e85fd
--- /dev/null
+++ b/docs/source/module_selectors.rst
@@ -0,0 +1,6 @@
+
+
+
+.. automodule:: Selectors
+ :members:
+
diff --git a/docs/source/module_statistics.rst b/docs/source/module_statistics.rst
new file mode 100644
index 0000000..e5f9a07
--- /dev/null
+++ b/docs/source/module_statistics.rst
@@ -0,0 +1,4 @@
+
+
+.. automodule:: Statistics
+ :members:
diff --git a/docs/source/module_util.rst b/docs/source/module_util.rst
new file mode 100644
index 0000000..e4983ad
--- /dev/null
+++ b/docs/source/module_util.rst
@@ -0,0 +1,4 @@
+
+.. automodule:: Util
+ :members:
+
diff --git a/docs/source/modules.rst b/docs/source/modules.rst
new file mode 100644
index 0000000..ab5d47a
--- /dev/null
+++ b/docs/source/modules.rst
@@ -0,0 +1,14 @@
+
+Modules
+====================================
+
+Documentation of the all Pyevolve modules.
+All modules above listed are under the "pyevolve" namespace.
+
+Contents:
+
+.. toctree::
+ :maxdepth: 3
+
+ module_pyevolve
+
diff --git a/docs/source/sitemap.xml b/docs/source/sitemap.xml
new file mode 100644
index 0000000..662e238
--- /dev/null
+++ b/docs/source/sitemap.xml
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<urlset xmlns="http://www.google.com/schemas/sitemap/0.84" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84 http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">
+ <url>
+ <loc>http://pyevolve.sourceforge.net/</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.8</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/genindex.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.8</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/modindex.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_const.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_util.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_interaction.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_dbadapters.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_functionslot.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_statistics.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_gsimplega.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_gpopulation.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_mutators.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_crossovers.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_initializators.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_selectors.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_scaling.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_genomebase.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_allele.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_g1dbinarystring.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_g1dlist.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_g2dlist.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/graphs.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.8</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/examples.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.8</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/faq.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/license.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/contact.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/intro.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/getstarted.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.7</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/modules.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+ <url>
+ <loc>http://pyevolve.sourceforge.net/module_pyevolve.html</loc>
+ <lastmod>2009-01-22</lastmod>
+ <changefreq>daily</changefreq>
+ <priority>0.5</priority>
+ </url>
+</urlset>
\ No newline at end of file
diff --git a/docs/source/sphinx06_code_patch.py b/docs/source/sphinx06_code_patch.py
new file mode 100644
index 0000000..b6561dd
--- /dev/null
+++ b/docs/source/sphinx06_code_patch.py
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.directives.code
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import sys
+import codecs
+import re
+from os import path
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+from sphinx import addnodes
+from sphinx.util import parselinenos
+
+
+# ------ highlight directive --------------------------------------------------------
+
+def highlightlang_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ if 'linenothreshold' in options:
+ try:
+ linenothreshold = int(options['linenothreshold'])
+ except Exception:
+ linenothreshold = 10
+ else:
+ linenothreshold = sys.maxint
+ return [addnodes.highlightlang(lang=arguments[0].strip(),
+ linenothreshold=linenothreshold)]
+
+highlightlang_directive.content = 0
+highlightlang_directive.arguments = (1, 0, 0)
+highlightlang_directive.options = {'linenothreshold': directives.unchanged}
+directives.register_directive('highlight', highlightlang_directive)
+directives.register_directive('highlightlang', highlightlang_directive) # old name
+
+
+# ------ code-block directive -------------------------------------------------------
+
+def codeblock_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ code = u'\n'.join(content)
+ literal = nodes.literal_block(code, code)
+ literal['language'] = arguments[0]
+ literal['linenos'] = 'linenos' in options
+ return [literal]
+
+codeblock_directive.content = 1
+codeblock_directive.arguments = (1, 0, 0)
+codeblock_directive.options = {'linenos': directives.flag}
+directives.register_directive('code-block', codeblock_directive)
+directives.register_directive('sourcecode', codeblock_directive)
+
+
+# ------ literalinclude directive ---------------------------------------------------
+
+def literalinclude_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Like .. include:: :literal:, but only warns if the include file is not found."""
+ if not state.document.settings.file_insertion_enabled:
+ return [state.document.reporter.warning('File insertion disabled', line=lineno)]
+ env = state.document.settings.env
+ rel_fn = arguments[0]
+ source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
+ lineno - state_machine.input_offset - 1)))
+ fn = path.normpath(path.join(source_dir, rel_fn))
+
+ if 'pyobject' in options and 'lines' in options:
+ return [state.document.reporter.warning(
+ 'Cannot use both "pyobject" and "lines" options', line=lineno)]
+
+ encoding = options.get('encoding', env.config.source_encoding)
+ try:
+ f = codecs.open(fn, 'r', encoding)
+ #f = open(fn, 'rb')
+ lines = f.readlines()
+ f.close()
+ except (IOError, OSError):
+ return [state.document.reporter.warning(
+ 'Include file %r not found or reading it failed' % arguments[0],
+ line=lineno)]
+ except UnicodeError:
+ return [state.document.reporter.warning(
+ 'Encoding %r used for reading included file %r seems to '
+ 'be wrong, try giving an :encoding: option' %
+ (encoding, arguments[0]))]
+
+ objectname = options.get('pyobject')
+ if objectname is not None:
+ from sphinx.pycode import ModuleAnalyzer
+ analyzer = ModuleAnalyzer.for_file(fn, '')
+ tags = analyzer.find_tags()
+ if objectname not in tags:
+ return [state.document.reporter.warning(
+ 'Object named %r not found in include file %r' %
+ (objectname, arguments[0]), line=lineno)]
+ else:
+ lines = lines[tags[objectname][1] - 1 : tags[objectname][2] - 1]
+
+ linespec = options.get('lines')
+ if linespec is not None:
+ try:
+ linelist = parselinenos(linespec, len(lines))
+ except ValueError, err:
+ return [state.document.reporter.warning(str(err), line=lineno)]
+ lines = [lines[i] for i in linelist]
+
+ startafter = options.get('start-after')
+ endbefore = options.get('end-before')
+ if startafter is not None or endbefore is not None:
+ use = not startafter
+ res = []
+ for line in lines:
+ if not use and startafter in line:
+ use = True
+ elif use and endbefore in line:
+ use = False
+ break
+ elif use:
+ res.append(line)
+ lines = res
+
+ text = ''.join(lines)
+ text = re.sub("\r\n", "\n", text)
+
+ retnode = nodes.literal_block(text, text, source=fn)
+ retnode.line = 1
+ if options.get('language', ''):
+ retnode['language'] = options['language']
+ if 'linenos' in options:
+ retnode['linenos'] = True
+ state.document.settings.env.note_dependency(rel_fn)
+ return [retnode]
+
+literalinclude_directive.options = {'linenos': directives.flag,
+ 'language': directives.unchanged_required,
+ 'encoding': directives.encoding,
+ 'pyobject': directives.unchanged_required,
+ 'lines': directives.unchanged_required,
+ 'start-after': directives.unchanged_required,
+ 'end-before': directives.unchanged_required,
+ }
+literalinclude_directive.content = 0
+literalinclude_directive.arguments = (1, 0, 0)
+directives.register_directive('literalinclude', literalinclude_directive)
diff --git a/docs/source/whatsnew.rst b/docs/source/whatsnew.rst
new file mode 100644
index 0000000..fef83ff
--- /dev/null
+++ b/docs/source/whatsnew.rst
@@ -0,0 +1,186 @@
+.. _whatsnew:
+
+What's new ?
+============================================================
+
+What's new on the release |release|:
+
+**Optimizations and bug-fixes**
+
+ Added many general optimizations and bug-fixes. The code is more *pythonic* and stable
+ now.
+
+**Documentation, documentation and documentation**
+
+ Added documentation about the new GP core, new features, changes were done
+ to reflect API changes here and there, etc...
+
+**Function Slots - Functions now have weights**
+
+ Added a new `weight` parameter to the `add` method of the
+ :class:`FunctionSlot.FunctionSlot` class. This parameter is
+ used when you enable the *random apply* of the slot. See
+ the class for more information.
+
+**Multiprocessing - the use of multiprocessign module**
+
+ Added a new method to the :class:`GSimpleGA.GSimpleGA` class, the
+ :meth:`GSimpleGA.GSimpleGA.setMultiProcessing` method. With this
+ method you can enable the use of **multiprocessing** python module.
+ When you enable this option, Pyevolve will check if you have
+ more than one CPU core and if there is support to the multiprocessing
+ use. You **must** see the warning on the :meth:`GSimpleGA.GSimpleGA.setMultiProcessing`
+ method.
+
+**Scaling Scheme - the Boltzmann scaling**
+
+ Added the Boltzmann scaling scheme, this scheme uses a temperature which is reduced
+ each generation by a small amount. As the temperature decreases, the difference
+ spread between the high and low fitnesses increases. See the description
+ on the :func:`Scaling.BoltzmannScaling` function.
+
+**Scaling Scheme - Exponential and Saturated scaling**
+
+ Added the Exponential and Saturated scaling schemes, using the exponential function
+ to calculate the fitness values. See more in :func:`Scaling.ExponentialScaling` and
+ :func:`Scaling.SaturatedScaling`.
+
+**Selectors - the alternative Tournament Selection**
+
+ Added an alternative Tournament selection method, the :func:`Selectors.GTournamentAlternative`.
+ This new Tournament Selector **don't uses** the Roulette Wheel method to pick individuals.
+
+**Statistics - two new statistical measures**
+
+ Added the **fitTot** and the **rawTot** parameters to the :class:`Statistics.Statistics`
+ class. See the class documentation for more information.
+
+**Elitism - replacement option**
+
+ Added the method :meth:`GSimpleGA.GSimpleGA.setElitismReplacement`. This method is used to set
+ the number of individuals cloned on the elitism.
+
+**String representation - resumeString**
+
+ Added the method *resumeString* to all native chromosomes. This method returns a
+ small as possible string representation of the chromosome.
+
+**DB Adapter - XML RPC**
+
+ Added a new DB Adapter to send Pyevolve statistics, the XML RPC, to see more information,
+ access the docs of the :class:`DBAdapters.DBXMLRPC`.
+
+**DB Adapters - OO redesigned**
+
+ The DB Adapters were redesigned and now there is a super class for all DB Adapters, you
+ can create your own DB Adapters subclassing the :class:`DBAdapters.DBBaseAdapter` class.
+
+**The Network module - lan/wan networking**
+
+ Added the :mod:`Network` module, this module is used to keep all the
+ networking related classes, currently it contains the threaded UDP client/server.
+
+**The Migration module - distributed GA**
+
+ Added the :mod:`Migration` module, this module is used to control the
+ migration of the distributed GA.
+
+**The G2DBinaryString module - the 2D Binary String**
+
+ Added the :mod:`G2DBinaryString` module. This module contains
+ the 2D Binary String chromosome representation.
+
+**1D chromosomes - new base class**
+
+ All the 1D choromsomes representation is now extending the
+ :class:`GenomeBase.G1DBase` base class.
+
+**Tree chromosome - new Tree representation chromosome**
+
+ Added the module :mod:`GTree`, this module contains the
+ new :class:`GTree.GTree` chromosome representation and all tree related
+ functions and the :class:`GTree.GTreeGP` chromosome used by Genetic Programming.
+
+**VPython DB Adapter - real-time graph statistics**
+
+ Added the new :class:`DBAdapters.DBVPythonGraph` class, this DB
+ Adapter uses the VPython to create real-time statistics graphs.
+
+**MySQL DB Adapter - dump statistics to MySQL**
+
+ Added the new :class:`DBAdapters.DBMySQLAdapter` class, this DB Adapter
+ will dump statistics to a local or remote MySQL database.
+
+**Genetic Programming - Pyevolve now supports GP**
+
+ Added new support for the Genetic Programming, you can check the
+ examples with symbolic regression. The GTreeGP choromsome representation
+ is used for the GP main tree.
+
+**Interactive mode - no more platform independent code**
+
+ Code that was platform independent from the Interactive Mode was removed,
+ so if you are unable to enter in the Interactive Mode using the ESC key,
+ try using the method call to enter in the mode at a defined generation.
+
+**Mutators**
+
+ Added the Simple Inversion Mutation (:func:`Mutators.G1DListMutatorSIM`) for G1DList genome.
+
+ Added the Integer Range Mutation (:func:`Mutators.G2DListMutatorIntegerRange`) for the G2DList genome.
+
+ Added the Binary String Swap Mutator (:func:`Mutators.G2DListMutatorIntegerRange`) for the G2DBinaryString genome.
+
+ Added the Binary String Flip Mutator (:func:`Mutators.G2DBinaryStringMutatorFlip`) for the G2DBinaryString genome.
+
+ Added the GTree Swap Mutator (:func:`Mutators.GTreeMutatorSwap`) for the GTree genome.
+
+ Added the GTree Integer Range Mutator (:func:`Mutators.GTreeMutatorIntegerRange`) for the GTree genome.
+
+ Added the GTree Integer Gaussian Mutator (:func:`Mutators.GTreeMutatorIntegerGaussian`) for the GTree genome.
+
+ Added the GTree Real Range Mutator (:func:`Mutators.GTreeMutatorRealRange`) for the GTree genome.
+
+ Added the GTree Real Gaussian Mutator (:func:`Mutators.GTreeMutatorRealGaussian`) for the GTree genome.
+
+ Added the GTreeGP Operation Mutator (:func:`Mutators.GTreeGPMutatorOperation`) for the GTreeGP genome.
+
+ Added the GTreeGP Subtree Mutator (:func:`Mutators.GTreeGPMutatorSubtree`) for the GTreeGP genome.
+
+**Crossovers**
+
+ Added the Cut and Crossfill Crossover (:func:`Crossovers.G1DListCrossoverCutCrossfill`), used for permutations, for
+ the G1DList genome.
+
+ Added the Uniform Crossover (:func:`Crossovers.G2DBinaryStringXUniform`) for the G2DBinaryString genome.
+
+ Added the Single Vert. Point Crossover (:func:`Crossovers.G2DBinaryStringXSingleVPoint`) for the G2DBinaryString genome.
+
+ Added the Single Horiz. Point Crossover (:func:`Crossovers.G2DBinaryStringXSingleHPoint`) for the G2DBinaryString genome.
+
+ Added the Single Point Crossover (:func:`Crossovers.GTreeCrossoverSinglePoint`) for the GTree genome.
+
+ Added the Single Point Strict Crossover (:func:`Crossovers.GTreeCrossoverSinglePointStrict`) for the GTree genome.
+
+ Added the Single Point Crossover (:func:`Crossovers.GTreeGPCrossoverSinglePoint`) for the GTreeGP genome.
+
+ Added the SBX Crossover (:func:`Crossovers.G1DListCrossoverRealSBX`) for G1DList genome, thanks to Amit Saha.
+
+ Added the Edge Recombination (:func:`Crossovers.G1DListCrossoverEdge`) for G1DList genome.
+
+**Initializators**
+
+ Added the Integer Initializator (:func:`Initializators.G2DBinaryStringInitializator`) for the G2DBinaryString genome.
+
+ Added the Integer Initializator (:func:`Initializators.GTreeInitializatorInteger`) for the GTree genome.
+
+ Added the Allele Initializator (:func:`Initializators.GTreeInitializatorAllele`) for the GTree genome.
+
+ Added the GTreeGP (Genetic Programming genome) Initializator (:func:`Initializators.GTreeGPInitializator`).
+ It accept the methods: grow, full and ramped.
+
+
+
+
+
+
diff --git a/examples/LICENSE.TXT b/examples/LICENSE.TXT
new file mode 100644
index 0000000..e99e500
--- /dev/null
+++ b/examples/LICENSE.TXT
@@ -0,0 +1,46 @@
+1. This LICENSE AGREEMENT is between Christian S. Perone ("CSP"), and the
+Individual or Organization ("Licensee") accessing and otherwise using
+Pyevolve software in source or binary form and its associated
+documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CSP
+hereby grants Licensee a nonexclusive, royalty-free, world-wide license
+to reproduce, analyze, test, perform and/or display publicly, prepare
+derivative works, distribute, and otherwise use Pyevolve 0.6
+alone or in any derivative version, provided, however, that CSP's
+License Agreement and CSP's notice of copyright, i.e., "Copyright (c)
+2007-2010 Christian S. Perone; All Rights Reserved" are retained in
+Pyevolve 0.6 alone or in any derivative version prepared by
+Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+incorporates Pyevolve 0.6 or any part thereof, and wants to
+make the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Pyevolve 0.6.
+
+4. CSP is making Pyevolve 0.6 available to Licensee on an "AS
+IS" basis. CSP MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CSP MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF Pyevolve 0.6
+WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CSP SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF Pyevolve
+0.6 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
+LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING
+Pyevolve 0.6, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF
+THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between CSP and
+Licensee. This License Agreement does not grant permission to use CSP
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Pyevolve 0.6,
+Licensee agrees to be bound by the terms and conditions of this License
+Agreement.
\ No newline at end of file
diff --git a/examples/pyevolve_ex10_g1dbinstr.py b/examples/pyevolve_ex10_g1dbinstr.py
new file mode 100644
index 0000000..d257cb8
--- /dev/null
+++ b/examples/pyevolve_ex10_g1dbinstr.py
@@ -0,0 +1,40 @@
+from pyevolve import G1DBinaryString
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import Mutators
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome
+ for value in chromosome:
+ if value == 0:
+ score += 0.1
+
+ return score
+
+def run_main():
+ # Genome instance
+ genome = G1DBinaryString.G1DBinaryString(50)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+ genome.mutator.set(Mutators.G1DBinaryStringMutatorFlip)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.selector.set(Selectors.GTournamentSelector)
+ ga.setGenerations(70)
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=20)
+
+ # Best individual
+ print ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
+
diff --git a/examples/pyevolve_ex11_allele.py b/examples/pyevolve_ex11_allele.py
new file mode 100644
index 0000000..52e12dc
--- /dev/null
+++ b/examples/pyevolve_ex11_allele.py
@@ -0,0 +1,72 @@
+from pyevolve import G1DList
+from pyevolve import GSimpleGA
+from pyevolve import Mutators
+from pyevolve import Initializators
+from pyevolve import GAllele
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome
+ for value in chromosome:
+ if value == 0:
+ score += 0.5
+
+ # Remember from the allele set defined above
+ # this value 'a' is possible at this position
+ if chromosome[18] == 'a':
+ score += 1.0
+
+ # Remember from the allele set defined above
+ # this value 'xxx' is possible at this position
+ if chromosome[12] == 'xxx':
+ score += 1.0
+
+ return score
+
+def run_main():
+ # Genome instance
+ setOfAlleles = GAllele.GAlleles()
+
+ # From 0 to 10 we can have only some
+ # defined ranges of integers
+ for i in xrange(11):
+ a = GAllele.GAlleleRange(0, i)
+ setOfAlleles.add(a)
+
+ # From 11 to 19 we can have a set
+ # of elements
+ for i in xrange(11, 20):
+ # You can even add objects instead of strings or
+ # primitive values
+ a = GAllele.GAlleleList(['a','b', 'xxx', 666, 0])
+ setOfAlleles.add(a)
+
+ genome = G1DList.G1DList(20)
+ genome.setParams(allele=setOfAlleles)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+
+ # This mutator and initializator will take care of
+ # initializing valid individuals based on the allele set
+ # that we have defined before
+ genome.mutator.set(Mutators.G1DListMutatorAllele)
+ genome.initializator.set(Initializators.G1DListInitializatorAllele)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setGenerations(40)
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=5)
+
+ # Best individual
+ print ga.bestIndividual()
+
+
+if __name__ == "__main__":
+ run_main()
\ No newline at end of file
diff --git a/examples/pyevolve_ex12_tsp.py b/examples/pyevolve_ex12_tsp.py
new file mode 100644
index 0000000..385bf46
--- /dev/null
+++ b/examples/pyevolve_ex12_tsp.py
@@ -0,0 +1,130 @@
+from pyevolve import G1DList, GAllele
+from pyevolve import GSimpleGA
+from pyevolve import Mutators
+from pyevolve import Crossovers
+from pyevolve import Consts
+
+import sys, random
+random.seed(1024)
+from math import sqrt
+
+PIL_SUPPORT = None
+
+try:
+ from PIL import Image, ImageDraw, ImageFont
+ PIL_SUPPORT = True
+except:
+ PIL_SUPPORT = False
+
+
+cm = []
+coords = []
+CITIES = 100
+WIDTH = 1024
+HEIGHT = 768
+LAST_SCORE = -1
+
+def cartesian_matrix(coords):
+ """ A distance matrix """
+ matrix={}
+ for i,(x1,y1) in enumerate(coords):
+ for j,(x2,y2) in enumerate(coords):
+ dx, dy = x1-x2, y1-y2
+ dist=sqrt(dx*dx + dy*dy)
+ matrix[i,j] = dist
+ return matrix
+
+def tour_length(matrix, tour):
+ """ Returns the total length of the tour """
+ total = 0
+ t = tour.getInternalList()
+ for i in range(CITIES):
+ j = (i+1)%CITIES
+ total += matrix[t[i], t[j]]
+ return total
+
+def write_tour_to_img(coords, tour, img_file):
+ """ The function to plot the graph """
+ padding=20
+ coords=[(x+padding,y+padding) for (x,y) in coords]
+ maxx,maxy=0,0
+ for x,y in coords:
+ maxx, maxy = max(x,maxx), max(y,maxy)
+ maxx+=padding
+ maxy+=padding
+ img=Image.new("RGB",(int(maxx),int(maxy)),color=(255,255,255))
+ font=ImageFont.load_default()
+ d=ImageDraw.Draw(img);
+ num_cities=len(tour)
+ for i in range(num_cities):
+ j=(i+1)%num_cities
+ city_i=tour[i]
+ city_j=tour[j]
+ x1,y1=coords[city_i]
+ x2,y2=coords[city_j]
+ d.line((int(x1),int(y1),int(x2),int(y2)),fill=(0,0,0))
+ d.text((int(x1)+7,int(y1)-5),str(i),font=font,fill=(32,32,32))
+
+ for x,y in coords:
+ x,y=int(x),int(y)
+ d.ellipse((x-5,y-5,x+5,y+5),outline=(0,0,0),fill=(196,196,196))
+ del d
+ img.save(img_file, "PNG")
+ print "The plot was saved into the %s file." % (img_file,)
+
+def G1DListTSPInitializator(genome, **args):
+ """ The initializator for the TSP """
+ lst = [i for i in xrange(genome.getListSize())]
+ random.shuffle(lst)
+ genome.setInternalList(lst)
+
+# This is to make a video of best individuals along the evolution
+# Use mencoder to create a video with the file list list.txt
+# mencoder mf://@list.txt -mf w=400:h=200:fps=3:type=png -ovc lavc
+# -lavcopts vcodec=mpeg4:mbd=2:trell -oac copy -o output.avi
+#
+def evolve_callback(ga_engine):
+ global LAST_SCORE
+ if ga_engine.getCurrentGeneration() % 100 == 0:
+ best = ga_engine.bestIndividual()
+ if LAST_SCORE != best.getRawScore():
+ write_tour_to_img( coords, best, "tspimg/tsp_result_%d.png" % ga_engine.getCurrentGeneration())
+ LAST_SCORE = best.getRawScore()
+ return False
+
+def main_run():
+ global cm, coords, WIDTH, HEIGHT
+
+ coords = [(random.randint(0, WIDTH), random.randint(0, HEIGHT))
+ for i in xrange(CITIES)]
+ cm = cartesian_matrix(coords)
+ genome = G1DList.G1DList(len(coords))
+
+ genome.evaluator.set(lambda chromosome: tour_length(cm, chromosome))
+ genome.crossover.set(Crossovers.G1DListCrossoverEdge)
+ genome.initializator.set(G1DListTSPInitializator)
+
+ # 3662.69
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setGenerations(200000)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setCrossoverRate(1.0)
+ ga.setMutationRate(0.02)
+ ga.setPopulationSize(80)
+
+ # This is to make a video
+ ga.stepCallback.set(evolve_callback)
+ # 21666.49
+ import psyco
+ psyco.full()
+
+ ga.evolve(freq_stats=500)
+ best = ga.bestIndividual()
+
+ if PIL_SUPPORT:
+ write_tour_to_img(coords, best, "tsp_result.png")
+ else:
+ print "No PIL detected, cannot plot the graph !"
+
+if __name__ == "__main__":
+ main_run()
diff --git a/examples/pyevolve_ex13_sphere.py b/examples/pyevolve_ex13_sphere.py
new file mode 100644
index 0000000..e040bde
--- /dev/null
+++ b/examples/pyevolve_ex13_sphere.py
@@ -0,0 +1,30 @@
+from pyevolve import G1DList
+from pyevolve import Mutators, Initializators
+from pyevolve import GSimpleGA, Consts
+
+# This is the Sphere Function
+def sphere(xlist):
+ total = 0
+ for i in xlist:
+ total += i**2
+ return total
+
+def run_main():
+ genome = G1DList.G1DList(140)
+ genome.setParams(rangemin=-5.12, rangemax=5.13)
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+ genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+ genome.evaluator.set(sphere)
+
+ ga = GSimpleGA.GSimpleGA(genome, seed=666)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(1500)
+ ga.setMutationRate(0.01)
+ ga.evolve(freq_stats=500)
+
+ best = ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
+
+
diff --git a/examples/pyevolve_ex14_ackley.py b/examples/pyevolve_ex14_ackley.py
new file mode 100644
index 0000000..ff6f6c4
--- /dev/null
+++ b/examples/pyevolve_ex14_ackley.py
@@ -0,0 +1,54 @@
+from pyevolve import G1DList, GSimpleGA, Selectors
+from pyevolve import Initializators, Mutators, Consts, DBAdapters
+import math
+
+# This is the Rastringin Function, a deception function
+def ackley(xlist):
+ sum1 = 0
+ score = 0
+ n = len(xlist)
+ for i in xrange(n):
+ sum1 += xlist[i]*xlist[i]
+ t1 = math.exp(-0.2*(math.sqrt((1.0/5.0)*sum1)))
+
+ sum1 = 0
+ for i in xrange(n):
+ sum1 += math.cos(2.0*math.pi*xlist[i]);
+ t2 = math.exp((1.0/5.0)*sum1);
+ score = 20 + math.exp(1) - 20 * t1 - t2;
+
+ return score
+
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(5)
+ genome.setParams(rangemin=-8, rangemax=8, bestrawscore=0.00, rounddecimal=2)
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+ genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(ackley)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(1000)
+ ga.setMutationRate(0.04)
+ ga.terminationCriteria.set(GSimpleGA.RawScoreCriteria)
+
+ # Create DB Adapter and set as adapter
+ # sqlite_adapter = DBAdapters.DBSQLite(identify="ackley")
+ # ga.setDBAdapter(sqlite_adapter)
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=50)
+
+ # Best individual
+ best = ga.bestIndividual()
+ print "\nBest individual score: %.2f" % (best.getRawScore(),)
+ print best
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex15_rosenbrock.py b/examples/pyevolve_ex15_rosenbrock.py
new file mode 100644
index 0000000..9403ea7
--- /dev/null
+++ b/examples/pyevolve_ex15_rosenbrock.py
@@ -0,0 +1,52 @@
+from pyevolve import G1DList, GSimpleGA, Selectors, Statistics
+from pyevolve import Initializators, Mutators, Consts, DBAdapters
+
+# This is the Rosenbrock Function
+def rosenbrock(xlist):
+ sum_var = 0
+ for x in xrange(1, len(xlist)):
+ sum_var += 100.0 * (xlist[x] - xlist[x-1]**2)**2 + (1 - xlist[x-1])**2
+ return sum_var
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(15)
+ genome.setParams(rangemin=-1, rangemax=1.1)
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+ genome.mutator.set(Mutators.G1DListMutatorRealRange)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(rosenbrock)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.selector.set(Selectors.GRouletteWheel)
+ ga.setGenerations(4000)
+ ga.setCrossoverRate(0.9)
+ ga.setPopulationSize(100)
+ ga.setMutationRate(0.03)
+
+ ga.evolve(freq_stats=500)
+
+ # Best individual
+ best = ga.bestIndividual()
+ print "\nBest individual score: %.2f" % (best.score,)
+ print best
+
+
+if __name__ == "__main__":
+ run_main()
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pyevolve_ex16_g2dbinstr.py b/examples/pyevolve_ex16_g2dbinstr.py
new file mode 100644
index 0000000..3b284d5
--- /dev/null
+++ b/examples/pyevolve_ex16_g2dbinstr.py
@@ -0,0 +1,37 @@
+from pyevolve import G2DBinaryString
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import Crossovers
+from pyevolve import Mutators
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome
+ for i in xrange(chromosome.getHeight()):
+ for j in xrange(chromosome.getWidth()):
+ # You can use the chromosome.getItem(i, j)
+ if chromosome[i][j]==0:
+ score += 0.1
+ return score
+
+# Genome instance
+genome = G2DBinaryString.G2DBinaryString(8, 5)
+
+# The evaluator function (objective function)
+genome.evaluator.set(eval_func)
+genome.crossover.set(Crossovers.G2DBinaryStringXSingleHPoint)
+genome.mutator.set(Mutators.G2DBinaryStringMutatorSwap)
+
+# Genetic Algorithm Instance
+ga = GSimpleGA.GSimpleGA(genome)
+ga.setGenerations(200)
+
+# Do the evolution, with stats dump
+# frequency of 10 generations
+ga.evolve(freq_stats=10)
+
+# Best individual
+print ga.bestIndividual()
diff --git a/examples/pyevolve_ex17_gtree.py b/examples/pyevolve_ex17_gtree.py
new file mode 100644
index 0000000..6c3a286
--- /dev/null
+++ b/examples/pyevolve_ex17_gtree.py
@@ -0,0 +1,44 @@
+from pyevolve import GSimpleGA
+from pyevolve import GTree
+from pyevolve import Crossovers
+from pyevolve import Mutators
+import time
+import random
+
+def eval_func(chromosome):
+ score = 0.0
+ # If you want to add score values based
+ # in the height of the Tree, the extra
+ # code is commented.
+
+ #height = chromosome.getHeight()
+
+ for node in chromosome:
+ score += (100 - node.getData())*0.1
+
+ #if height <= chromosome.getParam("max_depth"):
+ # score += (score*0.8)
+
+ return score
+
+def run_main():
+ genome = GTree.GTree()
+ root = GTree.GTreeNode(2)
+ genome.setRoot(root)
+ genome.processNodes()
+
+ genome.setParams(max_depth=3, max_siblings=2, method="grow")
+ genome.evaluator.set(eval_func)
+ genome.crossover.set(Crossovers.GTreeCrossoverSinglePointStrict)
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setGenerations(100)
+ ga.setMutationRate(0.05)
+
+ ga.evolve(freq_stats=10)
+ print ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
+
+
diff --git a/examples/pyevolve_ex18_gp.py b/examples/pyevolve_ex18_gp.py
new file mode 100644
index 0000000..05c683d
--- /dev/null
+++ b/examples/pyevolve_ex18_gp.py
@@ -0,0 +1,47 @@
+from pyevolve import Util
+from pyevolve import GTree
+from pyevolve import GSimpleGA
+from pyevolve import Consts
+import math
+
+rmse_accum = Util.ErrorAccumulator()
+
+def gp_add(a, b): return a+b
+def gp_sub(a, b): return a-b
+def gp_mul(a, b): return a*b
+def gp_sqrt(a): return math.sqrt(abs(a))
+
+def eval_func(chromosome):
+ global rmse_accum
+ rmse_accum.reset()
+ code_comp = chromosome.getCompiledCode()
+
+ for a in xrange(0, 5):
+ for b in xrange(0, 5):
+ evaluated = eval(code_comp)
+ target = math.sqrt((a*a)+(b*b))
+ rmse_accum += (target, evaluated)
+
+ return rmse_accum.getRMSE()
+
+def main_run():
+ genome = GTree.GTreeGP()
+ genome.setParams(max_depth=4, method="ramped")
+ genome.evaluator += eval_func
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_prefix = "gp")
+
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(50)
+ ga.setCrossoverRate(1.0)
+ ga.setMutationRate(0.25)
+ ga.setPopulationSize(800)
+
+ ga(freq_stats=10)
+ best = ga.bestIndividual()
+ print best
+
+if __name__ == "__main__":
+ main_run()
diff --git a/examples/pyevolve_ex19_gp.py b/examples/pyevolve_ex19_gp.py
new file mode 100644
index 0000000..323067b
--- /dev/null
+++ b/examples/pyevolve_ex19_gp.py
@@ -0,0 +1,94 @@
+from pyevolve import GSimpleGA
+from pyevolve import GTree
+from pyevolve import Consts
+from pyevolve import Selectors
+from pyevolve import Mutators
+from math import sqrt
+import pydot
+import random
+
+def gp_add(a, b):
+ assert len(a)==len(b)
+ new_list = [x+y for x,y in zip(a,b)]
+ return new_list
+
+#def gp_sub(a, b):
+# assert len(a)==len(b)
+# new_list = [x-y for x,y in zip(a,b)]
+# return new_list
+
+def prot_div(a, b):
+ if b==0:
+ return b
+ else:
+ return a/b
+
+#def gp_div(a,b):
+# assert len(a)==len(b)
+# new_list = [prot_div(x,float(y)) for x,y in zip(a,b)]
+# return new_list
+
+def gp_mul(a,b):
+ assert len(a)==len(b)
+ new_list = [x*y for x,y in zip(a,b)]
+ return new_list
+
+def random_lists(size):
+ list_a = [random.randint(1,20) for i in xrange(size)]
+ list_b = [random.randint(1,20) for i in xrange(size)]
+
+ return (list_a, list_b)
+
+
+def eval_func(chromosome):
+ sz = 20
+ code_comp = chromosome.getCompiledCode()
+ square_accum = 0.0
+
+ for j in xrange(sz):
+ a, b = random_lists(5)
+ target_list = gp_add(gp_mul(a,b),gp_mul(a,b))
+ ret_list = eval(code_comp)
+ square_accum += (sum(target_list)-sum(ret_list))**2
+
+ RMSE = sqrt(square_accum / float(sz))
+ score = (1.0 / (RMSE+1.0))
+ return score
+
+def main_run():
+ genome = GTree.GTreeGP()
+ root = GTree.GTreeNodeGP('a', Consts.nodeType["TERMINAL"])
+ genome.setRoot(root)
+
+ genome.setParams(max_depth=2, method="ramped")
+ genome.evaluator += eval_func
+ genome.mutator.set(Mutators.GTreeGPMutatorSubtree)
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_prefix = "gp")
+
+ ga.setMinimax(Consts.minimaxType["maximize"])
+ ga.setGenerations(500)
+ ga.setCrossoverRate(1.0)
+ ga.setMutationRate(0.08)
+ ga.setPopulationSize(80)
+
+ ga(freq_stats=1)
+ print ga.bestIndividual()
+
+ graph = pydot.Dot()
+ ga.bestIndividual().writeDotGraph(graph)
+ graph.write_jpeg('tree.png', prog='dot')
+
+if __name__ == "__main__":
+ main_run()
+ #import hotshot, hotshot.stats
+ #prof = hotshot.Profile("ev.prof")
+ #prof.runcall(main_run)
+ #prof.close()
+ #stats = hotshot.stats.load("ev.prof")
+ #stats.strip_dirs()
+ #stats.sort_stats('time', 'calls')
+ #stats.print_stats(20)
+
diff --git a/examples/pyevolve_ex1_simple.py b/examples/pyevolve_ex1_simple.py
new file mode 100644
index 0000000..028c350
--- /dev/null
+++ b/examples/pyevolve_ex1_simple.py
@@ -0,0 +1,54 @@
+from pyevolve import G1DList
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import Statistics
+from pyevolve import DBAdapters
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(genome):
+ score = 0.0
+
+ # iterate over the chromosome
+ # The same as "score = len(filter(lambda x: x==0, genome))"
+ for value in genome:
+ if value==0:
+ score += 1
+
+ return score
+
+def run_main():
+ # Genome instance, 1D List of 50 elements
+ genome = G1DList.G1DList(50)
+
+ # Sets the range max and min of the 1D List
+ genome.setParams(rangemin=0, rangemax=10)
+
+ # The evaluator function (evaluation function)
+ genome.evaluator.set(eval_func)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+
+ # Set the Roulette Wheel selector method, the number of generations and
+ # the termination criteria
+ ga.selector.set(Selectors.GRouletteWheel)
+ ga.setGenerations(500)
+ ga.terminationCriteria.set(GSimpleGA.ConvergenceCriteria)
+
+ # Sets the DB Adapter, the resetDB flag will make the Adapter recreate
+ # the database and erase all data every run, you should use this flag
+ # just in the first time, after the pyevolve.db was created, you can
+ # omit it.
+ sqlite_adapter = DBAdapters.DBSQLite(identify="ex1", resetDB=True)
+ ga.setDBAdapter(sqlite_adapter)
+
+ # Do the evolution, with stats dump
+ # frequency of 20 generations
+ ga.evolve(freq_stats=20)
+
+ # Best individual
+ print ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex20_gp_dotwrite.py b/examples/pyevolve_ex20_gp_dotwrite.py
new file mode 100644
index 0000000..e38d587
--- /dev/null
+++ b/examples/pyevolve_ex20_gp_dotwrite.py
@@ -0,0 +1,56 @@
+from pyevolve import *
+import math
+
+rmse_accum = Util.ErrorAccumulator()
+
+def gp_add(a, b): return a+b
+def gp_sub(a, b): return a-b
+def gp_mul(a, b): return a*b
+def gp_sqrt(a): return math.sqrt(abs(a))
+
+def eval_func(chromosome):
+ global rmse_accum
+ rmse_accum.reset()
+ code_comp = chromosome.getCompiledCode()
+
+ for a in xrange(0, 5):
+ for b in xrange(0, 5):
+ evaluated = eval(code_comp)
+ target = math.sqrt((a*a)+(b*b))
+ rmse_accum += (target, evaluated)
+ return rmse_accum.getRMSE()
+
+
+def step_callback(engine):
+ if engine.getCurrentGeneration() == 0:
+ GTree.GTreeGP.writePopulationDotRaw(engine, "pop.dot", 0, 40)
+ return False
+
+
+def main_run():
+ genome = GTree.GTreeGP()
+ genome.setParams(max_depth=6, method="ramped")
+ genome.evaluator += eval_func
+ genome.mutator.set(Mutators.GTreeGPMutatorSubtree)
+
+ ga = GSimpleGA.GSimpleGA(genome, seed=666)
+ ga.stepCallback.set(step_callback)
+ ga.setParams(gp_terminals = ['a', 'b'],
+ gp_function_prefix = "gp")
+
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(2)
+ ga.setCrossoverRate(1.0)
+ ga.setMutationRate(0.08)
+ ga.setPopulationSize(100)
+ ga.setMultiProcessing(False)
+
+ ga(freq_stats=5)
+
+ #GTree.GTreeGP.writePopulationDotRaw(ga, "pop.dot", 0, 14)
+
+ best = ga.bestIndividual()
+
+
+if __name__ == "__main__":
+ main_run()
diff --git a/examples/pyevolve_ex21_nqueens.py b/examples/pyevolve_ex21_nqueens.py
new file mode 100644
index 0000000..d295f23
--- /dev/null
+++ b/examples/pyevolve_ex21_nqueens.py
@@ -0,0 +1,58 @@
+from pyevolve import G1DList
+from pyevolve import Mutators, Crossovers
+from pyevolve import Consts, GSimpleGA
+from pyevolve import DBAdapters
+from random import shuffle
+
+# The "n" in n-queens
+BOARD_SIZE = 64
+
+# The n-queens fitness function
+def queens_eval(genome):
+ collisions = 0
+ for i in xrange(0, BOARD_SIZE):
+ if i not in genome: return 0
+ for i in xrange(0, BOARD_SIZE):
+ col = False
+ for j in xrange(0, BOARD_SIZE):
+ if (i != j) and (abs(i-j) == abs(genome[j]-genome[i])):
+ col = True
+ if col == True: collisions +=1
+ return BOARD_SIZE-collisions
+
+def queens_init(genome, **args):
+ genome.genomeList = range(0, BOARD_SIZE)
+ shuffle(genome.genomeList)
+
+def run_main():
+ genome = G1DList.G1DList(BOARD_SIZE)
+ genome.setParams(bestrawscore=BOARD_SIZE, rounddecimal=2)
+ genome.initializator.set(queens_init)
+ genome.mutator.set(Mutators.G1DListMutatorSwap)
+ genome.crossover.set(Crossovers.G1DListCrossoverCutCrossfill)
+ genome.evaluator.set(queens_eval)
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.terminationCriteria.set(GSimpleGA.RawScoreCriteria)
+ ga.setMinimax(Consts.minimaxType["maximize"])
+
+ ga.setPopulationSize(100)
+ ga.setGenerations(250)
+ ga.setMutationRate(0.02)
+ ga.setCrossoverRate(1.0)
+
+ #sqlite_adapter = DBAdapters.DBSQLite(identify="queens")
+ #ga.setDBAdapter(sqlite_adapter)
+
+ vpython_adapter = DBAdapters.DBVPythonGraph(identify="queens", frequency=1)
+ ga.setDBAdapter(vpython_adapter)
+
+ ga.evolve(freq_stats=10)
+
+ best = ga.bestIndividual()
+ print best
+ print "Best individual score: %.2f\n" % (best.getRawScore(),)
+
+if __name__ == "__main__":
+ run_main()
+
diff --git a/examples/pyevolve_ex22_monkey.py b/examples/pyevolve_ex22_monkey.py
new file mode 100644
index 0000000..be2a96b
--- /dev/null
+++ b/examples/pyevolve_ex22_monkey.py
@@ -0,0 +1,54 @@
+#===============================================================================
+# Pyevolve version of the Infinite Monkey Theorem
+# See: http://en.wikipedia.org/wiki/Infinite_monkey_theorem
+# By Jelle Feringa
+#===============================================================================
+
+from pyevolve import G1DList
+from pyevolve import GSimpleGA, Consts
+from pyevolve import Selectors
+from pyevolve import Initializators, Mutators, Crossovers
+import math
+
+sentence = """
+'Just living is not enough,' said the butterfly,
+'one must have sunshine, freedom, and a little flower.'
+"""
+numeric_sentence = map(ord, sentence)
+
+def evolve_callback(ga_engine):
+ generation = ga_engine.getCurrentGeneration()
+ if generation%50==0:
+ indiv = ga_engine.bestIndividual()
+ print ''.join(map(chr,indiv))
+ return False
+
+def run_main():
+ genome = G1DList.G1DList(len(sentence))
+ genome.setParams(rangemin=min(numeric_sentence),
+ rangemax=max(numeric_sentence),
+ bestrawscore=0.00,
+ gauss_mu=1, gauss_sigma=4)
+
+ genome.initializator.set(Initializators.G1DListInitializatorInteger)
+ genome.mutator.set(Mutators.G1DListMutatorIntegerGaussian)
+ genome.evaluator.set(lambda genome: sum(
+ [abs(a-b) for a, b in zip(genome, numeric_sentence)]
+ ))
+
+ ga = GSimpleGA.GSimpleGA(genome)
+ #ga.stepCallback.set(evolve_callback)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.terminationCriteria.set(GSimpleGA.RawScoreCriteria)
+ ga.setPopulationSize(60)
+ ga.setMutationRate(0.02)
+ ga.setCrossoverRate(0.9)
+ ga.setGenerations(5000)
+ ga.evolve(freq_stats=100)
+
+ best = ga.bestIndividual()
+ print "Best individual score: %.2f" % (best.score,)
+ print ''.join(map(chr, best))
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex2_realgauss.py b/examples/pyevolve_ex2_realgauss.py
new file mode 100644
index 0000000..168c7b2
--- /dev/null
+++ b/examples/pyevolve_ex2_realgauss.py
@@ -0,0 +1,42 @@
+from pyevolve import GSimpleGA
+from pyevolve import G1DList
+from pyevolve import Selectors
+from pyevolve import Initializators, Mutators
+
+# Find negative element
+def eval_func(genome):
+ score = 0.0
+
+ for element in genome:
+ if element < 0: score += 0.1
+
+ return score
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(20)
+ genome.setParams(rangemin=-6.0, rangemax=6.0)
+
+ # Change the initializator to Real values
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+
+ # Change the mutator to Gaussian Mutator
+ genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.selector.set(Selectors.GRouletteWheel)
+ ga.setGenerations(100)
+
+ # Do the evolution
+ ga.evolve(freq_stats=10)
+
+ # Best individual
+ print ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
+
diff --git a/examples/pyevolve_ex3_schaffer.py b/examples/pyevolve_ex3_schaffer.py
new file mode 100644
index 0000000..3270d76
--- /dev/null
+++ b/examples/pyevolve_ex3_schaffer.py
@@ -0,0 +1,46 @@
+from pyevolve import G1DList, GSimpleGA, Selectors
+from pyevolve import Initializators, Mutators, Consts
+import math
+
+# This is the Schaffer F6 Function
+# This function has been conceived by Schaffer, it's a
+# multimodal function and it's hard for GAs due to the
+# large number of local minima, the global minimum is
+# at x=0,y=0 and there are many local minima around it
+def schafferF6(genome):
+ t1 = math.sin(math.sqrt(genome[0]**2 + genome[1]**2));
+ t2 = 1.0 + 0.001*(genome[0]**2 + genome[1]**2);
+ score = 0.5 + (t1*t1 - 0.5)/(t2*t2)
+ return score
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(2)
+ genome.setParams(rangemin=-100.0, rangemax=100.0, bestrawscore=0.0000, rounddecimal=4)
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+ genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(schafferF6)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.selector.set(Selectors.GRouletteWheel)
+
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(8000)
+ ga.setMutationRate(0.05)
+ ga.setPopulationSize(100)
+ ga.terminationCriteria.set(GSimpleGA.RawScoreCriteria)
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=250)
+
+ # Best individual
+ best = ga.bestIndividual()
+ print best
+ print "Best individual score: %.2f" % best.getRawScore()
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex4_sigmatrunc.py b/examples/pyevolve_ex4_sigmatrunc.py
new file mode 100644
index 0000000..91a406c
--- /dev/null
+++ b/examples/pyevolve_ex4_sigmatrunc.py
@@ -0,0 +1,49 @@
+from pyevolve import G1DList
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import Initializators, Mutators
+from pyevolve import Scaling
+from pyevolve import Consts
+import math
+
+def eval_func(ind):
+ score = 0.0
+ var_x = ind[0]
+ var_z = var_x**2+2*var_x+1*math.cos(var_x)
+ return var_z
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(1)
+ genome.setParams(rangemin=-60.0, rangemax=60.0)
+
+ # Change the initializator to Real values
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+
+ # Change the mutator to Gaussian Mutator
+ genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+
+ # Removes the default crossover
+ genome.crossover.clear()
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+
+ pop = ga.getPopulation()
+ pop.scaleMethod.set(Scaling.SigmaTruncScaling)
+
+ ga.selector.set(Selectors.GRouletteWheel)
+ ga.setGenerations(100)
+
+ # Do the evolution
+ ga.evolve(10)
+
+ # Best individual
+ print ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex5_callback.py b/examples/pyevolve_ex5_callback.py
new file mode 100644
index 0000000..233c7d4
--- /dev/null
+++ b/examples/pyevolve_ex5_callback.py
@@ -0,0 +1,45 @@
+from pyevolve import G1DList
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+
+# The step callback function, this function
+# will be called every step (generation) of the GA evolution
+def evolve_callback(ga_engine):
+ generation = ga_engine.getCurrentGeneration()
+ if generation % 100 == 0:
+ print "Current generation: %d" % (generation,)
+ print ga_engine.getStatistics()
+ return False
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(genome):
+ score = 0.0
+ # iterate over the chromosome
+ for value in genome:
+ if value==0: score += 0.1
+ return score
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(200)
+ genome.setParams(rangemin=0, rangemax=10)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.selector.set(Selectors.GRouletteWheel)
+ ga.setGenerations(800)
+ ga.stepCallback.set(evolve_callback)
+
+ # Do the evolution
+ ga.evolve()
+
+ # Best individual
+ print ga.bestIndividual()
+
+if __name__ == "__main__":
+ run_main()
+
diff --git a/examples/pyevolve_ex6_dbadapter.py b/examples/pyevolve_ex6_dbadapter.py
new file mode 100644
index 0000000..33aa5f7
--- /dev/null
+++ b/examples/pyevolve_ex6_dbadapter.py
@@ -0,0 +1,47 @@
+from pyevolve import G1DList
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import DBAdapters
+from pyevolve import Statistics
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome
+ for value in chromosome:
+ if value==0:
+ score += 0.5
+ return score
+
+# Genome instance
+genome = G1DList.G1DList(100)
+genome.setParams(rangemin=0, rangemax=10)
+
+# The evaluator function (objective function)
+genome.evaluator.set(eval_func)
+
+# Genetic Algorithm Instance
+ga = GSimpleGA.GSimpleGA(genome, 666)
+ga.setGenerations(80)
+ga.setMutationRate(0.2)
+
+# Create DB Adapter and set as adapter
+#sqlite_adapter = DBAdapters.DBSQLite(identify="ex6", resetDB=True)
+#ga.setDBAdapter(sqlite_adapter)
+
+# Using CSV Adapter
+#csvfile_adapter = DBAdapters.DBFileCSV()
+#ga.setDBAdapter(csvfile_adapter)
+
+# Using the URL Post Adapter
+# urlpost_adapter = DBAdapters.DBURLPost(url="http://whatismyip.oceanus.ro/server_variables.php", post=False)
+# ga.setDBAdapter(urlpost_adapter)
+
+# Do the evolution, with stats dump
+# frequency of 10 generations
+ga.evolve(freq_stats=10)
+
+# Best individual
+#print ga.bestIndividual()
diff --git a/examples/pyevolve_ex7_rastrigin.py b/examples/pyevolve_ex7_rastrigin.py
new file mode 100644
index 0000000..ef6226b
--- /dev/null
+++ b/examples/pyevolve_ex7_rastrigin.py
@@ -0,0 +1,40 @@
+from pyevolve import GSimpleGA
+from pyevolve import G1DList
+from pyevolve import Mutators, Initializators
+from pyevolve import Selectors
+from pyevolve import Consts
+import math
+
+# This is the Rastrigin Function, a deception function
+def rastrigin(genome):
+ n = len(genome)
+ total = 0
+ for i in xrange(n):
+ total += genome[i]**2 - 10*math.cos(2*math.pi*genome[i])
+ return (10*n) + total
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(20)
+ genome.setParams(rangemin=-5.2, rangemax=5.30, bestrawscore=0.00, rounddecimal=2)
+ genome.initializator.set(Initializators.G1DListInitializatorReal)
+ genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+
+ genome.evaluator.set(rastrigin)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.terminationCriteria.set(GSimpleGA.RawScoreCriteria)
+ ga.setMinimax(Consts.minimaxType["minimize"])
+ ga.setGenerations(3000)
+ ga.setCrossoverRate(0.8)
+ ga.setPopulationSize(100)
+ ga.setMutationRate(0.06)
+
+ ga.evolve(freq_stats=50)
+
+ best = ga.bestIndividual()
+ print best
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex8_gauss_int.py b/examples/pyevolve_ex8_gauss_int.py
new file mode 100644
index 0000000..1771eab
--- /dev/null
+++ b/examples/pyevolve_ex8_gauss_int.py
@@ -0,0 +1,44 @@
+from pyevolve import G1DList
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import Mutators
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome
+ for value in chromosome:
+ if value==0:
+ score += 0.1
+ return score
+
+
+def run_main():
+ # Genome instance
+ genome = G1DList.G1DList(40)
+
+ # The gauss_mu and gauss_sigma is used to the Gaussian Mutator, but
+ # if you don't specify, the mutator will use the defaults
+ genome.setParams(rangemin=0, rangemax=10, gauss_mu=4, gauss_sigma=6)
+ genome.mutator.set(Mutators.G1DListMutatorIntegerGaussian)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ #ga.selector.set(Selectors.GRouletteWheel)
+ ga.setGenerations(800)
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=150)
+
+ # Best individual
+ print ga.bestIndividual()
+
+
+if __name__ == "__main__":
+ run_main()
diff --git a/examples/pyevolve_ex9_g2dlist.py b/examples/pyevolve_ex9_g2dlist.py
new file mode 100644
index 0000000..41ad83e
--- /dev/null
+++ b/examples/pyevolve_ex9_g2dlist.py
@@ -0,0 +1,43 @@
+from pyevolve import G2DList
+from pyevolve import GSimpleGA
+from pyevolve import Selectors
+from pyevolve import Crossovers
+from pyevolve import Mutators
+
+# This function is the evaluation function, we want
+# to give high score to more zero'ed chromosomes
+def eval_func(chromosome):
+ score = 0.0
+
+ # iterate over the chromosome
+ for i in xrange(chromosome.getHeight()):
+ for j in xrange(chromosome.getWidth()):
+ # You can use the chromosome.getItem(i, j) too
+ if chromosome[i][j]==0:
+ score += 0.1
+ return score
+
+def run_main():
+ # Genome instance
+ genome = G2DList.G2DList(8, 5)
+ genome.setParams(rangemin=0, rangemax=100)
+
+ # The evaluator function (objective function)
+ genome.evaluator.set(eval_func)
+ genome.crossover.set(Crossovers.G2DListCrossoverSingleHPoint)
+ genome.mutator.set(Mutators.G2DListMutatorIntegerRange)
+
+ # Genetic Algorithm Instance
+ ga = GSimpleGA.GSimpleGA(genome)
+ ga.setGenerations(800)
+
+ # Do the evolution, with stats dump
+ # frequency of 10 generations
+ ga.evolve(freq_stats=100)
+
+ # Best individual
+ print ga.bestIndividual()
+
+
+if __name__ == "__main__":
+ run_main()
diff --git a/pyevolve/Consts.py b/pyevolve/Consts.py
new file mode 100644
index 0000000..b6ab473
--- /dev/null
+++ b/pyevolve/Consts.py
@@ -0,0 +1,531 @@
+"""
+
+:mod:`Consts` -- constants module
+============================================================================
+
+Pyevolve have defaults in all genetic operators, settings and etc, this is an issue to helps the user in the API use and minimize the source code needed to make simple things. In the module :mod:`Consts`, you will find those defaults settings. You are encouraged to see the constants, but not to change directly on the module, there are methods for this.
+
+General constants
+----------------------------------------------------------------------------
+
+.. attribute:: CDefPythonRequire
+
+ The mininum version required to run Pyevolve.
+
+.. attribute:: CDefLogFile
+
+ The default log filename.
+
+.. attribute:: CDefLogLevel
+
+ Default log level.
+
+.. attribute:: sortType
+
+ Sort type, raw or scaled.
+
+ Example:
+ >>> sort_type = Consts.sortType["raw"]
+ >>> sort_type = Consts.sortType["scaled"]
+
+.. attribute:: minimaxType
+
+ The Min/Max type, maximize or minimize the evaluation function.
+
+ Example:
+ >>> minmax = Consts.minimaxType["minimize"]
+ >>> minmax = Consts.minimaxType["maximize]
+
+.. attribute:: CDefESCKey
+
+ The ESC key ASCII code. Used to start Interactive Mode.
+
+.. attribute:: CDefRangeMin
+
+ Minimum range. This constant is used as integer and real max/min.
+
+.. attribute:: CDefRangeMax
+
+ Maximum range. This constant is used as integer and real max/min.
+
+.. attribute:: CDefBroadcastAddress
+
+ The broadcast address for UDP, 255.255.255.255
+
+.. attribute:: CDefImportList
+
+ The import list and messages
+
+.. attribute:: nodeType
+
+ The genetic programming node types, can be "TERMINAL":0 or "NONTERMINAL":1
+
+.. attribute:: CDefGPGenomes
+
+ The classes which are used in Genetic Programming, used to detected the
+ correct mode when starting the evolution
+
+Selection methods constants (:mod:`Selectors`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefTournamentPoolSize
+
+ The default pool size for the Tournament Selector (:func:`Selectors.GTournamentSelector`).
+
+Scaling scheme constants (:mod:`Scaling`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefScaleLinearMultiplier
+
+ The multiplier of the Linear (:func:`Scaling.LinearScaling`) scaling scheme.
+
+.. attribute:: CDefScaleSigmaTruncMultiplier
+
+ The default Sigma Truncation (:func:`Scaling.SigmaTruncScaling`) scaling scheme.
+
+.. attribute:: CDefScalePowerLawFactor
+
+ The default Power Law (:func:`Scaling.PowerLawScaling`) scaling scheme factor.
+
+.. attribute:: CDefScaleBoltzMinTemp
+
+ The default mininum temperature of the (:func:`Scaling.BoltzmannScaling`) scaling scheme factor.
+
+.. attribute:: CDefScaleBoltzFactor
+
+ The default Boltzmann Factor of (:func:`Scaling.BoltzmannScaling`) scaling scheme factor.
+ This is the factor that the temperature will be subtracted.
+
+.. attribute:: CDefScaleBoltzStart
+
+ The default Boltzmann start temperature (:func:`Scaling.BoltzmannScaling`).
+ If you don't set the start temperature parameter, this will be the default initial
+ temperature for the Boltzmann scaling scheme.
+
+Population constants (:class:`GPopulation.GPopulation`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefPopSortType
+
+ Default sort type parameter.
+
+.. attribute:: CDefPopMinimax
+
+ Default min/max parameter.
+
+.. attribute:: CDefPopScale
+
+ Default scaling scheme.
+
+
+1D Binary String Defaults (:class:`G1DBinaryString.G1DBinaryString`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefG1DBinaryStringMutator
+
+ The default mutator for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome.
+
+.. attribute:: CDefG1DBinaryStringCrossover
+
+ The default crossover method for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome.
+
+.. attribute:: CDefG1DBinaryStringInit
+
+ The default initializator for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome.
+
+.. attribute:: CDefG1DBinaryStringUniformProb
+
+ The default uniform probability used for some uniform genetic operators for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome.
+
+
+2D Binary String Defaults (:class:`G2DBinaryString.G2DBinaryString`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefG2DBinaryStringMutator
+
+ The default mutator for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome.
+
+.. attribute:: CDefG2DBinaryStringCrossover
+
+ The default crossover method for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome.
+
+.. attribute:: CDefG2DBinaryStringInit
+
+ The default initializator for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome.
+
+.. attribute:: CDefG2DBinaryStringUniformProb
+
+ The default uniform probability used for some uniform genetic operators for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome.
+
+
+1D List chromosome constants (:class:`G1DList.G1DList`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefG1DListMutIntMU
+
+ Default *mu* value of the 1D List Gaussian Integer Mutator (:func:`Mutators.G1DListMutatorIntegerGaussian`), the *mu* represents the mean of the distribution.
+
+.. attribute:: CDefG1DListMutIntSIGMA
+
+ Default *sigma* value of the 1D List Gaussian Integer Mutator (:func:`Mutators.G1DListMutatorIntegerGaussian`), the *sigma* represents the standard deviation of the distribution.
+
+.. attribute:: CDefG1DListMutRealMU
+
+ Default *mu* value of the 1D List Gaussian Real Mutator (:func:`Mutators.G1DListMutatorRealGaussian`), the *mu* represents the mean of the distribution.
+
+.. attribute:: CDefG1DListMutRealSIGMA
+
+ Default *sigma* value of the 1D List Gaussian Real Mutator (:func:`Mutators.G1DListMutatorRealGaussian`), the *sigma* represents the mean of the distribution.
+
+
+Tree chromosome constants (:class:`GTree.GTree`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefGTreeInit
+
+ Default initializator of the tree chromosome.
+
+.. attribute:: CDefGGTreeMutator
+
+ Default mutator of the tree chromosome.
+
+.. attribute:: CDefGTreeCrossover
+
+ Default crossover of the tree chromosome.
+
+
+2D List chromosome constants (:class:`G2DList.G2DList`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefG2DListMutRealMU
+
+ Default *mu* value of the 2D List Gaussian Real Mutator (:func:`Mutators.G2DListMutatorRealGaussian`), the *mu* represents the mean of the distribution.
+
+.. attribute:: CDefG2DListMutRealSIGMA
+
+ Default *sigma* value of the 2D List Gaussian Real Mutator (:func:`Mutators.G2DListMutatorRealGaussian`), the *sigma* represents the mean of the distribution.
+
+.. attribute:: CDefG2DListMutIntMU
+
+ Default *mu* value of the 2D List Gaussian Integer Mutator (:func:`Mutators.G2DListMutatorIntegerGaussian`), the *mu* represents the mean of the distribution.
+
+.. attribute:: CDefG2DListMutIntSIGMA
+
+ Default *sigma* value of the 2D List Gaussian Integer Mutator (:func:`Mutators.G2DListMutatorIntegerGaussian`), the *sigma* represents the mean of the distribution.
+
+.. attribute:: CDefG2DListMutator
+
+ Default mutator for the 2D List chromosome.
+
+.. attribute:: CDefG2DListCrossover
+
+ Default crossover method for the 2D List chromosome.
+
+.. attribute:: CDefG2DListInit
+
+ Default initializator for the 2D List chromosome.
+
+.. attribute:: CDefG2DListCrossUniformProb
+
+ Default uniform probability for the 2D List Uniform Crossover method (:func:`Crossovers.G2DListCrossoverUniform`).
+
+
+GA Engine constants (:class:`GSimpleGA.GSimpleGA`)
+----------------------------------------------------------------------------
+
+.. attribute:: CDefGAGenerations
+
+ Default number of generations.
+
+.. attribute:: CDefGAMutationRate
+
+ Default mutation rate.
+
+.. attribute:: CDefGACrossoverRate
+
+ Default crossover rate.
+
+.. attribute:: CDefGAPopulationSize
+
+ Default population size.
+
+.. attribute:: CDefGASelector
+
+ Default selector method.
+
+DB Adapters constants (:mod:`DBAdapters`)
+----------------------------------------------------------------------------
+Constants for the DB Adapters
+
+
+SQLite3 DB Adapter Constants (:class:`DBAdapters.DBSQLite`)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. attribute:: CDefSQLiteDBName
+
+ Default database filename.
+
+.. attribute:: CDefSQLiteDBTable
+
+ Default statistical table name.
+
+.. attribute:: CDefSQLiteDBTablePop
+
+ Default population statistical table name.
+
+.. attribute:: CDefSQLiteStatsGenFreq
+
+ Default generational frequency for dump statistics.
+
+.. attribute:: CDefSQLiteStatsCommitFreq
+
+ Default commit frequency.
+
+
+MySQL DB Adapter Constants (:class:`DBAdapters.DBMySQLAdapter`)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. attribute:: CDefMySQLDBName
+
+ Default database name.
+
+.. attribute:: CDefMySQLDBTable
+
+ Default statistical table name.
+
+.. attribute:: CDefMySQLDBTablePop
+
+ Default population statistical table name.
+
+.. attribute:: CDefMySQLStatsGenFreq
+
+ Default generational frequency for dump statistics.
+
+.. attribute:: CDefMySQLStatsCommitFreq
+
+ Default commit frequency.
+
+.. attribute:: CDefMySQLDBHost
+
+ Default MySQL connection host.
+
+.. attribute:: CDefMySQLDBPort
+
+ Default MySQL connection TCP port.
+
+
+URL Post DB Adapter Constants (:class:`DBAdapters.DBURLPost`)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. attribute:: CDefURLPostStatsGenFreq
+
+ Default generational frequency for dump statistics.
+
+
+CSV File DB Adapter Constants (:class:`DBAdapters.DBFileCSV`)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. attribute:: CDefCSVFileName
+
+ The default CSV filename to dump statistics.
+
+.. attribute:: CDefCSVFileStatsGenFreq
+
+ Default generational frequency for dump statistics.
+
+
+XMP RPC DB Adapter Constants (:class:`DBAdapters.DBXMLRPC`)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. attribute:: CDefXMLRPCStatsGenFreq
+
+ Default generational frequency for dump statistics.
+
+Migration Constants (:mod:`Migration`)
+----------------------------------------------------------------------------
+.. attribute:: CDefGenMigrationRate
+
+ The default generations supposed to migrate and receive individuals
+
+.. attribute:: CDefMigrationNIndividuals
+
+ The default number of individuals that will migrate at the *CDefGenMigrationRate*
+ interval
+
+.. attribute:: CDefNetworkIndividual
+
+ A migration code for network individual data
+
+.. attribute:: CDefNetworkInfo
+
+ A migration code for network info data
+
+.. attribute:: CDefGenMigrationReplacement
+
+ The default number of individuals to be replaced at the migration stage
+
+
+"""
+import Scaling
+import Selectors
+import Initializators
+import Mutators
+import Crossovers
+import logging
+from GTree import GTreeGP
+
+# Required python version 2.5+
+CDefPythonRequire = (2, 5)
+
+# Logging system
+CDefLogFile = "pyevolve.log"
+CDefLogLevel = logging.DEBUG
+
+# Types of sort
+# - raw: uses the "score" attribute
+# - scaled: uses the "fitness" attribute
+sortType = {
+ "raw" : 0,
+ "scaled" : 1
+}
+
+# Optimization type
+# - Minimize or Maximize the Evaluator Function
+minimaxType = { "minimize" : 0,
+ "maximize" : 1
+ }
+
+CDefESCKey = 27
+
+CDefImportList = {"visual.graph": "you must install VPython !",
+ "csv" : "csv module not found !",
+ "urllib" : "urllib module not found !",
+ "sqlite3": "sqlite3 module not found, are you using Jython or IronPython ?",
+ "xmlrpclib" : "xmlrpclib module not found !",
+ "MySQLdb" : "MySQLdb module not found, you must install mysql-python !",
+ "pydot" : "Pydot module not found, you must install Pydot to plot graphs !"}
+
+####################
+# Defaults section #
+####################
+
+# - Tournament selector
+CDefTournamentPoolSize = 2
+
+# - Scale methods defaults
+CDefScaleLinearMultiplier = 1.2
+CDefScaleSigmaTruncMultiplier = 2.0
+CDefScalePowerLawFactor = 1.0005
+CDefScaleBoltzMinTemp = 1.0
+CDefScaleBoltzFactor = 0.05
+# 40 temp. = 500 generations
+CDefScaleBoltzStart = 40.0
+
+# - Population Defaults
+CDefPopSortType = sortType["scaled"]
+CDefPopMinimax = minimaxType["maximize"]
+CDefPopScale = Scaling.LinearScaling
+
+# - GA Engine defaults
+CDefGAGenerations = 100
+CDefGAMutationRate = 0.02
+CDefGACrossoverRate = 0.9
+CDefGAPopulationSize = 80
+CDefGASelector = Selectors.GRankSelector
+CDefGAElitismReplacement = 1
+
+# - This is general used by integer/real ranges defaults
+CDefRangeMin = 0
+CDefRangeMax = 100
+
+# - G1DBinaryString defaults
+CDefG1DBinaryStringMutator = Mutators.G1DBinaryStringMutatorFlip
+CDefG1DBinaryStringCrossover = Crossovers.G1DBinaryStringXSinglePoint
+CDefG1DBinaryStringInit = Initializators.G1DBinaryStringInitializator
+CDefG1DBinaryStringUniformProb = 0.5
+
+# - G2DBinaryString defaults
+CDefG2DBinaryStringMutator = Mutators.G2DBinaryStringMutatorFlip
+CDefG2DBinaryStringCrossover = Crossovers.G2DBinaryStringXUniform
+CDefG2DBinaryStringInit = Initializators.G2DBinaryStringInitializator
+CDefG2DBinaryStringUniformProb = 0.5
+
+# - GTree defaults
+CDefGTreeInit = Initializators.GTreeInitializatorInteger
+CDefGGTreeMutator = Mutators.GTreeMutatorIntegerRange
+CDefGTreeCrossover = Crossovers.GTreeCrossoverSinglePointStrict
+
+# - GTreeGP defaults
+CDefGTreeGPInit = Initializators.GTreeGPInitializator
+CDefGGTreeGPMutator = Mutators.GTreeGPMutatorSubtree
+CDefGTreeGPCrossover = Crossovers.GTreeGPCrossoverSinglePoint
+
+# - G1DList defaults
+CDefG1DListMutIntMU = 2
+CDefG1DListMutIntSIGMA = 10
+
+CDefG1DListMutRealMU = 0
+CDefG1DListMutRealSIGMA = 1
+
+CDefG1DListMutator = Mutators.G1DListMutatorSwap
+CDefG1DListCrossover = Crossovers.G1DListCrossoverSinglePoint
+CDefG1DListInit = Initializators.G1DListInitializatorInteger
+CDefG1DListCrossUniformProb = 0.5
+
+# SBX Crossover defaults
+# Crossover distribution index for SBX
+CDefG1DListSBXEtac = 10
+CDefG1DListSBXEPS = 1.0e-14
+
+# - G2DList defaults
+CDefG2DListMutIntMU = 2
+CDefG2DListMutIntSIGMA = 10
+
+CDefG2DListMutRealMU = 0
+CDefG2DListMutRealSIGMA = 1
+
+CDefG2DListMutator = Mutators.G2DListMutatorSwap
+CDefG2DListCrossover = Crossovers.G2DListCrossoverUniform
+CDefG2DListInit = Initializators.G2DListInitializatorInteger
+CDefG2DListCrossUniformProb = 0.5
+
+# - DB Adapters SQLite defaults
+CDefSQLiteDBName = "pyevolve.db"
+CDefSQLiteDBTable = "statistics"
+CDefSQLiteDBTablePop = "population"
+CDefSQLiteStatsGenFreq = 1
+CDefSQLiteStatsCommitFreq = 300
+
+# - DB Adapters MySQL defaults
+CDefMySQLDBName = "pyevolve"
+CDefMySQLDBTable = "statistics"
+CDefMySQLDBTablePop = "population"
+CDefMySQLDBHost = "localhost"
+CDefMySQLDBPort = 3306
+CDefMySQLStatsGenFreq = 1
+CDefMySQLStatsCommitFreq = 300
+
+# - DB Adapters URL Post defaults
+CDefURLPostStatsGenFreq = 100
+
+# - DB Adapters CSV File defaults
+CDefCSVFileName = "pyevolve.csv"
+CDefCSVFileStatsGenFreq = 1
+
+# - DB Adapter XML RPC
+CDefXMLRPCStatsGenFreq = 20
+
+# Util Consts
+CDefBroadcastAddress = "255.255.255.255"
+nodeType = {"TERMINAL" : 0, "NONTERMINAL": 1}
+
+CDefGPGenomes = [GTreeGP]
+
+# Migration Consts
+CDefGenMigrationRate = 20
+CDefMigrationNIndividuals = 3
+CDefGenMigrationReplacement = 3
+
+CDefNetworkIndividual = 1
+CDefNetworkInfo = 2
+
diff --git a/pyevolve/Crossovers.py b/pyevolve/Crossovers.py
new file mode 100644
index 0000000..7895f3d
--- /dev/null
+++ b/pyevolve/Crossovers.py
@@ -0,0 +1,784 @@
+"""
+
+:mod:`Crossovers` -- crossover methods module
+=====================================================================
+
+In this module we have the genetic operators of crossover (or recombination) for each chromosome representation.
+
+"""
+
+from random import randint as rand_randint, choice as rand_choice
+from random import random as rand_random
+import math
+import Util
+import Consts
+
+#############################
+## 1D Binary String ##
+#############################
+
+def G1DBinaryStringXSinglePoint(genome, **args):
+ """ The crossover of 1D Binary String, Single Point
+
+ .. warning:: You can't use this crossover method for binary strings with length of 1.
+
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ if len(gMom) == 1:
+ Util.raiseException("The Binary String have one element, can't use the Single Point Crossover method !", TypeError)
+
+ cut = rand_randint(1, len(gMom)-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ sister[cut:] = gDad[cut:]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ brother[cut:] = gMom[cut:]
+
+ return (sister, brother)
+
+def G1DBinaryStringXTwoPoint(genome, **args):
+ """ The 1D Binary String crossover, Two Point
+
+ .. warning:: You can't use this crossover method for binary strings with length of 1.
+
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ if len(gMom) == 1:
+ Util.raiseException("The Binary String have one element, can't use the Two Point Crossover method !", TypeError)
+
+ cuts = [rand_randint(1, len(gMom)-1), rand_randint(1, len(gMom)-1)]
+
+ if cuts[0] > cuts[1]:
+ Util.listSwapElement(cuts, 0, 1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ sister[cuts[0]:cuts[1]] = gDad[cuts[0]:cuts[1]]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ brother[cuts[0]:cuts[1]] = gMom[cuts[0]:cuts[1]]
+
+ return (sister, brother)
+
+def G1DBinaryStringXUniform(genome, **args):
+ """ The G1DList Uniform Crossover """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ sister = gMom.clone()
+ brother = gDad.clone()
+ sister.resetStats()
+ brother.resetStats()
+
+ for i in xrange(len(gMom)):
+ if Util.randomFlipCoin(Consts.CDefG1DBinaryStringUniformProb):
+ temp = sister[i]
+ sister[i] = brother[i]
+ brother[i] = temp
+
+ return (sister, brother)
+
+####################
+## 1D List ##
+####################
+
+def G1DListCrossoverSinglePoint(genome, **args):
+ """ The crossover of G1DList, Single Point
+
+ .. warning:: You can't use this crossover method for lists with just one element.
+
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ if len(gMom) == 1:
+ Util.raiseException("The 1D List have one element, can't use the Single Point Crossover method !", TypeError)
+
+ cut = rand_randint(1, len(gMom)-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ sister[cut:] = gDad[cut:]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ brother[cut:] = gMom[cut:]
+
+ return (sister, brother)
+
+def G1DListCrossoverTwoPoint(genome, **args):
+ """ The G1DList crossover, Two Point
+
+ .. warning:: You can't use this crossover method for lists with just one element.
+
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ if len(gMom) == 1:
+ Util.raiseException("The 1D List have one element, can't use the Two Point Crossover method !", TypeError)
+
+ cuts = [rand_randint(1, len(gMom)-1), rand_randint(1, len(gMom)-1)]
+
+ if cuts[0] > cuts[1]:
+ Util.listSwapElement(cuts, 0, 1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ sister[cuts[0]:cuts[1]] = gDad[cuts[0]:cuts[1]]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ brother[cuts[0]:cuts[1]] = gMom[cuts[0]:cuts[1]]
+
+ return (sister, brother)
+
+def G1DListCrossoverUniform(genome, **args):
+ """ The G1DList Uniform Crossover """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ sister = gMom.clone()
+ brother = gDad.clone()
+ sister.resetStats()
+ brother.resetStats()
+
+ for i in xrange(len(gMom)):
+ if Util.randomFlipCoin(Consts.CDefG1DListCrossUniformProb):
+ temp = sister[i]
+ sister[i] = brother[i]
+ brother[i] = temp
+
+ return (sister, brother)
+
+def G1DListCrossoverOX(genome, **args):
+ """ The OX Crossover for G1DList (order crossover) """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+ listSize = len(gMom)
+
+ c1, c2 = [rand_randint(1, len(gMom)-1), rand_randint(1, len(gMom)-1)]
+
+ while c1 == c2:
+ c2 = rand_randint(1, len(gMom)-1)
+
+ if c1 > c2:
+ h = c1
+ c1 = c2
+ c2 = h
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ P1 = [ c for c in gMom[c2:] + gMom[:c2] if c not in gDad[c1:c2] ]
+ sister.genomeList = P1[listSize - c2:] + gDad[c1:c2] + P1[:listSize-c2]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ P2 = [ c for c in gDad[c2:] + gDad[:c2] if c not in gMom[c1:c2] ]
+ brother.genomeList = P2[listSize - c2:] + gMom[c1:c2] + P2[:listSize-c2]
+
+ assert listSize == len(sister)
+ assert listSize == len(brother)
+
+ return (sister, brother)
+
+def G1DListCrossoverEdge(genome, **args):
+ """ THe Edge Recombination crossover for G1DList (widely used for TSP problem)
+
+ See more information in the `Edge Recombination Operator <http://en.wikipedia.org/wiki/Edge_recombination_operator>`_
+ Wikipedia entry.
+ """
+ gMom, sisterl = args["mom"], []
+ gDad, brotherl = args["dad"], []
+
+ mom_edges, dad_edges, merge_edges = Util.G1DListGetEdgesComposite(gMom, gDad)
+
+ for c, u in (sisterl, set(gMom)), (brotherl, set(gDad)):
+ curr = None
+ for i in xrange(len(gMom)):
+ curr = rand_choice(tuple(u)) if not curr else curr
+ c.append(curr)
+ u.remove(curr)
+ d = [v for v in merge_edges.get(curr, []) if v in u]
+ if d: curr = rand_choice(d)
+ else:
+ s = [v for v in mom_edges.get(curr, []) if v in u]
+ s += [v for v in dad_edges.get(curr, []) if v in u]
+ curr = rand_choice(s) if s else None
+
+ sister = gMom.clone()
+ brother = gDad.clone()
+ sister.resetStats()
+ brother.resetStats()
+
+ sister.genomeList = sisterl
+ brother.genomeList = brotherl
+
+ return (sister, brother)
+
+def G1DListCrossoverCutCrossfill(genome, **args):
+ """ The crossover of G1DList, Cut and crossfill, for permutations
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ if len(gMom) == 1:
+ Util.raiseException("The 1D List have one element, can't use the Single Point Crossover method !", TypeError)
+
+ cut = rand_randint(1, len(gMom)-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ mother_part = gMom[0:cut]
+ sister.resetStats()
+ i = (len(sister) - cut)
+ x = 0
+ for v in gDad:
+ if v in mother_part: continue
+ if x >= i: break
+ sister[cut+x] = v
+ x += 1
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ father_part = gDad[0:cut]
+ brother.resetStats()
+ i = (len(brother) - cut)
+ x = 0
+ for v in gMom:
+ if v in father_part: continue
+ if x >= i: break
+ brother[cut+x] = v
+ x += 1
+
+ return (sister, brother)
+
+def G1DListCrossoverRealSBX(genome, **args):
+ """ Experimental SBX Implementation - Follows the implementation in NSGA-II (Deb, et.al)
+
+ Some implementation `reference <http://vision.ucsd.edu/~sagarwal/icannga.pdf>`_.
+
+ .. warning:: This crossover method is Data Type Dependent, which means that
+ must be used for 1D genome of real values.
+ """
+ EPS = Consts.CDefG1DListSBXEPS
+ # Crossover distribution index
+ eta_c = Consts.CDefG1DListSBXEtac
+
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ # Get the variable bounds ('gDad' could have been used; but I love Mom:-))
+ lb = gMom.getParam("rangemin", Consts.CDefRangeMin)
+ ub = gMom.getParam("rangemax", Consts.CDefRangeMax)
+
+ sister = gMom.clone()
+ brother = gDad.clone()
+
+ sister.resetStats()
+ brother.resetStats()
+
+ for i in range(0,len(gMom)):
+
+ if math.fabs(gMom[i]-gDad[i]) > EPS:
+ if gMom[i] > gDad[i]:
+ #swap
+ temp = gMom[i]
+ gMom[i] = gDad[i]
+ gDad[i] = temp
+
+ #random number betwn. 0 & 1
+ u = rand_random()
+
+ beta = 1.0 + 2*(gMom[i] - lb)/(1.0*(gDad[i]-gMom[i]))
+ alpha = 2.0 - beta**(-(eta_c+1.0))
+
+ if u <= (1.0/alpha):
+ beta_q = (u*alpha)**(1.0/((eta_c + 1.0)*1.0))
+ else:
+ beta_q = (1.0/(2.0-u*alpha))**(1.0/(1.0*(eta_c + 1.0)))
+
+ brother[i] = 0.5*((gMom[i] + gDad[i]) - beta_q*(gDad[i]-gMom[i]))
+
+ beta = 1.0 + 2.0*(ub - gDad[i])/(1.0*(gDad[i]-gMom[i]))
+ alpha = 2.0 - beta**(-(eta_c+1.0))
+
+ if u <= (1.0/alpha):
+ beta_q = (u*alpha)**(1.0/((eta_c + 1)*1.0))
+ else:
+ beta_q = (1.0/(2.0-u*alpha))**(1.0/(1.0*(eta_c + 1.0)))
+
+ sister[i] = 0.5*((gMom[i] + gDad[i]) + beta_q*(gDad[i]-gMom[i]))
+
+
+ if brother[i] > ub: brother[i] = ub
+ if brother[i] < lb: brother[i] = lb
+
+ if sister[i] > ub: sister[i] = ub
+ if sister[i] < lb: sister[i] = lb
+
+ if rand_random() > 0.5:
+ # Swap
+ temp = sister[i]
+ sister[i] = brother[i]
+ brother[i] = temp
+ else:
+ sister[i] = gMom[i]
+ brother[i] = gDad[i]
+
+ return (sister, brother)
+
+
+####################
+## 2D List ##
+####################
+
+def G2DListCrossoverUniform(genome, **args):
+ """ The G2DList Uniform Crossover """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ sister = gMom.clone()
+ brother = gDad.clone()
+ sister.resetStats()
+ brother.resetStats()
+
+ h, w = gMom.getSize()
+
+ for i in xrange(h):
+ for j in xrange(w):
+ if Util.randomFlipCoin(Consts.CDefG2DListCrossUniformProb):
+ temp = sister.getItem(i, j)
+ sister.setItem(i, j, brother.getItem(i, j))
+ brother.setItem(i, j, temp)
+
+ return (sister, brother)
+
+
+def G2DListCrossoverSingleVPoint(genome, **args):
+ """ The crossover of G2DList, Single Vertical Point """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ cut = rand_randint(1, gMom.getWidth()-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ for i in xrange(sister.getHeight()):
+ sister[i][cut:] = gDad[i][cut:]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ for i in xrange(brother.getHeight()):
+ brother[i][cut:] = gMom[i][cut:]
+
+ return (sister, brother)
+
+def G2DListCrossoverSingleHPoint(genome, **args):
+ """ The crossover of G2DList, Single Horizontal Point """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ cut = rand_randint(1, gMom.getHeight()-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ for i in xrange(cut, sister.getHeight()):
+ sister[i][:] = gDad[i][:]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ for i in xrange(brother.getHeight()):
+ brother[i][:] = gMom[i][:]
+
+ return (sister, brother)
+
+
+#############################
+## 2D Binary String ##
+#############################
+
+
+def G2DBinaryStringXUniform(genome, **args):
+ """ The G2DBinaryString Uniform Crossover
+
+ .. versionadded:: 0.6
+ The *G2DBinaryStringXUniform* function
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ sister = gMom.clone()
+ brother = gDad.clone()
+ sister.resetStats()
+ brother.resetStats()
+
+ h, w = gMom.getSize()
+
+ for i in xrange(h):
+ for j in xrange(w):
+ if Util.randomFlipCoin(Consts.CDefG2DBinaryStringUniformProb):
+ temp = sister.getItem(i, j)
+ sister.setItem(i, j, brother.getItem(i, j))
+ brother.setItem(i, j, temp)
+
+ return (sister, brother)
+
+
+def G2DBinaryStringXSingleVPoint(genome, **args):
+ """ The crossover of G2DBinaryString, Single Vertical Point
+
+ .. versionadded:: 0.6
+ The *G2DBinaryStringXSingleVPoint* function
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ cut = rand_randint(1, gMom.getWidth()-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ for i in xrange(sister.getHeight()):
+ sister[i][cut:] = gDad[i][cut:]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ for i in xrange(brother.getHeight()):
+ brother[i][cut:] = gMom[i][cut:]
+
+ return (sister, brother)
+
+def G2DBinaryStringXSingleHPoint(genome, **args):
+ """ The crossover of G2DBinaryString, Single Horizontal Point
+
+ .. versionadded:: 0.6
+ The *G2DBinaryStringXSingleHPoint* function
+
+ """
+ sister = None
+ brother = None
+ gMom = args["mom"]
+ gDad = args["dad"]
+
+ cut = rand_randint(1, gMom.getHeight()-1)
+
+ if args["count"] >= 1:
+ sister = gMom.clone()
+ sister.resetStats()
+ for i in xrange(cut, sister.getHeight()):
+ sister[i][:] = gDad[i][:]
+
+ if args["count"] == 2:
+ brother = gDad.clone()
+ brother.resetStats()
+ for i in xrange(brother.getHeight()):
+ brother[i][:] = gMom[i][:]
+
+ return (sister, brother)
+
+#############################
+## Tree ##
+#############################
+
+
+def GTreeCrossoverSinglePoint(genome, **args):
+ """ The crossover for GTree, Single Point """
+ sister = None
+ brother = None
+ gMom = args["mom"].clone()
+ gDad = args["dad"].clone()
+
+ gMom.resetStats()
+ gDad.resetStats()
+
+ node_mom_stack = []
+ all_mom_nodes = []
+ node_mom_tmp = None
+
+ node_dad_stack = []
+ all_dad_nodes = []
+ node_dad_tmp = None
+
+ node_mom_stack.append(gMom.getRoot())
+ node_dad_stack.append(gDad.getRoot())
+
+ while (len(node_mom_stack) > 0) and (len(node_dad_stack) > 0):
+ node_mom_tmp = node_mom_stack.pop()
+ node_dad_tmp = node_dad_stack.pop()
+
+ if node_mom_tmp != gMom.getRoot():
+ all_mom_nodes.append(node_mom_tmp)
+ all_dad_nodes.append(node_dad_tmp)
+
+ node_mom_stack.extend(node_mom_tmp.getChilds())
+ node_dad_stack.extend(node_dad_tmp.getChilds())
+
+ if len(all_mom_nodes)==0 or len(all_dad_nodes)==0:
+ return (gMom, gDad)
+
+ if len(all_dad_nodes) == 1: nodeDad = all_dad_nodes[0]
+ else: nodeDad = rand_choice(all_dad_nodes)
+
+ if len(all_mom_nodes) == 1: nodeMom = all_mom_nodes[0]
+ else: nodeMom = rand_choice(all_mom_nodes)
+
+ nodeMom_parent = nodeMom.getParent()
+ nodeDad_parent = nodeDad.getParent()
+
+ # Sister
+ if args["count"] >= 1:
+ sister = gMom
+ nodeDad.setParent(nodeMom_parent)
+ nodeMom_parent.replaceChild(nodeMom, nodeDad)
+ sister.processNodes()
+
+ # Brother
+ if args["count"] == 2:
+ brother = gDad
+ nodeMom.setParent(nodeDad_parent)
+ nodeDad_parent.replaceChild(nodeDad, nodeMom)
+ brother.processNodes()
+
+ return (sister, brother)
+
+def GTreeCrossoverSinglePointStrict(genome, **args):
+ """ The crossover of Tree, Strict Single Point
+
+ ..note:: This crossover method creates offspring with restriction of the
+ *max_depth* parameter.
+
+ Accepts the *max_attempt* parameter, *max_depth* (required), and
+ the distr_leaft (>= 0.0 and <= 1.0), which represents the probability
+ of leaf selection when findin random nodes for crossover.
+
+ """
+ sister = None
+ brother = None
+
+ gMom = args["mom"].clone()
+ gDad = args["dad"].clone()
+
+ gMom.resetStats()
+ gDad.resetStats()
+
+ max_depth = gMom.getParam("max_depth", None)
+ max_attempt = gMom.getParam("max_attempt", 10)
+ distr_leaf = gMom.getParam("distr_leaf", None)
+
+ if max_depth is None:
+ Util.raiseException("You must specify the max_depth genome parameter !", ValueError)
+
+ if max_depth < 0:
+ Util.raiseException("The max_depth must be >= 1, if you want to use GTreeCrossoverSinglePointStrict crossover !", ValueError)
+
+ momRandom = None
+ dadRandom = None
+
+ for i in xrange(max_attempt):
+
+ if distr_leaf is None:
+ dadRandom = gDad.getRandomNode()
+ momRandom = gMom.getRandomNode()
+ else:
+ if Util.randomFlipCoin(distr_leaf):
+ momRandom = gMom.getRandomNode(1)
+ else:
+ momRandom = gMom.getRandomNode(2)
+
+ if Util.randomFlipCoin(distr_leaf):
+ dadRandom = gDad.getRandomNode(1)
+ else:
+ dadRandom = gDad.getRandomNode(2)
+
+ assert momRandom is not None
+ assert dadRandom is not None
+
+ # Optimize here
+ mH = gMom.getNodeHeight(momRandom)
+ dH = gDad.getNodeHeight(dadRandom)
+
+ mD = gMom.getNodeDepth(momRandom)
+ dD = gDad.getNodeDepth(dadRandom)
+
+ # The depth of the crossover is greater than the max_depth
+ if (dD+mH <= max_depth) and (mD+dH <= max_depth):
+ break
+
+ if i == (max_attempt-1):
+ assert gMom.getHeight() <= max_depth
+ return (gMom, gDad)
+ else:
+ nodeMom, nodeDad = momRandom, dadRandom
+
+ nodeMom_parent = nodeMom.getParent()
+ nodeDad_parent = nodeDad.getParent()
+
+ # Sister
+ if args["count"] >= 1:
+ sister = gMom
+ nodeDad.setParent(nodeMom_parent)
+
+ if nodeMom_parent is None:
+ sister.setRoot(nodeDad)
+ else:
+ nodeMom_parent.replaceChild(nodeMom, nodeDad)
+ sister.processNodes()
+ assert sister.getHeight() <= max_depth
+
+ # Brother
+ if args["count"] == 2:
+ brother = gDad
+ nodeMom.setParent(nodeDad_parent)
+
+ if nodeDad_parent is None:
+ brother.setRoot(nodeMom)
+ else:
+ nodeDad_parent.replaceChild(nodeDad, nodeMom)
+ brother.processNodes()
+ assert brother.getHeight() <= max_depth
+
+ return (sister, brother)
+
+#############################################################################
+################# GTreeGP Crossovers ######################################
+#############################################################################
+
+def GTreeGPCrossoverSinglePoint(genome, **args):
+ """ The crossover of the GTreeGP, Single Point for Genetic Programming
+
+ ..note:: This crossover method creates offspring with restriction of the
+ *max_depth* parameter.
+
+ Accepts the *max_attempt* parameter, *max_depth* (required).
+ """
+ sister = None
+ brother = None
+
+ gMom = args["mom"].clone()
+ gDad = args["dad"].clone()
+
+ gMom.resetStats()
+ gDad.resetStats()
+
+ max_depth = gMom.getParam("max_depth", None)
+ max_attempt = gMom.getParam("max_attempt", 15)
+
+ if max_depth is None:
+ Util.raiseException("You must specify the max_depth genome parameter !", ValueError)
+
+ if max_depth < 0:
+ Util.raiseException("The max_depth must be >= 1, if you want to use GTreeCrossoverSinglePointStrict crossover !", ValueError)
+
+ momRandom = None
+ dadRandom = None
+
+ for i in xrange(max_attempt):
+
+ dadRandom = gDad.getRandomNode()
+
+ if dadRandom.getType() == Consts.nodeType["TERMINAL"]:
+ momRandom = gMom.getRandomNode(1)
+ elif dadRandom.getType() == Consts.nodeType["NONTERMINAL"]:
+ momRandom = gMom.getRandomNode(2)
+
+ mD = gMom.getNodeDepth(momRandom)
+ dD = gDad.getNodeDepth(dadRandom)
+
+ # Two nodes are root
+ if mD==0 and dD==0: continue
+
+ mH = gMom.getNodeHeight(momRandom)
+ if dD+mH > max_depth: continue
+
+ dH = gDad.getNodeHeight(dadRandom)
+ if mD+dH > max_depth: continue
+
+ break
+
+ if i==(max_attempt-1):
+ assert gMom.getHeight() <= max_depth
+ return (gMom, gDad)
+ else:
+ nodeMom, nodeDad = momRandom, dadRandom
+
+ nodeMom_parent = nodeMom.getParent()
+ nodeDad_parent = nodeDad.getParent()
+
+ # Sister
+ if args["count"] >= 1:
+ sister = gMom
+ nodeDad.setParent(nodeMom_parent)
+
+ if nodeMom_parent is None:
+ sister.setRoot(nodeDad)
+ else:
+ nodeMom_parent.replaceChild(nodeMom, nodeDad)
+ sister.processNodes()
+ assert sister.getHeight() <= max_depth
+
+ # Brother
+ if args["count"] == 2:
+ brother = gDad
+ nodeMom.setParent(nodeDad_parent)
+
+ if nodeDad_parent is None:
+ brother.setRoot(nodeMom)
+ else:
+ nodeDad_parent.replaceChild(nodeDad, nodeMom)
+ brother.processNodes()
+ assert brother.getHeight() <= max_depth
+
+ return (sister, brother)
+
+
+
diff --git a/pyevolve/DBAdapters.py b/pyevolve/DBAdapters.py
new file mode 100644
index 0000000..7c76f24
--- /dev/null
+++ b/pyevolve/DBAdapters.py
@@ -0,0 +1,792 @@
+"""
+:mod:`DBAdapters` -- database adapters for statistics
+=====================================================================
+
+.. warning:: the use the of a DB Adapter can reduce the performance of the
+ Genetic Algorithm.
+
+Pyevolve have a feature in which you can save the statistics of every
+generation in a database, file or call an URL with the statistics as param.
+You can use the database to plot evolution statistics graphs later. In this
+module, you'll find the adapters above cited.
+
+.. seealso::
+
+ Method :meth:`GSimpleGA.GSimpleGA.setDBAdapter`
+ DB Adapters are set in the GSimpleGA Class.
+
+"""
+
+from pyevolve import __version__
+import Consts
+import Util
+import logging
+import types
+import datetime
+import Statistics
+
+
+class DBBaseAdapter:
+ """ DBBaseAdapter Class - The base class for all DB Adapters
+
+ If you want to create your own DB Adapter, you must subclass this
+ class.
+
+ :param frequency: the the generational dump frequency
+
+ .. versionadded:: 0.6
+ Added the :class:`DBBaseAdapter` class.
+ """
+ def __init__(self, frequency, identify):
+ """ The class constructor """
+ self.statsGenFreq = frequency
+
+ if identify is None:
+ self.identify = datetime.datetime.strftime(datetime.datetime.now(), "%d/%m/%y-%H:%M")
+ else:
+ self.identify = identify
+
+ def setIdentify(self, identify):
+ """ Sets the identify of the statistics
+
+ :param identify: the id string
+ """
+ if identify is None:
+ self.identify = datetime.datetime.strftime(datetime.datetime.now(), "%d/%m/%y-%H:%M")
+ else:
+ self.identify = identify
+
+ def getIdentify(self):
+ """ Return the statistics identify
+
+ :rtype: identify string
+ """
+ return self.identify
+
+ def getStatsGenFreq(self):
+ """ Returns the frequency of statistical dump
+
+ :rtype: the generation interval of statistical dump
+ """
+ return self.statsGenFreq
+
+ def setStatsGenFreq(self, statsGenFreq):
+ """ Set the frequency of statistical dump
+
+ :param statsGenFreq: the generation interval of statistical dump
+ """
+ self.statsGenFreq = statsGenFreq
+
+ def open(self, ga_engine):
+ """ This method is called one time to do the initialization of
+ the DB Adapter
+
+ :param ga_engine: the GA Engine
+ """
+ pass
+
+ def commitAndClose(self):
+ """ This method is called at the end of the evolution, to closes the
+ DB Adapter and commit the changes """
+ pass
+
+ def insert(self, ga_engine):
+ """ Insert the stats
+
+ :param ga_engine: the GA Engine
+ """
+ Util.raiseException("This method is not implemented on the ABC", NotImplementedError)
+
+class DBFileCSV(DBBaseAdapter):
+ """ DBFileCSV Class - Adapter to dump statistics in CSV format
+
+ Inheritance diagram for :class:`DBAdapters.DBFileCSV`:
+
+ .. inheritance-diagram:: DBAdapters.DBFileCSV
+
+ Example:
+ >>> adapter = DBFileCSV(filename="file.csv", identify="run_01",
+ frequency = 1, reset = True)
+
+ :param filename: the CSV filename
+ :param identify: the identify of the run
+ :param frequency: the generational dump frequency
+ :param reset: if is True, the file old data will be overwrite with the new
+
+ .. versionadded:: 0.6
+ Removed the stub methods and subclassed the :class:`DBBaseAdapter` class.
+
+ """
+ def __init__(self, filename=Consts.CDefCSVFileName, identify=None,
+ frequency = Consts.CDefCSVFileStatsGenFreq, reset=True):
+ """ The creator of DBFileCSV Class """
+
+ DBBaseAdapter.__init__(self, frequency, identify)
+
+ self.csvmod = None
+
+ self.filename = filename
+ self.csvWriter = None
+ self.fHandle = None
+ self.reset = reset
+
+ def __repr__(self):
+ """ The string representation of adapter """
+ ret = "DBFileCSV DB Adapter [File='%s', identify='%s']" % (self.filename, self.getIdentify())
+ return ret
+
+ def open(self, ga_engine):
+ """ Open the CSV file or creates a new file
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ if self.csvmod is None:
+ logging.debug("Loading the csv module...")
+ self.csvmod = Util.importSpecial("csv")
+
+ logging.debug("Opening the CSV file to dump statistics [%s]", self.filename)
+ if self.reset: open_mode = "w"
+ else: open_mode = "a"
+ self.fHandle = open(self.filename, open_mode)
+ self.csvWriter = self.csvmod.writer(self.fHandle, delimiter=';')
+
+ def close(self):
+ """ Closes the CSV file handle """
+ logging.debug("Closing the CSV file [%s]", self.filename)
+ if self.fHandle:
+ self.fHandle.close()
+
+ def commitAndClose(self):
+ """ Commits and closes """
+ self.close()
+
+ def insert(self, ga_engine):
+ """ Inserts the stats into the CSV file
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ stats = ga_engine.getStatistics()
+ generation = ga_engine.getCurrentGeneration()
+ line = [self.getIdentify(), generation]
+ line.extend(stats.asTuple())
+ self.csvWriter.writerow(line)
+
+class DBURLPost(DBBaseAdapter):
+ """ DBURLPost Class - Adapter to call an URL with statistics
+
+ Inheritance diagram for :class:`DBAdapters.DBURLPost`:
+
+ .. inheritance-diagram:: DBAdapters.DBURLPost
+
+ Example:
+ >>> dbadapter = DBURLPost(url="http://localhost/post.py", identify="test")
+
+ The parameters that will be sent is all the statistics described in the :class:`Statistics.Statistics`
+ class, and the parameters:
+
+ **generation**
+ The generation of the statistics
+
+ **identify**
+ The id specified by user
+
+ .. note:: see the :class:`Statistics.Statistics` documentation.
+
+ :param url: the URL to be used
+ :param identify: the identify of the run
+ :param frequency: the generational dump frequency
+ :param post: if True, the POST method will be used, otherwise GET will be used.
+
+ .. versionadded:: 0.6
+ Removed the stub methods and subclassed the :class:`DBBaseAdapter` class.
+ """
+
+ def __init__(self, url, identify=None,
+ frequency = Consts.CDefURLPostStatsGenFreq, post=True):
+ """ The creator of the DBURLPost Class. """
+
+ DBBaseAdapter.__init__(self, frequency, identify)
+ self.urllibmod = None
+
+ self.url = url
+ self.post = post
+
+ def __repr__(self):
+ """ The string representation of adapter """
+ ret = "DBURLPost DB Adapter [URL='%s', identify='%s']" % (self.url, self.getIdentify())
+ return ret
+
+ def open(self, ga_engine):
+ """ Load the modules needed
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ if self.urllibmod is None:
+ logging.debug("Loading urllib module...")
+ self.urllibmod = Util.importSpecial("urllib")
+
+ def insert(self, ga_engine):
+ """ Sends the data to the URL using POST or GET
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ logging.debug("Sending http request to %s.", self.url)
+ stats = ga_engine.getStatistics()
+ response = None
+ params = stats.internalDict.copy()
+ params["generation"] = ga_engine.getCurrentGeneration()
+ params["identify"] = self.getIdentify()
+ if self.post: # POST
+ response = self.urllibmod.urlopen(self.url, self.urllibmod.urlencode(params))
+ else: # GET
+ response = self.urllibmod.urlopen(self.url + "?%s" % (self.urllibmod.urlencode(params)))
+ if response: response.close()
+
+class DBSQLite(DBBaseAdapter):
+ """ DBSQLite Class - Adapter to dump data in SQLite3 database format
+
+ Inheritance diagram for :class:`DBAdapters.DBSQLite`:
+
+ .. inheritance-diagram:: DBAdapters.DBSQLite
+
+ Example:
+ >>> dbadapter = DBSQLite(identify="test")
+
+ When you run some GA for the first time, you need to create the database, for this, you
+ must use the *resetDB* parameter:
+
+ >>> dbadapter = DBSQLite(identify="test", resetDB=True)
+
+ This parameter will erase all the database tables and will create the new ones.
+ The *resetDB* parameter is different from the *resetIdentify* parameter, the *resetIdentify*
+ only erases the rows with the same "identify" name.
+
+ :param dbname: the database filename
+ :param identify: the identify if the run
+ :param resetDB: if True, the database structure will be recreated
+ :param resetIdentify: if True, the identify with the same name will be overwrite with new data
+ :param frequency: the generational dump frequency
+ :param commit_freq: the commit frequency
+ """
+
+ def __init__(self, dbname=Consts.CDefSQLiteDBName, identify=None, resetDB=False,
+ resetIdentify=True, frequency=Consts.CDefSQLiteStatsGenFreq,
+ commit_freq=Consts.CDefSQLiteStatsCommitFreq):
+ """ The creator of the DBSQLite Class """
+
+ DBBaseAdapter.__init__(self, frequency, identify)
+
+ self.sqlite3mod = None
+ self.connection = None
+ self.resetDB = resetDB
+ self.resetIdentify = resetIdentify
+ self.dbName = dbname
+ self.typeDict = { types.FloatType : "real" }
+ self.cursorPool = None
+ self.commitFreq = commit_freq
+
+ def __repr__(self):
+ """ The string representation of adapter """
+ ret = "DBSQLite DB Adapter [File='%s', identify='%s']" % (self.dbName, self.getIdentify())
+ return ret
+
+ def open(self, ga_engine):
+ """ Open the database connection
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ if self.sqlite3mod is None:
+ logging.debug("Loading sqlite3 module...")
+ self.sqlite3mod = Util.importSpecial("sqlite3")
+
+ logging.debug("Opening database, dbname=%s", self.dbName)
+ self.connection = self.sqlite3mod.connect(self.dbName)
+
+ temp_stats = Statistics.Statistics()
+
+ if self.resetDB:
+ self.resetStructure(Statistics.Statistics())
+
+ self.createStructure(temp_stats)
+
+ if self.resetIdentify:
+ self.resetTableIdentify()
+
+ def commitAndClose(self):
+ """ Commit changes on database and closes connection """
+ self.commit()
+ self.close()
+
+ def close(self):
+ """ Close the database connection """
+ logging.debug("Closing database.")
+ if self.cursorPool:
+ self.cursorPool.close()
+ self.cursorPool = None
+ self.connection.close()
+
+ def commit(self):
+ """ Commit changes to database """
+ logging.debug("Commiting changes to database.")
+ self.connection.commit()
+
+ def getCursor(self):
+ """ Return a cursor from the pool
+
+ :rtype: the cursor
+
+ """
+ if not self.cursorPool:
+ logging.debug("Creating new cursor for database...")
+ self.cursorPool = self.connection.cursor()
+ return self.cursorPool
+ else:
+ return self.cursorPool
+
+ def createStructure(self, stats):
+ """ Create table using the Statistics class structure
+
+ :param stats: the statistics object
+
+ """
+ c = self.getCursor()
+ pstmt = "create table if not exists %s(identify text, generation integer, " % (Consts.CDefSQLiteDBTable)
+ for k, v in stats.items():
+ pstmt += "%s %s, " % (k, self.typeDict[type(v)])
+ pstmt = pstmt[:-2] + ")"
+ logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTable, pstmt)
+ c.execute(pstmt)
+
+ pstmt = """create table if not exists %s(identify text, generation integer,
+ individual integer, fitness real, raw real)""" % (Consts.CDefSQLiteDBTablePop)
+ logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTablePop, pstmt)
+ c.execute(pstmt)
+ self.commit()
+
+ def resetTableIdentify(self):
+ """ Delete all records on the table with the same Identify """
+ c = self.getCursor()
+ stmt = "delete from %s where identify = ?" % (Consts.CDefSQLiteDBTable)
+ stmt2 = "delete from %s where identify = ?" % (Consts.CDefSQLiteDBTablePop)
+
+ logging.debug("Erasing data from the tables with the identify = %s", self.getIdentify())
+ try:
+ c.execute(stmt, (self.getIdentify(),))
+ c.execute(stmt2, (self.getIdentify(),))
+ except self.sqlite3mod.OperationalError, expt:
+ if str(expt).find("no such table") >= 0:
+ print "\n ## The DB Adapter can't find the tables ! Consider enable the parameter resetDB ! ##\n"
+
+ self.commit()
+
+
+ def resetStructure(self, stats):
+ """ Deletes de current structure and calls createStructure
+
+ :param stats: the statistics object
+
+ """
+ logging.debug("Reseting structure, droping table and creating new empty table.")
+ c = self.getCursor()
+ c.execute("drop table if exists %s" % (Consts.CDefSQLiteDBTable,))
+ c.execute("drop table if exists %s" % (Consts.CDefSQLiteDBTablePop,))
+ self.commit()
+ self.createStructure(stats)
+
+ def insert(self, ga_engine):
+ """ Inserts the statistics data to database
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ stats = ga_engine.getStatistics()
+ population = ga_engine.getPopulation()
+ generation = ga_engine.getCurrentGeneration()
+
+ c = self.getCursor()
+ pstmt = "insert into %s values (?, ?, " % (Consts.CDefSQLiteDBTable)
+ for i in xrange(len(stats)):
+ pstmt += "?, "
+ pstmt = pstmt[:-2] + ")"
+ c.execute(pstmt, (self.getIdentify(), generation) + stats.asTuple())
+
+ pstmt = "insert into %s values(?, ?, ?, ?, ?)" % (Consts.CDefSQLiteDBTablePop,)
+ tups = []
+ for i in xrange(len(population)):
+ ind = population[i]
+ tups.append((self.getIdentify(), generation, i, ind.fitness, ind.score))
+
+ c.executemany(pstmt, tups)
+ if (generation % self.commitFreq == 0):
+ self.commit()
+
+class DBXMLRPC(DBBaseAdapter):
+ """ DBXMLRPC Class - Adapter to dump statistics to a XML Remote Procedure Call
+
+ Inheritance diagram for :class:`DBAdapters.DBXMLRPC`:
+
+ .. inheritance-diagram:: DBAdapters.DBXMLRPC
+
+ Example:
+ >>> adapter = DBXMLRPC(url="http://localhost:8000/", identify="run_01",
+ frequency = 1)
+
+ :param url: the URL of the XML RPC
+ :param identify: the identify of the run
+ :param frequency: the generational dump frequency
+
+
+ .. note:: The XML RPC Server must implement the *insert* method, wich receives
+ a python dictionary as argument.
+
+ Example of an server in Python: ::
+
+ import xmlrpclib
+ from SimpleXMLRPCServer import SimpleXMLRPCServer
+
+ def insert(l):
+ print "Received statistics: %s" % l
+
+ server = SimpleXMLRPCServer(("localhost", 8000), allow_none=True)
+ print "Listening on port 8000..."
+ server.register_function(insert, "insert")
+ server.serve_forever()
+
+ .. versionadded:: 0.6
+ The :class:`DBXMLRPC` class.
+
+ """
+ def __init__(self, url, identify=None, frequency = Consts.CDefXMLRPCStatsGenFreq):
+ """ The creator of DBXMLRPC Class """
+
+ DBBaseAdapter.__init__(self, frequency, identify)
+ self.xmlrpclibmod = None
+
+ self.url = url
+ self.proxy = None
+
+ def __repr__(self):
+ """ The string representation of adapter """
+ ret = "DBXMLRPC DB Adapter [URL='%s', identify='%s']" % (self.url, self.getIdentify())
+ return ret
+
+ def open(self, ga_engine):
+ """ Open the XML RPC Server proxy
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ if self.xmlrpclibmod is None:
+ logging.debug("Loding the xmlrpclib module...")
+ self.xmlrpclibmod = Util.importSpecial("xmlrpclib")
+
+ logging.debug("Opening the XML RPC Server Proxy on %s", self.url)
+ self.proxy = self.xmlrpclibmod.ServerProxy(self.url, allow_none=True)
+
+ def insert(self, ga_engine):
+ """ Calls the XML RPC procedure
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ stats = ga_engine.getStatistics()
+ generation = ga_engine.getCurrentGeneration()
+ di = stats.internalDict.copy()
+ di.update({"identify": self.getIdentify(), "generation": generation})
+ self.proxy.insert(di)
+
+class DBVPythonGraph(DBBaseAdapter):
+ """ The DBVPythonGraph Class - A DB Adapter for real-time visualization using VPython
+
+ Inheritance diagram for :class:`DBAdapters.DBVPythonGraph`:
+
+ .. inheritance-diagram:: DBAdapters.DBVPythonGraph
+
+ .. note:: to use this DB Adapter, you **must** install VPython first.
+
+ Example:
+ >>> adapter = DBAdapters.DBVPythonGraph(identify="run_01", frequency = 1)
+ >>> ga_engine.setDBAdapter(adapter)
+
+ :param identify: the identify of the run
+ :param genmax: use the generations as max value for x-axis, default False
+ :param frequency: the generational dump frequency
+
+ .. versionadded:: 0.6
+ The *DBVPythonGraph* class.
+ """
+
+ def __init__(self, identify=None, frequency = 20, genmax=False):
+ DBBaseAdapter.__init__(self, frequency, identify)
+ self.genmax = genmax
+ self.vtkGraph = None
+ self.curveMin = None
+ self.curveMax = None
+ self.curveDev = None
+ self.curveAvg = None
+
+ def makeDisplay(self, title_sec, x, y, ga_engine):
+ """ Used internally to create a new display for VPython.
+
+ :param title_sec: the title of the window
+ :param x: the x position of the window
+ :param y: the y position of the window
+ :param ga_engine: the GA Engine
+
+ :rtype: the window (the return of gdisplay call)
+ """
+ title = "Pyevolve v.%s - %s - id [%s]" % (__version__, title_sec, self.identify)
+ if self.genmax:
+ disp = self.vtkGraph.gdisplay(title=title, xtitle='Generation', ytitle=title_sec,
+ xmax=ga_engine.getGenerations(), xmin=0., width=500,
+ height=250, x=x, y=y)
+ else:
+ disp = self.vtkGraph.gdisplay(title=title, xtitle='Generation', ytitle=title_sec,
+ xmin=0., width=500, height=250, x=x, y=y)
+ return disp
+
+ def open(self, ga_engine):
+ """ Imports the VPython module and creates the four graph windows
+
+ :param ga_engine: the GA Engine
+ """
+ logging.debug("Loading visual.graph (VPython) module...")
+ if self.vtkGraph is None:
+ self.vtkGraph = Util.importSpecial("visual.graph").graph
+
+ display_rawmin = self.makeDisplay("Raw Score (min)", 0, 0, ga_engine)
+ display_rawmax = self.makeDisplay("Raw Score (max)", 0, 250, ga_engine)
+ display_rawdev = self.makeDisplay("Raw Score (std. dev.)", 500, 0, ga_engine)
+ display_rawavg = self.makeDisplay("Raw Score (avg)", 500, 250, ga_engine)
+
+ self.curveMin = self.vtkGraph.gcurve(color=self.vtkGraph.color.red, gdisplay=display_rawmin)
+ self.curveMax = self.vtkGraph.gcurve(color=self.vtkGraph.color.green, gdisplay=display_rawmax)
+ self.curveDev = self.vtkGraph.gcurve(color=self.vtkGraph.color.blue, gdisplay=display_rawdev)
+ self.curveAvg = self.vtkGraph.gcurve(color=self.vtkGraph.color.orange, gdisplay=display_rawavg)
+
+ def insert(self, ga_engine):
+ """ Plot the current statistics to the graphs
+
+ :param ga_engine: the GA Engine
+ """
+ stats = ga_engine.getStatistics()
+ generation = ga_engine.getCurrentGeneration()
+
+ self.curveMin.plot(pos=(generation, stats["rawMin"]))
+ self.curveMax.plot(pos=(generation, stats["rawMax"]))
+ self.curveDev.plot(pos=(generation, stats["rawDev"]))
+ self.curveAvg.plot(pos=(generation, stats["rawAve"]))
+
+class DBMySQLAdapter(DBBaseAdapter):
+ """ DBMySQLAdapter Class - Adapter to dump data in MySql database server
+
+ Inheritance diagram for :class:`DBAdapters.DBMySQLAdapter`:
+
+ .. inheritance-diagram:: DBAdapters.DBMySQLAdapter
+
+ Example:
+ >>> dbadapter = DBMySQLAdapter("pyevolve_username", "password", identify="run1")
+
+ or
+
+ >>> dbadapter = DBMySQLAdapter(user="username", passwd="password",
+ ... host="mysqlserver.com.br", port=3306, db="pyevolve_db")
+
+ When you run some GA for the first time, you need to create the database, for this, you
+ must use the *resetDB* parameter as True.
+
+ This parameter will erase all the database tables and will create the new ones.
+ The *resetDB* parameter is different from the *resetIdentify* parameter, the *resetIdentify*
+ only erases the rows with the same "identify" name, and *resetDB* will drop and recreate
+ the tables.
+
+ :param user: mysql username (must have permission to create, drop, insert, etc.. on tables
+ :param passwd: the user password on MySQL server
+ :param host: the hostname, default is "localhost"
+ :param port: the port, default is 3306
+ :param db: the database name, default is "pyevolve"
+ :param identify: the identify if the run
+ :param resetDB: if True, the database structure will be recreated
+ :param resetIdentify: if True, the identify with the same name will be overwrite with new data
+ :param frequency: the generational dump frequency
+ :param commit_freq: the commit frequency
+ """
+
+ def __init__(self, user, passwd, host=Consts.CDefMySQLDBHost, port=Consts.CDefMySQLDBPort,
+ db=Consts.CDefMySQLDBName, identify=None, resetDB=False, resetIdentify=True,
+ frequency=Consts.CDefMySQLStatsGenFreq, commit_freq=Consts.CDefMySQLStatsCommitFreq):
+ """ The creator of the DBSQLite Class """
+
+ DBBaseAdapter.__init__(self, frequency, identify)
+
+ self.mysqldbmod = None
+ self.connection = None
+ self.resetDB = resetDB
+ self.resetIdentify = resetIdentify
+ self.db = db
+ self.host = host
+ self.port = port
+ self.user = user
+ self.passwd = passwd
+ self.typeDict = { types.FloatType : "DOUBLE(14,6)" }
+ self.cursorPool = None
+ self.commitFreq = commit_freq
+
+ def __repr__(self):
+ """ The string representation of adapter """
+ ret = "DBMySQLAdapter DB Adapter [identify='%s', host='%s', username='%s', db='%s']" % (self.getIdentify(),
+ self.host, self.user, self.db)
+ return ret
+
+ def open(self, ga_engine):
+ """ Open the database connection
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ if self.mysqldbmod is None:
+ logging.debug("Loading MySQLdb module...")
+ self.mysqldbmod = Util.importSpecial("MySQLdb")
+
+ logging.debug("Opening database, host=%s", self.host)
+ self.connection = self.mysqldbmod.connect(host=self.host, user=self.user,
+ passwd=self.passwd, db=self.db,
+ port=self.port)
+ temp_stats = Statistics.Statistics()
+ self.createStructure(temp_stats)
+
+ if self.resetDB:
+ self.resetStructure(Statistics.Statistics())
+
+ if self.resetIdentify:
+ self.resetTableIdentify()
+
+ def commitAndClose(self):
+ """ Commit changes on database and closes connection """
+ self.commit()
+ self.close()
+
+ def close(self):
+ """ Close the database connection """
+ logging.debug("Closing database.")
+ if self.cursorPool:
+ self.cursorPool.close()
+ self.cursorPool = None
+ self.connection.close()
+
+ def commit(self):
+ """ Commit changes to database """
+ logging.debug("Commiting changes to database.")
+ self.connection.commit()
+
+ def getCursor(self):
+ """ Return a cursor from the pool
+
+ :rtype: the cursor
+
+ """
+ if not self.cursorPool:
+ logging.debug("Creating new cursor for database...")
+ self.cursorPool = self.connection.cursor()
+ return self.cursorPool
+ else:
+ return self.cursorPool
+
+ def createStructure(self, stats):
+ """ Create table using the Statistics class structure
+
+ :param stats: the statistics object
+
+ """
+ c = self.getCursor()
+ pstmt = "create table if not exists %s(identify VARCHAR(80), generation INTEGER, " % (Consts.CDefMySQLDBTable)
+ for k, v in stats.items():
+ pstmt += "%s %s, " % (k, self.typeDict[type(v)])
+ pstmt = pstmt[:-2] + ")"
+ logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTable, pstmt)
+ c.execute(pstmt)
+
+ pstmt = """create table if not exists %s(identify VARCHAR(80), generation INTEGER,
+ individual INTEGER, fitness DOUBLE(14,6), raw DOUBLE(14,6))""" % (Consts.CDefMySQLDBTablePop)
+ logging.debug("Creating table %s: %s.", Consts.CDefMySQLDBTablePop, pstmt)
+ c.execute(pstmt)
+ self.commit()
+
+ def resetTableIdentify(self):
+ """ Delete all records on the table with the same Identify """
+ c = self.getCursor()
+ stmt = "delete from %s where identify = '%s'" % (Consts.CDefMySQLDBTable, self.getIdentify())
+ stmt2 = "delete from %s where identify = '%s'" % (Consts.CDefMySQLDBTablePop, self.getIdentify())
+
+ logging.debug("Erasing data from the tables with the identify = %s", self.getIdentify())
+ c.execute(stmt)
+ c.execute(stmt2)
+
+ self.commit()
+
+
+ def resetStructure(self, stats):
+ """ Deletes de current structure and calls createStructure
+
+ :param stats: the statistics object
+
+ """
+ logging.debug("Reseting structure, droping table and creating new empty table.")
+ c = self.getCursor()
+ c.execute("drop table if exists %s" % (Consts.CDefMySQLDBTable,))
+ c.execute("drop table if exists %s" % (Consts.CDefMySQLDBTablePop,))
+ self.commit()
+ self.createStructure(stats)
+
+ def insert(self, ga_engine):
+ """ Inserts the statistics data to database
+
+ :param ga_engine: the GA Engine
+
+ .. versionchanged:: 0.6
+ The method now receives the *ga_engine* parameter.
+ """
+ stats = ga_engine.getStatistics()
+ population = ga_engine.getPopulation()
+ generation = ga_engine.getCurrentGeneration()
+
+ c = self.getCursor()
+ pstmt = "insert into " + Consts.CDefMySQLDBTable + " values (%s, %s, "
+ for i in xrange(len(stats)):
+ pstmt += "%s, "
+ pstmt = pstmt[:-2] + ")"
+ c.execute(pstmt, (self.getIdentify(), generation) + stats.asTuple())
+
+ pstmt = "insert into " + Consts.CDefMySQLDBTablePop + " values(%s, %s, %s, %s, %s)"
+
+ tups = []
+ for i in xrange(len(population)):
+ ind = population[i]
+ tups.append((self.getIdentify(), generation, i, ind.fitness, ind.score))
+
+ c.executemany(pstmt, tups)
+ if (generation % self.commitFreq == 0):
+ self.commit()
diff --git a/pyevolve/FunctionSlot.py b/pyevolve/FunctionSlot.py
new file mode 100644
index 0000000..20b2b94
--- /dev/null
+++ b/pyevolve/FunctionSlot.py
@@ -0,0 +1,205 @@
+"""
+:mod:`FunctionSlot` -- function slots module
+==================================================================
+
+The *function slot* concept is large used by Pyevolve, the idea
+is simple, each genetic operator or any operator, can be assigned
+to a slot, by this way, we can add more than simple one operator,
+we can have for example, two or more mutator operators at same time,
+two or more evaluation functions, etc. In this :mod:`FunctionSlot` module,
+you'll find the class :class:`FunctionSlot.FunctionSlot`, which is the slot class.
+
+"""
+
+from random import uniform as rand_uniform
+import inspect
+from types import BooleanType
+
+import Util
+
+class FunctionSlot:
+ """ FunctionSlot Class - The function slot
+
+ Example:
+ >>> genome.evaluator.set(eval_func)
+ >>> genome.evaluator[0]
+ <function eval_func at 0x018C8930>
+ >>> genome.evaluator
+ Slot [Evaluation Function] (Count: 1)
+ Name: eval_func
+ >>> genome.evaluator.clear()
+ >>> genome.evaluator
+ Slot [Evaluation Function] (Count: 0)
+ No function
+
+ You can add weight to functions when using the `rand_apply` paramter:
+ >>> genome.evaluator.set(eval_main, 0.9)
+ >>> genome.evaluator.add(eval_sec, 0.3)
+ >>> genome.evaluator.setRandomApply()
+
+ In the above example, the function *eval_main* will be called with 90% of
+ probability and the *eval_sec* will be called with 30% of probability.
+
+ There are another way to add functions too:
+ >>> genome.evaluator += eval_func
+
+ :param name: the slot name
+ :param rand_apply: if True, just one of the functions in the slot
+ will be applied, this function is randomly picked based
+ on the weight of the function added.
+
+ """
+
+ def __init__(self, name="Anonymous Function", rand_apply=False):
+ """ The creator of the FunctionSlot Class """
+ self.funcList = []
+ self.funcWeights = []
+ self.slotName = name
+ self.rand_apply = rand_apply
+
+ def __typeCheck(self, func):
+ """ Used internally to check if a function passed to the
+ function slot is callable. Otherwise raises a TypeError exception.
+
+ :param func: the function object
+ """
+ if not callable(func):
+ Util.raiseException("The function must be a method or function", TypeError)
+
+ def __iadd__(self, func):
+ """ To add more functions using the += operator
+
+ .. versionadded:: 0.6
+ The __iadd__ method.
+ """
+ self.__typeCheck(func)
+ self.funcList.append(func)
+ return self
+
+ def __getitem__(self, index):
+ """ Used to retrieve some slot function index """
+ return self.funcList[index]
+
+ def __setitem__(self, index, value):
+ """ Used to set the index slot function """
+ self.__typeCheck(value)
+ self.funcList[index] = value
+
+ def __iter__(self):
+ """ Return the function list iterator """
+ return iter(self.funcList)
+
+ def __len__(self):
+ """ Return the number of functions on the slot
+
+ .. versionadded:: 0.6
+ The *__len__* method
+ """
+ return len(self.funcList)
+
+ def setRandomApply(self, flag=True):
+ """ Sets the random function application, in this mode, the
+ function will randomly choose one slot to apply
+
+ :param flag: True or False
+
+ """
+ if type(flag) != BooleanType:
+ Util.raiseException("Random option must be True or False", TypeError)
+
+ self.rand_apply = flag
+
+ def clear(self):
+ """ Used to clear the functions in the slot """
+ if len(self.funcList) > 0:
+ del self.funcList[:]
+
+ def add(self, func, weight=0.5):
+ """ Used to add a function to the slot
+
+ :param func: the function to be added in the slot
+ :param weight: used when you enable the *random apply*, it's the weight
+ of the function for the random selection
+
+ .. versionadded:: 0.6
+ The `weight` parameter.
+
+ """
+ self.__typeCheck(func)
+ self.funcList.append(func)
+ self.funcWeights.append(weight)
+
+ def isEmpty(self):
+ """ Return true if the function slot is empy """
+ return (len(self.funcList) == 0)
+
+ #def __call__(self, *args):
+ # """ The callable method """
+
+ def set(self, func, weight=0.5):
+ """ Used to clear all functions in the slot and add one
+
+ :param func: the function to be added in the slot
+ :param weight: used when you enable the *random apply*, it's the weight
+ of the function for the random selection
+
+ .. versionadded:: 0.6
+ The `weight` parameter.
+
+ .. note:: the method *set* of the function slot remove all previous
+ functions added to the slot.
+ """
+ self.clear()
+ self.__typeCheck(func)
+ self.add(func, weight)
+
+ def apply(self, index, obj, **args):
+ """ Apply the index function
+
+ :param index: the index of the function
+ :param obj: this object is passes as parameter to the function
+ :param args: this args dictionary is passed to the function
+
+ """
+ if len(self.funcList) <= 0:
+ raise Exception("No function defined: " + self.slotName)
+ return self.funcList[index](obj, **args)
+
+ def applyFunctions(self, obj=None, **args):
+ """ Generator to apply all function slots in obj
+
+ :param obj: this object is passes as parameter to the function
+ :param args: this args dictionary is passed to the function
+
+ """
+ if len(self.funcList) <= 0:
+ Util.raiseException("No function defined: " + self.slotName)
+
+ if not self.rand_apply:
+ for f in self.funcList:
+ yield f(obj, **args)
+ else:
+ v = rand_uniform(0, 1)
+ fobj = None
+ for func, weight in zip(self.funcList, self.funcWeights):
+ fobj = func
+ if v < weight:
+ break
+ v = v - weight
+
+ yield fobj(obj, **args)
+
+ def __repr__(self):
+ """ String representation of FunctionSlot """
+ strRet = "Slot [%s] (Count: %d)\n" % (self.slotName, len(self.funcList))
+
+ if len(self.funcList) <= 0:
+ strRet += "\t\tNo function\n"
+ return strRet
+
+ for f, w in zip(self.funcList, self.funcWeights):
+ strRet += "\t\tName: %s - Weight: %.2f\n" % (f.func_name, w)
+ if f.func_doc:
+ strRet += "\t\tDoc: " + f.func_doc + "\n"
+
+ return strRet
diff --git a/pyevolve/G1DBinaryString.py b/pyevolve/G1DBinaryString.py
new file mode 100644
index 0000000..efe2c89
--- /dev/null
+++ b/pyevolve/G1DBinaryString.py
@@ -0,0 +1,203 @@
+"""
+:mod:`G1DBinaryString` -- the classical binary string chromosome
+=====================================================================
+
+This is the classical chromosome representation on GAs, it is the 1D
+Binary String. This string looks like "00011101010".
+
+
+Default Parameters
+-------------------------------------------------------------
+
+*Initializator*
+
+ :func:`Initializators.G1DBinaryStringInitializator`
+
+ The Binatry String Initializator for G1DBinaryString
+
+*Mutator*
+
+ :func:`Mutators.G1DBinaryStringMutatorFlip`
+
+ The Flip Mutator for G1DBinaryString
+
+*Crossover*
+
+ :func:`Crossovers.G1DBinaryStringXSinglePoint`
+
+ The Single Point Crossover for G1DBinaryString
+
+
+Class
+-------------------------------------------------------------
+
+
+"""
+
+from GenomeBase import GenomeBase, G1DBase
+import Consts
+import Util
+
+class G1DBinaryString(GenomeBase, G1DBase):
+ """ G1DBinaryString Class - The 1D Binary String chromosome
+
+ Inheritance diagram for :class:`G1DBinaryString.G1DBinaryString`:
+
+ .. inheritance-diagram:: G1DBinaryString.G1DBinaryString
+
+ This chromosome class extends the :class:`GenomeBase.GenomeBase`
+ and :class:`GenomeBase.G1DBase` classes.
+
+ Example:
+ >>> genome = G1DBinaryString.G1DBinaryString(5)
+
+ :param length: the 1D Binary String size
+
+ """
+
+ evaluator = None
+ """ This is the :term:`evaluation function` slot, you can add
+ a function with the *set* method: ::
+
+ genome.evaluator.set(eval_func)
+ """
+
+ initializator = None
+ """ This is the initialization function of the genome, you
+ can change the default initializator using the function slot: ::
+
+ genome.initializator.set(Initializators.G1DBinaryStringInitializator)
+
+ In this example, the initializator :func:`Initializators.G1DBinaryStringInitializator`
+ will be used to create the initial population.
+ """
+
+ mutator = None
+ """ This is the mutator function slot, you can change the default
+ mutator using the slot *set* function: ::
+
+ genome.mutator.set(Mutators.G1DBinaryStringMutatorSwap)
+
+ """
+
+ crossover = None
+ """ This is the reproduction function slot, the crossover. You
+ can change the default crossover method using: ::
+
+ genome.crossover.set(Crossovers.G1DBinaryStringXUniform)
+ """
+
+
+ def __init__(self, length=10):
+ """ The initializator of G1DList representation """
+ GenomeBase.__init__(self)
+ G1DBase.__init__(self, length)
+ self.genomeList = []
+ self.stringLength = length
+ self.initializator.set(Consts.CDefG1DBinaryStringInit)
+ self.mutator.set(Consts.CDefG1DBinaryStringMutator)
+ self.crossover.set(Consts.CDefG1DBinaryStringCrossover)
+
+ def __setitem__(self, key, value):
+ """ Set the specified value for an gene of List
+
+ >>> g = G1DBinaryString(5)
+ >>> for i in xrange(len(g)):
+ ... g.append(1)
+ >>> g[4] = 0
+ >>> g[4]
+ 0
+
+ """
+ if value not in (0, 1):
+ Util.raiseException("The value must be zero (0) or one (1), used (%s)" % value, ValueError)
+ G1DBase.__setitem__(self, key, value)
+
+ def __repr__(self):
+ """ Return a string representation of Genome """
+ ret = GenomeBase.__repr__(self)
+ ret += "- G1DBinaryString\n"
+ ret += "\tString length:\t %s\n" % (self.getListSize(),)
+ ret += "\tString:\t\t %s\n\n" % (self.getBinary(),)
+ return ret
+
+ def getDecimal(self):
+ """ Converts the binary string to decimal representation
+
+ Example:
+ >>> g = G1DBinaryString(5)
+ >>> for i in xrange(len(g)):
+ ... g.append(0)
+ >>> g[3] = 1
+ >>> g.getDecimal()
+ 2
+
+ :rtype: decimal value
+
+ """
+ return int(self.getBinary(), 2)
+
+ def getBinary(self):
+ """ Returns the binary string representation
+
+ Example:
+ >>> g = G1DBinaryString(2)
+ >>> g.append(0)
+ >>> g.append(1)
+ >>> g.getBinary()
+ '01'
+
+ :rtype: the binary string
+
+ """
+ return "".join(map(str, self))
+
+ def append(self, value):
+ """ Appends an item to the list
+
+ Example:
+ >>> g = G1DBinaryString(2)
+ >>> g.append(0)
+
+ :param value: value to be added, 0 or 1
+
+ """
+ if value not in [0, 1]:
+ Util.raiseException("The value must be 0 or 1", ValueError)
+ G1DBase.append(self, value)
+
+ def copy(self, g):
+ """ Copy genome to 'g'
+
+ Example:
+ >>> g1 = G1DBinaryString(2)
+ >>> g1.append(0)
+ >>> g1.append(1)
+ >>> g2 = G1DBinaryString(2)
+ >>> g1.copy(g2)
+ >>> g2[1]
+ 1
+
+ :param g: the destination genome
+
+ """
+ GenomeBase.copy(self, g)
+ G1DBase.copy(self, g)
+
+ def clone(self):
+ """ Return a new instace copy of the genome
+
+ Example:
+ >>> g = G1DBinaryString(5)
+ >>> for i in xrange(len(g)):
+ ... g.append(1)
+ >>> clone = g.clone()
+ >>> clone[0]
+ 1
+
+ :rtype: the G1DBinaryString instance clone
+
+ """
+ newcopy = G1DBinaryString(self.getListSize())
+ self.copy(newcopy)
+ return newcopy
diff --git a/pyevolve/G1DList.py b/pyevolve/G1DList.py
new file mode 100644
index 0000000..2fd60a5
--- /dev/null
+++ b/pyevolve/G1DList.py
@@ -0,0 +1,199 @@
+"""
+
+:mod:`G1DList` -- the 1D list chromosome
+=============================================================
+
+This is the 1D List representation, this list can carry real
+numbers or integers or any kind of object, by default, we have
+genetic operators for integer and real lists, which can be found
+on the respective modules.
+
+Default Parameters
+-------------------------------------------------------------
+
+*Initializator*
+
+ :func:`Initializators.G1DListInitializatorInteger`
+
+ The Integer Initializator for G1DList
+
+*Mutator*
+
+ :func:`Mutators.G1DListMutatorSwap`
+
+ The Swap Mutator for G1DList
+
+*Crossover*
+
+ :func:`Crossovers.G1DListCrossoverSinglePoint`
+
+ The Single Point Crossover for G1DList
+
+
+Class
+-------------------------------------------------------------
+
+"""
+from GenomeBase import GenomeBase, G1DBase
+import Consts
+
+class G1DList(GenomeBase, G1DBase):
+ """ G1DList Class - The 1D List chromosome representation
+
+ Inheritance diagram for :class:`G1DList.G1DList`:
+
+ .. inheritance-diagram:: G1DList.G1DList
+
+ This chromosome class extends the :class:`GenomeBase.GenomeBase`
+ and :class:`GenomeBase.G1DBase` classes.
+
+ **Examples**
+
+ The instantiation
+ >>> g = G1DList(10)
+
+ Compare
+ >>> genome2 = genome1.clone()
+ >>> genome2 == genome1
+ True
+
+ Multiply
+ >>> genome = population[0]
+ >>> genome
+ (...)
+ [1, 2, 3, 4]
+ >>> genome_result = genome * 2
+ >>> genome_result
+ (...)
+ [2, 2, 6, 8]
+
+ Add
+ >>> genome
+ (...)
+ [1, 2, 3, 4]
+ >>> genome_result = genome + 2
+ (...)
+ [3, 4, 5, 6]
+
+ Iteration
+ >>> for i in genome:
+ >>> print i
+ 1
+ 2
+ 3
+ 4
+
+ Size, slice, get/set, append
+ >>> len(genome)
+ 4
+ >>> genome
+ (...)
+ [1, 2, 3, 4]
+ >>> genome[0:1]
+ [1, 2]
+ >>> genome[1] = 666
+ >>> genome
+ (...)
+ [1, 666, 3, 4]
+ >>> genome.append(99)
+ >>> genome
+ (...)
+ [1, 666, 3, 4, 99]
+
+ :param size: the 1D list size
+
+ """
+
+ evaluator = None
+ """ This is the :term:`evaluation function` slot, you can add
+ a function with the *set* method: ::
+
+ genome.evaluator.set(eval_func)
+ """
+
+ initializator = None
+ """ This is the initialization function of the genome, you
+ can change the default initializator using the function slot: ::
+
+ genome.initializator.set(Initializators.G1DListInitializatorAllele)
+
+ In this example, the initializator :func:`Initializators.G1DListInitializatorAllele`
+ will be used to create the initial population.
+ """
+
+ mutator = None
+ """ This is the mutator function slot, you can change the default
+ mutator using the slot *set* function: ::
+
+ genome.mutator.set(Mutators.G1DListMutatorSwap)
+
+ """
+
+ crossover = None
+ """ This is the reproduction function slot, the crossover. You
+ can change the default crossover method using: ::
+
+ genome.crossover.set(Crossovers.G1DListCrossoverUniform)
+ """
+
+ def __init__(self, size=10, cloning=False):
+ """ The initializator of G1DList representation,
+ size parameter must be specified """
+ GenomeBase.__init__(self)
+ G1DBase.__init__(self, size)
+ if not cloning:
+ self.initializator.set(Consts.CDefG1DListInit)
+ self.mutator.set(Consts.CDefG1DListMutator)
+ self.crossover.set(Consts.CDefG1DListCrossover)
+
+ def __mul__(self, other):
+ """ Multiply every element of G1DList by "other" """
+ newObj = self.clone()
+ for i in xrange(len(newObj)):
+ newObj[i] *= other
+ return newObj
+
+ def __add__(self, other):
+ """ Plus every element of G1DList by "other" """
+ newObj = self.clone()
+ for i in xrange(len(newObj)):
+ newObj[i] += other
+ return newObj
+
+ def __sub__(self, other):
+ """ Plus every element of G1DList by "other" """
+ newObj = self.clone()
+ for i in xrange(len(newObj)):
+ newObj[i] -= other
+ return newObj
+
+ def __repr__(self):
+ """ Return a string representation of Genome """
+ ret = GenomeBase.__repr__(self)
+ ret += "- G1DList\n"
+ ret += "\tList size:\t %s\n" % (self.getListSize(),)
+ ret += "\tList:\t\t %s\n\n" % (self.genomeList,)
+ return ret
+
+ def copy(self, g):
+ """ Copy genome to 'g'
+
+ Example:
+ >>> genome_origin.copy(genome_destination)
+
+ :param g: the destination G1DList instance
+
+ """
+ GenomeBase.copy(self, g)
+ G1DBase.copy(self, g)
+
+ def clone(self):
+ """ Return a new instace copy of the genome
+
+ :rtype: the G1DList clone instance
+
+ """
+ newcopy = G1DList(self.genomeSize, True)
+ self.copy(newcopy)
+ return newcopy
+
diff --git a/pyevolve/G2DBinaryString.py b/pyevolve/G2DBinaryString.py
new file mode 100644
index 0000000..1e9c997
--- /dev/null
+++ b/pyevolve/G2DBinaryString.py
@@ -0,0 +1,230 @@
+"""
+:mod:`G2DBinaryString` -- the classical binary string chromosome
+=====================================================================
+
+This representation is a 2D Binary String, the string looks like
+this matrix:
+
+00101101010
+00100011010
+00101101010
+10100101000
+
+Default Parameters
+-------------------------------------------------------------
+
+*Initializator*
+
+ :func:`Initializators.G2DBinaryStringInitializator`
+
+ The Binatry String Initializator for G2DBinaryString
+
+*Mutator*
+
+ :func:`Mutators.G2DBinaryStringMutatorFlip`
+
+ The Flip Mutator for G2DBinaryString
+
+*Crossover*
+
+ :func:`Crossovers.G2DBinaryStringXSinglePoint`
+
+ The Single Point Crossover for G2DBinaryString
+
+.. versionadded:: 0.6
+ Added the module :mod:`G2DBinaryString`
+
+Class
+-------------------------------------------------------------
+"""
+
+from GenomeBase import GenomeBase
+import Consts
+import Util
+
+class G2DBinaryString(GenomeBase):
+ """ G3DBinaryString Class - The 2D Binary String chromosome
+
+ Inheritance diagram for :class:`G2DBinaryString.G2DBinaryString`:
+
+ .. inheritance-diagram:: G2DBinaryString.G2DBinaryString
+
+ Example:
+ >>> genome = G2DBinaryString.G2DBinaryString(10, 12)
+
+
+ :param height: the number of rows
+ :param width: the number of columns
+
+ """
+
+ evaluator = None
+ """ This is the :term:`evaluation function` slot, you can add
+ a function with the *set* method: ::
+
+ genome.evaluator.set(eval_func)
+ """
+
+ initializator = None
+ """ This is the initialization function of the genome, you
+ can change the default initializator using the function slot: ::
+
+ genome.initializator.set(Initializators.G2DBinaryStringInitializator)
+
+ In this example, the initializator :func:`Initializators.G1DBinaryStringInitializator`
+ will be used to create the initial population.
+ """
+
+ mutator = None
+ """ This is the mutator function slot, you can change the default
+ mutator using the slot *set* function: ::
+
+ genome.mutator.set(Mutators.G2DBinaryStringMutatorSwap)
+
+ """
+
+ crossover = None
+ """ This is the reproduction function slot, the crossover. You
+ can change the default crossover method using: ::
+
+ genome.crossover.set(Crossovers.G2DBinaryStringXUniform)
+ """
+
+
+ def __init__(self, height, width):
+ """ The initializator of G2DBinaryString representation,
+ height and width must be specified """
+ GenomeBase.__init__(self)
+ self.height = height
+ self.width = width
+
+ self.genomeString = [None]*height
+ for i in xrange(height):
+ self.genomeString[i] = [None] * width
+
+ self.initializator.set(Consts.CDefG2DBinaryStringInit)
+ self.mutator.set(Consts.CDefG2DBinaryStringMutator)
+ self.crossover.set(Consts.CDefG2DBinaryStringCrossover)
+
+ def __eq__(self, other):
+ """ Compares one chromosome with another """
+ cond1 = (self.genomeString == other.genomeString)
+ cond2 = (self.height == other.height)
+ cond3 = (self.width == other.width)
+ return True if cond1 and cond2 and cond3 else False
+
+ def getItem(self, x, y):
+ """ Return the specified gene of List
+
+ Example:
+ >>> genome.getItem(3, 1)
+ 0
+
+ :param x: the x index, the column
+ :param y: the y index, the row
+ :rtype: the item at x,y position
+
+ """
+ return self.genomeString[x][y]
+
+ def setItem(self, x, y, value):
+ """ Set the specified gene of List
+
+ Example:
+ >>> genome.setItem(3, 1, 0)
+
+ :param x: the x index, the column
+ :param y: the y index, the row
+ :param value: the value (integers 0 or 1)
+
+ """
+ if value not in [0,1]:
+ Util.raiseException("The item value must be 0 or 1 in the G2DBinaryString chromosome", ValueError)
+ self.genomeString[x][y] = value
+
+
+ def __getitem__(self, key):
+ """ Return the specified gene of List """
+ return self.genomeString[key]
+
+ def __iter__(self):
+ """ Iterator support to the list """
+ return iter(self.genomeString)
+
+ def getHeight(self):
+ """ Return the height (lines) of the List """
+ return self.height
+
+ def getWidth(self):
+ """ Return the width (lines) of the List """
+ return self.width
+
+ def getSize(self):
+ """ Returns a tuple (height, widht)
+
+ Example:
+ >>> genome.getSize()
+ (3, 2)
+
+ """
+ return (self.getHeight(), self.getWidth())
+
+
+ def __repr__(self):
+ """ Return a string representation of Genome """
+ ret = GenomeBase.__repr__(self)
+ ret += "- G2DBinaryString\n"
+ ret += "\tList size:\t %s\n" % (self.getSize(),)
+ ret += "\tList:\n"
+ for line in self.genomeString:
+ ret += "\t\t\t"
+ for item in line:
+ ret += "[%s] " % (item)
+ ret += "\n"
+ ret += "\n"
+ return ret
+
+ def resumeString(self):
+ """ Returns a resumed string representation of the Genome
+
+ """
+ ret = ""
+ for line in self.genomeString:
+ for item in line:
+ ret += "[%s] " % (item)
+ ret += "\n"
+ return ret
+
+ def clearString(self):
+ """ Remove all genes from Genome """
+ del self.genomeString[:]
+
+ self.genomeString = [None]* self.height
+ for i in xrange(self.height):
+ self.genomeString[i] = [None] * self.width
+
+ def copy(self, g):
+ """ Copy genome to 'g'
+
+ Example:
+ >>> genome_origin.copy(genome_destination)
+
+ :param g: the destination G2DBinaryString instance
+
+ """
+ GenomeBase.copy(self, g)
+ g.height = self.height
+ g.width = self.width
+ for i in xrange(self.height):
+ g.genomeString[i] = self.genomeString[i][:]
+
+ def clone(self):
+ """ Return a new instace copy of the genome
+
+ :rtype: the G2DBinaryString clone instance
+
+ """
+ newcopy = G2DBinaryString(self.height, self.width)
+ self.copy(newcopy)
+ return newcopy
+
diff --git a/pyevolve/G2DList.py b/pyevolve/G2DList.py
new file mode 100644
index 0000000..5d143e2
--- /dev/null
+++ b/pyevolve/G2DList.py
@@ -0,0 +1,259 @@
+"""
+:mod:`G2DList` -- the 2D list chromosome
+================================================================
+
+This is the 2D List representation, this list can carry real numbers or
+integers or any kind of object, by default, we have genetic operators
+for integer and real lists, which can be found on the respective modules.
+This chromosome class extends the :class:`GenomeBase.GenomeBase`.
+
+Default Parameters
+-------------------------------------------------------------
+
+*Initializator*
+
+ :func:`Initializators.G2DListInitializatorInteger`
+
+ The Integer Initializator for G2DList
+
+*Mutator*
+
+ :func:`Mutators.G2DListMutatorSwap`
+
+ The Swap Mutator for G2DList
+
+*Crossover*
+
+ :func:`Crossovers.G2DListCrossoverUniform`
+
+ The Uniform Crossover for G2DList
+
+
+Class
+-------------------------------------------------------------
+
+
+"""
+
+from GenomeBase import GenomeBase
+import Consts
+
+class G2DList(GenomeBase):
+ """ G2DList Class - The 2D List chromosome representation
+
+ Inheritance diagram for :class:`G2DList.G2DList`:
+
+ .. inheritance-diagram:: G2DList.G2DList
+
+ **Examples**
+
+ The instantiation
+ >>> genome = G2DList.G2DList(10, 10)
+
+ Compare
+ >>> genome2 = genome1.clone()
+ >>> genome2 == genome1
+ True
+
+ Iteration
+ >>> for row in genome:
+ >>> print row
+ [1, 3, 4, 1]
+ [7, 5, 3, 4]
+ [9, 0, 1, 2]
+
+ Size, slice, get/set, append
+ >>> len(genome)
+ 3
+ >>> genome
+ (...)
+ [1, 3, 4, 1]
+ [7, 5, 3, 4]
+ [9, 0, 1, 2]
+ >>> genome[1][2]
+ 3
+ >>> genome[1] = [666, 666, 666, 666]
+ >>> genome
+ (...)
+ [1, 3, 4, 1]
+ [666, 666, 666, 666]
+ [9, 0, 1, 2]
+ >>> genome[1][1] = 2
+ (...)
+
+ :param height: the number of rows
+ :param width: the number of columns
+
+ """
+
+ evaluator = None
+ """ This is the :term:`evaluation function` slot, you can add
+ a function with the *set* method: ::
+
+ genome.evaluator.set(eval_func)
+ """
+
+ initializator = None
+ """ This is the initialization function of the genome, you
+ can change the default initializator using the function slot: ::
+
+ genome.initializator.set(Initializators.G2DListInitializatorAllele)
+
+ In this example, the initializator :func:`Initializators.G2DListInitializatorAllele`
+ will be used to create the initial population.
+ """
+
+ mutator = None
+ """ This is the mutator function slot, you can change the default
+ mutator using the slot *set* function: ::
+
+ genome.mutator.set(Mutators.G2DListMutatorIntegerGaussian)
+
+ """
+
+ crossover = None
+ """ This is the reproduction function slot, the crossover. You
+ can change the default crossover method using: ::
+
+ genome.crossover.set(Crossovers.G2DListCrossoverSingleHPoint)
+ """
+
+ def __init__(self, height, width, cloning=False):
+ """ The initializator of G2DList representation,
+ height and width must be specified """
+ GenomeBase.__init__(self)
+ self.height = height
+ self.width = width
+
+ self.genomeList = [None]*height
+ for i in xrange(height):
+ self.genomeList[i] = [None] * width
+
+ if not cloning:
+ self.initializator.set(Consts.CDefG2DListInit)
+ self.mutator.set(Consts.CDefG2DListMutator)
+ self.crossover.set(Consts.CDefG2DListCrossover)
+
+ def __eq__(self, other):
+ """ Compares one chromosome with another """
+ cond1 = (self.genomeList == other.genomeList)
+ cond2 = (self.height == other.height)
+ cond3 = (self.width == other.width)
+ return True if cond1 and cond2 and cond3 else False
+
+ def getItem(self, x, y):
+ """ Return the specified gene of List
+
+ Example:
+ >>> genome.getItem(3, 1)
+ 666
+ >>> genome[3][1]
+
+ :param x: the x index, the column
+ :param y: the y index, the row
+ :rtype: the item at x,y position
+
+ """
+ return self.genomeList[x][y]
+
+ def setItem(self, x, y, value):
+ """ Set the specified gene of List
+
+ Example:
+ >>> genome.setItem(3, 1, 666)
+ >>> genome[3][1] = 666
+
+ :param x: the x index, the column
+ :param y: the y index, the row
+ :param value: the value
+
+ """
+ self.genomeList[x][y] = value
+
+ def __getitem__(self, key):
+ """ Return the specified gene of List """
+ return self.genomeList[key]
+
+ def __iter__(self):
+ """ Iterator support to the list """
+ return iter(self.genomeList)
+
+ def getHeight(self):
+ """ Return the height (lines) of the List """
+ return self.height
+
+ def getWidth(self):
+ """ Return the width (lines) of the List """
+ return self.width
+
+ def getSize(self):
+ """ Returns a tuple (height, widht)
+
+ Example:
+ >>> genome.getSize()
+ (3, 2)
+
+ """
+ return (self.getHeight(), self.getWidth())
+
+ def __repr__(self):
+ """ Return a string representation of Genome """
+ ret = GenomeBase.__repr__(self)
+ ret += "- G2DList\n"
+ ret += "\tList size:\t %s\n" % (self.getSize(),)
+ ret += "\tList:\n"
+ for line in self.genomeList:
+ ret += "\t\t\t"
+ for item in line:
+ ret += "[%s] " % (item)
+ ret += "\n"
+ ret += "\n"
+ return ret
+
+ def resumeString(self):
+ """ Returns a resumed string representation of the Genome
+
+ .. versionadded:: 0.6
+ The *resumeString* method.
+ """
+ ret = ""
+ for line in self.genomeList:
+ for item in line:
+ ret += "[%s] " % (item)
+ ret += "\n"
+ return ret
+
+ def clearList(self):
+ """ Remove all genes from Genome """
+ del self.genomeList[:]
+
+ self.genomeList = [None]* self.height
+ for i in xrange(self.height):
+ self.genomeList[i] = [None] * self.width
+
+ def copy(self, g):
+ """ Copy genome to 'g'
+
+ Example:
+ >>> genome_origin.copy(genome_destination)
+
+ :param g: the destination G2DList instance
+
+ """
+ GenomeBase.copy(self, g)
+ g.height = self.height
+ g.width = self.width
+ for i in xrange(self.height):
+ g.genomeList[i] = self.genomeList[i][:]
+
+ def clone(self):
+ """ Return a new instace copy of the genome
+
+ :rtype: the G2DList clone instance
+
+ """
+ newcopy = G2DList(self.height, self.width, True)
+ self.copy(newcopy)
+ return newcopy
+
+
diff --git a/pyevolve/GAllele.py b/pyevolve/GAllele.py
new file mode 100644
index 0000000..87737eb
--- /dev/null
+++ b/pyevolve/GAllele.py
@@ -0,0 +1,279 @@
+"""
+
+:mod:`GAllele` -- the genome alleles module
+===========================================================
+
+In this module, there are the :class:`GAllele.GAlleles` class (which is the
+class that holds the allele types) and all the
+allele types to use with the supported chromosomes.
+
+"""
+import random
+import Consts
+import Util
+
+class GAlleles:
+ """ GAlleles Class - The set of alleles
+
+ Example:
+ >>> alleles = GAlleles()
+ >>> choices = [1,2,3,4]
+ >>> lst = GAlleleList(choices)
+ >>> alleles.add(lst)
+ >>> alleles[0].getRandomAllele() in lst
+ True
+
+ :param allele_list: the list of alleles
+ :param homogeneous: if is True, all the alleles will be use only the first added
+
+ """
+
+ def __init__(self, allele_list = None, homogeneous=False):
+ """ The constructor of GAlleles class """
+ self.allele_list = []
+ if allele_list is not None:
+ self.allele_list.extend(allele_list)
+ self.homogeneous = homogeneous
+
+ def __iadd__(self, allele):
+ """ To add more alleles using the += operator
+
+ .. versionadded:: 0.6
+ The __iadd__ method.
+ """
+ self.add(allele)
+ return self
+
+ def add(self, allele):
+ """ Appends one allele to the alleles list
+
+ :param allele: allele to be added
+
+ """
+ self.allele_list.append(allele)
+
+ def __getslice__(self, a, b):
+ """ Returns the slice part of alleles list """
+ return self.allele_list[a:b]
+
+ def __getitem__(self, index):
+ """ Returns the index allele of the alleles list """
+ if self.homogeneous: return self.allele_list[0]
+ try:
+ val = self.allele_list[index]
+ except IndexError:
+ Util.raiseException(
+ """An error was occurred while finding allele for the %d position of chromosome.
+ You may consider use the 'homogeneous' parameter of the GAlleles class.
+ """ % (index,))
+ return val
+
+ def __setitem__(self, index, value):
+ """ Sets the index allele of the alleles list """
+ if self.homogeneous: self.allele_list[0] = value
+ self.allele_list[index] = value
+
+ def __iter__(self):
+ """ Return the list iterator """
+ if self.homogeneous:
+ oneList = [self.allele_list[0]]
+ return iter(oneList)
+ return iter(self.allele_list)
+
+ def __len__(self):
+ """ Returns the lenght of the alleles list """
+ if self.homogeneous: return 1
+ return len(self.allele_list)
+
+ def __repr__(self):
+ """ Return a string representation of the allele """
+ ret = "- GAlleles\n"
+ ret += "\tHomogeneous:\t %s\n" % (self.homogeneous,)
+ ret += "\tList size:\t %s\n" % (len(self),)
+ ret += "\tAlleles:\n\n"
+ if self.homogeneous:
+ ret += "Allele for 0 position:\n"
+ ret += self.allele_list[0].__repr__()
+ else:
+ for i in xrange(len(self)):
+ ret += "Allele for %d position:\n" % (i,)
+ ret += self.allele_list[i].__repr__()
+ return ret
+
+
+class GAlleleList:
+ """ GAlleleList Class - The list allele type
+
+ Example:
+ >>> alleles = GAlleles()
+ >>> choices = [1,2,3,4]
+ >>> lst = GAlleleList(choices)
+ >>> alleles.add(lst)
+ >>> alleles[0].getRandomAllele() in lst
+ True
+
+ """
+
+ def __init__(self, options=None):
+ """ The constructor of GAlleleList class """
+ self.options = []
+ if options is not None:
+ self.options.extend(options)
+
+ def clear(self):
+ """ Removes all the allele options from the list """
+ del self.options[:]
+
+ def getRandomAllele(self):
+ """ Returns one random choice from the options list """
+ return random.choice(self.options)
+
+ def add(self, option):
+ """ Appends one option to the options list
+
+ :param option: option to be added in the list
+
+ """
+ self.options.append(option)
+
+ def __getslice__(self, a, b):
+ """ Returns the slice part of options """
+ return self.options[a:b]
+
+ def __getitem__(self, index):
+ """ Returns the index option from the options list """
+ return self.options[index]
+
+ def __setitem__(self, index, value):
+ """ Sets the index option of the list """
+ self.options[index] = value
+
+ def __iter__(self):
+ """ Return the list iterator """
+ return iter(self.options)
+
+ def __len__(self):
+ """ Returns the lenght of the options list """
+ return len(self.options)
+
+ def remove(self, option):
+ """ Removes the option from list
+
+ :param option: remove the option from the list
+
+ """
+ self.options.remove(option)
+
+ def __repr__(self):
+ """ Return a string representation of the allele """
+ ret = "- GAlleleList\n"
+ ret += "\tList size:\t %s\n" % (len(self),)
+ ret += "\tAllele Options:\t %s\n\n" % (self.options,)
+ return ret
+
+class GAlleleRange:
+ """ GAlleleRange Class - The range allele type
+
+ Example:
+ >>> ranges = GAlleleRange(0,100)
+ >>> ranges.getRandomAllele() >= 0 and ranges.getRandomAllele() <= 100
+ True
+
+ :param begin: the begin of the range
+ :param end: the end of the range
+ :param real: if True, the range will be of real values
+
+ """
+
+ def __init__(self, begin=Consts.CDefRangeMin,
+ end=Consts.CDefRangeMax, real=False):
+ """ The constructor of GAlleleRange class """
+ self.beginEnd = [(begin, end)]
+ self.real = real
+ self.minimum = None
+ self.maximum = None
+ self.__processMinMax()
+
+ def __processMinMax(self):
+ """ Process the mininum and maximum of the Allele """
+ self.minimum = min([x for x,y in self.beginEnd])
+ self.maximum = max([y for x,y in self.beginEnd])
+
+ def add(self, begin, end):
+ """ Add a new range
+
+ :param begin: the begin of range
+ :param end: the end of the range
+
+ """
+ if begin > end:
+ Util.raiseException('Wrong value, the end of the range (%s) is greater than the begin (%s) !' % (end, begin), ValueError)
+ self.beginEnd.append((begin, end))
+ self.__processMinMax()
+
+ def __getitem__(self, index):
+ return self.beginEnd[index]
+
+ def __setitem__(self, index, value):
+ if value[0] > value[1]:
+ Util.raiseException('Wrong value, the end of the range is greater than the begin ! %s' % value, ValueError)
+ self.beginEnd[index] = value
+ self.__processMinMax()
+
+ def __iter__(self):
+ return iter(self.beginEnd)
+
+ def getMaximum(self):
+ """ Return the maximum of all the ranges
+
+ :rtype: the maximum value
+ """
+ return self.maximum
+
+ def getMinimum(self):
+ """ Return the minimum of all the ranges
+
+ :rtype: the minimum value
+ """
+ return self.minimum
+
+ def clear(self):
+ """ Removes all ranges """
+ del self.beginEnd[:]
+ self.minimum = None
+ self.maximum = None
+
+ def getRandomAllele(self):
+ """ Returns one random choice between the range """
+ rand_func = random.uniform if self.real else random.randint
+
+ if len(self.beginEnd) <= 1: choice = 0
+ else: choice = random.randint(0, len(self.beginEnd)-1)
+ return rand_func(self.beginEnd[choice][0], self.beginEnd[choice][1])
+
+ def setReal(self, flag=True):
+ """ Sets True if the range is real or False if is integer
+
+ :param flag: True or False
+
+ """
+ self.real = flag
+
+ def getReal(self):
+ """ Returns True if the range is real or False if it is integer """
+ return self.real
+
+ def __len__(self):
+ """ Returns the ranges in the allele """
+ return len(self.beginEnd)
+
+ def __repr__(self):
+ """ Return a string representation of the allele """
+ ret = "- GAlleleRange\n"
+ ret += "\tReal:\t\t %s\n" % (self.real,)
+ ret += "\tRanges Count:\t %s\n" % (len(self),)
+ ret += "\tRange List:\n"
+ for beg, end in self.beginEnd:
+ ret += "\t\t\t Range from [%s] to [%s]\n" % (beg, end)
+ ret += "\n"
+ return ret
diff --git a/pyevolve/GPopulation.py b/pyevolve/GPopulation.py
new file mode 100644
index 0000000..b1b6d4d
--- /dev/null
+++ b/pyevolve/GPopulation.py
@@ -0,0 +1,467 @@
+"""
+:mod:`GPopulation` -- the population module
+================================================================
+
+This module contains the :class:`GPopulation.GPopulation` class, which is reponsible
+to keep the population and the statistics.
+
+Default Parameters
+-------------------------------------------------------------
+
+*Sort Type*
+
+ >>> Consts.sortType["scaled"]
+
+ The scaled sort type
+
+*Minimax*
+
+ >>> Consts.minimaxType["maximize"]
+
+ Maximize the evaluation function
+
+*Scale Method*
+
+ :func:`Scaling.LinearScaling`
+
+ The Linear Scaling scheme
+
+Class
+-------------------------------------------------------------
+
+
+"""
+
+import Consts, Util
+from FunctionSlot import FunctionSlot
+from Statistics import Statistics
+from math import sqrt as math_sqrt
+import logging
+
+try:
+ from multiprocessing import cpu_count, Pool
+ CPU_COUNT = cpu_count()
+ MULTI_PROCESSING = True if CPU_COUNT > 1 else False
+ logging.debug("You have %d CPU cores, so the multiprocessing state is %s", CPU_COUNT, MULTI_PROCESSING)
+except ImportError:
+ MULTI_PROCESSING = False
+ logging.debug("You don't have multiprocessing support for your Python version !")
+
+
+def key_raw_score(individual):
+ """ A key function to return raw score
+
+ :param individual: the individual instance
+ :rtype: the individual raw score
+
+ .. note:: this function is used by the max()/min() python functions
+
+ """
+ return individual.score
+
+def key_fitness_score(individual):
+ """ A key function to return fitness score, used by max()/min()
+
+ :param individual: the individual instance
+ :rtype: the individual fitness score
+
+ .. note:: this function is used by the max()/min() python functions
+
+ """
+ return individual.fitness
+
+
+def multiprocessing_eval(ind):
+ """ Internal used by the multiprocessing """
+ ind.evaluate()
+ return ind.score
+
+def multiprocessing_eval_full(ind):
+ """ Internal used by the multiprocessing (full copy)"""
+ ind.evaluate()
+ return ind
+
+
+class GPopulation:
+ """ GPopulation Class - The container for the population
+
+ **Examples**
+ Get the population from the :class:`GSimpleGA.GSimpleGA` (GA Engine) instance
+ >>> pop = ga_engine.getPopulation()
+
+ Get the best fitness individual
+ >>> bestIndividual = pop.bestFitness()
+
+ Get the best raw individual
+ >>> bestIndividual = pop.bestRaw()
+
+ Get the statistics from the :class:`Statistics.Statistics` instance
+ >>> stats = pop.getStatistics()
+ >>> print stats["rawMax"]
+ 10.4
+
+ Iterate, get/set individuals
+ >>> for ind in pop:
+ >>> print ind
+ (...)
+
+ >>> for i in xrange(len(pop)):
+ >>> print pop[i]
+ (...)
+
+ >>> pop[10] = newGenome
+ >>> pop[10].fitness
+ 12.5
+
+ :param genome: the :term:`Sample genome`, or a GPopulation object, when cloning.
+
+ """
+
+ def __init__(self, genome):
+ """ The GPopulation Class creator """
+
+ if isinstance(genome, GPopulation):
+ self.oneSelfGenome = genome.oneSelfGenome
+ self.internalPop = []
+ self.internalPopRaw = []
+ self.popSize = genome.popSize
+ self.sortType = genome.sortType
+ self.sorted = False
+ self.minimax = genome.minimax
+ self.scaleMethod = genome.scaleMethod
+ self.allSlots = [self.scaleMethod]
+
+ self.internalParams = genome.internalParams
+ self.multiProcessing = genome.multiProcessing
+
+ self.statted = False
+ self.stats = Statistics()
+ return
+
+ logging.debug("New population instance, %s class genomes.", genome.__class__.__name__)
+ self.oneSelfGenome = genome
+ self.internalPop = []
+ self.internalPopRaw = []
+ self.popSize = 0
+ self.sortType = Consts.CDefPopSortType
+ self.sorted = False
+ self.minimax = Consts.CDefPopMinimax
+ self.scaleMethod = FunctionSlot("Scale Method")
+ self.scaleMethod.set(Consts.CDefPopScale)
+ self.allSlots = [self.scaleMethod]
+
+ self.internalParams = {}
+ self.multiProcessing = (False, False)
+
+ # Statistics
+ self.statted = False
+ self.stats = Statistics()
+
+ def setMultiProcessing(self, flag=True, full_copy=False):
+ """ Sets the flag to enable/disable the use of python multiprocessing module.
+ Use this option when you have more than one core on your CPU and when your
+ evaluation function is very slow.
+ The parameter "full_copy" defines where the individual data should be copied back
+ after the evaluation or not. This parameter is useful when you change the
+ individual in the evaluation function.
+
+ :param flag: True (default) or False
+ :param full_copy: True or False (default)
+
+ .. warning:: Use this option only when your evaluation function is slow, se you
+ will get a good tradeoff between the process communication speed and the
+ parallel evaluation.
+
+ .. versionadded:: 0.6
+ The `setMultiProcessing` method.
+
+ """
+ self.multiProcessing = (flag, full_copy)
+
+ def setMinimax(self, minimax):
+ """ Sets the population minimax
+
+ Example:
+ >>> pop.setMinimax(Consts.minimaxType["maximize"])
+
+ :param minimax: the minimax type
+
+ """
+ self.minimax = minimax
+
+ def __repr__(self):
+ """ Returns the string representation of the population """
+ ret = "- GPopulation\n"
+ ret += "\tPopulation Size:\t %d\n" % (self.popSize,)
+ ret += "\tSort Type:\t\t %s\n" % (Consts.sortType.keys()[Consts.sortType.values().index(self.sortType)].capitalize(),)
+ ret += "\tMinimax Type:\t\t %s\n" % (Consts.minimaxType.keys()[Consts.minimaxType.values().index(self.minimax)].capitalize(),)
+ for slot in self.allSlots:
+ ret+= "\t" + slot.__repr__()
+ ret+="\n"
+ ret+= self.stats.__repr__()
+ return ret
+
+ def __len__(self):
+ """ Return the length of population """
+ return len(self.internalPop)
+
+ def __getitem__(self, key):
+ """ Returns the specified individual from population """
+ return self.internalPop[key]
+
+ def __iter__(self):
+ """ Returns the iterator of the population """
+ return iter(self.internalPop)
+
+ def __setitem__(self, key, value):
+ """ Set an individual of population """
+ self.internalPop[key] = value
+ self.clearFlags()
+
+ def clearFlags(self):
+ """ Clear the sorted and statted internal flags """
+ self.sorted = False
+ self.statted = False
+
+ def getStatistics(self):
+ """ Return a Statistics class for statistics
+
+ :rtype: the :class:`Statistics.Statistics` instance
+
+ """
+ self.statistics()
+ return self.stats
+
+ def statistics(self):
+ """ Do statistical analysis of population and set 'statted' to True """
+ if self.statted: return
+ logging.debug("Running statistical calculations")
+ raw_sum = 0
+ fit_sum = 0
+
+ len_pop = len(self)
+ for ind in xrange(len_pop):
+ raw_sum += self[ind].score
+ #fit_sum += self[ind].fitness
+
+ self.stats["rawMax"] = max(self, key=key_raw_score).score
+ self.stats["rawMin"] = min(self, key=key_raw_score).score
+ self.stats["rawAve"] = raw_sum / float(len_pop)
+ #self.stats["rawTot"] = raw_sum
+ #self.stats["fitTot"] = fit_sum
+
+ tmpvar = 0.0
+ for ind in xrange(len_pop):
+ s = self[ind].score - self.stats["rawAve"]
+ s*= s
+ tmpvar += s
+
+ tmpvar/= float((len(self) - 1))
+ try:
+ self.stats["rawDev"] = math_sqrt(tmpvar)
+ except:
+ self.stats["rawDev"] = 0.0
+
+ self.stats["rawVar"] = tmpvar
+
+ self.statted = True
+
+ def bestFitness(self, index=0):
+ """ Return the best scaled fitness individual of population
+
+ :param index: the *index* best individual
+ :rtype: the individual
+
+ """
+ self.sort()
+ return self.internalPop[index]
+
+ def bestRaw(self, index=0):
+ """ Return the best raw score individual of population
+
+ :param index: the *index* best raw individual
+ :rtype: the individual
+
+ .. versionadded:: 0.6
+ The parameter `index`.
+
+ """
+ if self.sortType == Consts.sortType["raw"]:
+ return self.internalPop[index]
+ else:
+ self.sort()
+ return self.internalPopRaw[index]
+
+ def sort(self):
+ """ Sort the population """
+ if self.sorted: return
+ rev = (self.minimax == Consts.minimaxType["maximize"])
+
+ if self.sortType == Consts.sortType["raw"]:
+ self.internalPop.sort(cmp=Util.cmp_individual_raw, reverse=rev)
+ else:
+ self.scale()
+ self.internalPop.sort(cmp=Util.cmp_individual_scaled, reverse=rev)
+ self.internalPopRaw = self.internalPop[:]
+ self.internalPopRaw.sort(cmp=Util.cmp_individual_raw, reverse=rev)
+
+ self.sorted = True
+
+ def setPopulationSize(self, size):
+ """ Set the population size
+
+ :param size: the population size
+
+ """
+ self.popSize = size
+
+ def setSortType(self, sort_type):
+ """ Sets the sort type
+
+ Example:
+ >>> pop.setSortType(Consts.sortType["scaled"])
+
+ :param sort_type: the Sort Type
+
+ """
+ self.sortType = sort_type
+
+ def create(self, **args):
+ """ Clone the example genome to fill the population """
+ self.minimax = args["minimax"]
+ self.internalPop = [self.oneSelfGenome.clone() for i in xrange(self.popSize)]
+ self.clearFlags()
+
+ def __findIndividual(self, individual, end):
+ for i in xrange(end):
+ if individual.compare(self.internalPop[i]) == 0:
+ return True
+
+ def initialize(self, **args):
+ """ Initialize all individuals of population,
+ this calls the initialize() of individuals """
+ logging.debug("Initializing the population")
+
+ if self.oneSelfGenome.getParam("full_diversity", True) and hasattr(self.oneSelfGenome, "compare"):
+ for i in xrange(len(self.internalPop)):
+ curr = self.internalPop[i]
+ curr.initialize(**args)
+ while self.__findIndividual(curr, i):
+ curr.initialize(**args)
+ else:
+ for gen in self.internalPop:
+ gen.initialize(**args)
+ self.clearFlags()
+
+ def evaluate(self, **args):
+ """ Evaluate all individuals in population, calls the evaluate() method of individuals
+
+ :param args: this params are passed to the evaluation function
+
+ """
+ # We have multiprocessing
+ if self.multiProcessing[0] and MULTI_PROCESSING:
+ logging.debug("Evaluating the population using the multiprocessing method")
+ proc_pool = Pool()
+
+ # Multiprocessing full_copy parameter
+ if self.multiProcessing[1]:
+ results = proc_pool.map(multiprocessing_eval_full, self.internalPop)
+ for i in xrange(len(self.internalPop)):
+ self.internalPop[i] = results[i]
+ else:
+ results = proc_pool.map(multiprocessing_eval, self.internalPop)
+ for individual, score in zip(self.internalPop, results):
+ individual.score = score
+ else:
+ for ind in self.internalPop:
+ ind.evaluate(**args)
+
+ self.clearFlags()
+
+ def scale(self, **args):
+ """ Scale the population using the scaling method
+
+ :param args: this parameter is passed to the scale method
+
+ """
+ for it in self.scaleMethod.applyFunctions(self, **args):
+ pass
+
+ fit_sum = 0
+ for ind in xrange(len(self)):
+ fit_sum += self[ind].fitness
+
+ self.stats["fitMax"] = max(self, key=key_fitness_score).fitness
+ self.stats["fitMin"] = min(self, key=key_fitness_score).fitness
+ self.stats["fitAve"] = fit_sum / float(len(self))
+
+ self.sorted = False
+
+ def printStats(self):
+ """ Print statistics of the current population """
+ message = ""
+ if self.sortType == Consts.sortType["scaled"]:
+ message = "Max/Min/Avg Fitness(Raw) [%(fitMax).2f(%(rawMax).2f)/%(fitMin).2f(%(rawMin).2f)/%(fitAve).2f(%(rawAve).2f)]" % self.stats
+ else:
+ message = "Max/Min/Avg Raw [%(rawMax).2f/%(rawMin).2f/%(rawAve).2f]" % self.stats
+ logging.info(message)
+ print message
+ return message
+
+ def copy(self, pop):
+ """ Copy current population to 'pop'
+
+ :param pop: the destination population
+
+ .. warning:: this method do not copy the individuals, only the population logic
+
+ """
+ pop.popSize = self.popSize
+ pop.sortType = self.sortType
+ pop.minimax = self.minimax
+ pop.scaleMethod = self.scaleMethod
+ #pop.internalParams = self.internalParams.copy()
+ pop.internalParams = self.internalParams
+ pop.multiProcessing = self.multiProcessing
+
+ def getParam(self, key, nvl=None):
+ """ Gets an internal parameter
+
+ Example:
+ >>> population.getParam("tournamentPool")
+ 5
+
+ :param key: the key of param
+ :param nvl: if the key doesn't exist, the nvl will be returned
+
+ """
+ return self.internalParams.get(key, nvl)
+
+
+ def setParams(self, **args):
+ """ Gets an internal parameter
+
+ Example:
+ >>> population.setParams(tournamentPool=5)
+
+ :param args: parameters to set
+
+ .. versionadded:: 0.6
+ The `setParams` method.
+ """
+ self.internalParams.update(args)
+
+ def clear(self):
+ """ Remove all individuals from population """
+ del self.internalPop[:]
+ del self.internalPopRaw[:]
+ self.clearFlags()
+
+ def clone(self):
+ """ Return a brand-new cloned population """
+ newpop = GPopulation(self.oneSelfGenome)
+ self.copy(newpop)
+ return newpop
+
+
diff --git a/pyevolve/GSimpleGA.py b/pyevolve/GSimpleGA.py
new file mode 100644
index 0000000..46d05ee
--- /dev/null
+++ b/pyevolve/GSimpleGA.py
@@ -0,0 +1,848 @@
+"""
+
+:mod:`GSimpleGA` -- the genetic algorithm by itself
+=====================================================================
+
+This module contains the GA Engine, the GA Engine class is responsible
+for all the evolutionary process. It contains the GA Engine related
+funtions, like the Termination Criteria functions for convergence analysis, etc.
+
+Default Parameters
+-------------------------------------------------------------
+
+*Number of Generations*
+
+ Default is 100 generations
+
+*Mutation Rate*
+
+ Default is 0.02, which represents 0.2%
+
+*Crossover Rate*
+
+ Default is 0.9, which represents 90%
+
+*Elitism Replacement*
+
+ Default is 1 individual
+
+*Population Size*
+
+ Default is 80 individuals
+
+*Minimax*
+
+ >>> Consts.minimaxType["maximize"]
+
+ Maximize the evaluation function
+
+*DB Adapter*
+
+ Default is **None**
+
+*Migration Adapter*
+
+ Default is **None**
+
+*Interactive Mode*
+
+ Default is **True**
+
+*Selector (Selection Method)*
+
+ :func:`Selectors.GRankSelector`
+
+ The Rank Selection method
+
+Class
+-------------------------------------------------------------
+
+"""
+
+from GPopulation import GPopulation
+from FunctionSlot import FunctionSlot
+from Migration import MigrationScheme
+from GenomeBase import GenomeBase
+from DBAdapters import DBBaseAdapter
+
+import Consts
+import Util
+
+import random
+import logging
+
+from time import time
+from types import BooleanType
+from sys import platform as sys_platform
+from sys import stdout as sys_stdout
+
+import code
+import pyevolve
+
+# Platform dependant code for the Interactive Mode
+if sys_platform[:3] == "win":
+ import msvcrt
+
+def RawScoreCriteria(ga_engine):
+ """ Terminate the evolution using the **bestrawscore** and **rounddecimal**
+ parameter obtained from the individual
+
+ Example:
+ >>> genome.setParams(bestrawscore=0.00, rounddecimal=2)
+ (...)
+ >>> ga_engine.terminationCriteria.set(GSimpleGA.RawScoreCriteria)
+
+ """
+ ind = ga_engine.bestIndividual()
+ bestRawScore = ind.getParam("bestrawscore")
+ roundDecimal = ind.getParam("rounddecimal")
+
+ if bestRawScore is None:
+ Util.raiseException("you must specify the bestrawscore parameter", ValueError)
+
+ if ga_engine.getMinimax() == Consts.minimaxType["maximize"]:
+ if roundDecimal is not None:
+ return round(bestRawScore, roundDecimal) <= round(ind.score, roundDecimal)
+ else:
+ return bestRawScore <= ind.score
+ else:
+ if roundDecimal is not None:
+ return round(bestRawScore, roundDecimal) >= round(ind.score, roundDecimal)
+ else:
+ return bestRawScore >= ind.score
+
+def ConvergenceCriteria(ga_engine):
+ """ Terminate the evolution when the population have converged
+
+ Example:
+ >>> ga_engine.terminationCriteria.set(GSimpleGA.ConvergenceCriteria)
+
+ """
+ pop = ga_engine.getPopulation()
+ return pop[0] == pop[len(pop)-1]
+
+def RawStatsCriteria(ga_engine):
+ """ Terminate the evolution based on the raw stats
+
+ Example:
+ >>> ga_engine.terminationCriteria.set(GSimpleGA.RawStatsCriteria)
+
+ """
+ stats = ga_engine.getStatistics()
+ if stats["rawMax"] == stats["rawMin"]:
+ if stats["rawAve"] == stats["rawMax"]:
+ return True
+ return False
+
+def FitnessStatsCriteria(ga_engine):
+ """ Terminate the evoltion based on the fitness stats
+
+ Example:
+ >>> ga_engine.terminationCriteria.set(GSimpleGA.FitnessStatsCriteria)
+
+
+ """
+ stats = ga_engine.getStatistics()
+ if stats["fitMax"] == stats["fitMin"]:
+ if stats["fitAve"] == stats["fitMax"]:
+ return True
+ return False
+
+class GSimpleGA:
+ """ GA Engine Class - The Genetic Algorithm Core
+
+ Example:
+ >>> ga = GSimpleGA.GSimpleGA(genome)
+ >>> ga.selector.set(Selectors.GRouletteWheel)
+ >>> ga.setGenerations(120)
+ >>> ga.terminationCriteria.set(GSimpleGA.ConvergenceCriteria)
+
+ :param genome: the :term:`Sample Genome`
+ :param interactiveMode: this flag enables the Interactive Mode, the default is True
+ :param seed: the random seed value
+
+ .. note:: if you use the same random seed, all the runs of algorithm will be the same
+
+ """
+
+ selector = None
+ """ This is the function slot for the selection method
+ if you want to change the default selector, you must do this: ::
+
+ ga_engine.selector.set(Selectors.GRouletteWheel) """
+
+ stepCallback = None
+ """ This is the :term:`step callback function` slot,
+ if you want to set the function, you must do this: ::
+
+ def your_func(ga_engine):
+ # Here you have access to the GA Engine
+ return False
+
+ ga_engine.stepCallback.set(your_func)
+
+ now *"your_func"* will be called every generation.
+ When this function returns True, the GA Engine will stop the evolution and show
+ a warning, if is False, the evolution continues.
+ """
+
+ terminationCriteria = None
+ """ This is the termination criteria slot, if you want to set one
+ termination criteria, you must do this: ::
+
+ ga_engine.terminationCriteria.set(GSimpleGA.ConvergenceCriteria)
+
+ Now, when you run your GA, it will stop when the population converges.
+
+ There are those termination criteria functions: :func:`GSimpleGA.RawScoreCriteria`, :func:`GSimpleGA.ConvergenceCriteria`, :func:`GSimpleGA.RawStatsCriteria`, :func:`GSimpleGA.FitnessStatsCriteria`
+
+ But you can create your own termination function, this function receives
+ one parameter which is the GA Engine, follows an example: ::
+
+ def ConvergenceCriteria(ga_engine):
+ pop = ga_engine.getPopulation()
+ return pop[0] == pop[len(pop)-1]
+
+ When this function returns True, the GA Engine will stop the evolution and show
+ a warning, if is False, the evolution continues, this function is called every
+ generation.
+ """
+
+ def __init__(self, genome, seed=None, interactiveMode=True):
+ """ Initializator of GSimpleGA """
+ if seed: random.seed(seed)
+
+ if type(interactiveMode) != BooleanType:
+ Util.raiseException("Interactive Mode option must be True or False", TypeError)
+
+ if not isinstance(genome, GenomeBase):
+ Util.raiseException("The genome must be a GenomeBase subclass", TypeError)
+
+ self.internalPop = GPopulation(genome)
+ self.nGenerations = Consts.CDefGAGenerations
+ self.pMutation = Consts.CDefGAMutationRate
+ self.pCrossover = Consts.CDefGACrossoverRate
+ self.nElitismReplacement = Consts.CDefGAElitismReplacement
+ self.setPopulationSize(Consts.CDefGAPopulationSize)
+ self.minimax = Consts.minimaxType["maximize"]
+ self.elitism = True
+
+ # Adapters
+ self.dbAdapter = None
+ self.migrationAdapter = None
+
+ self.time_init = None
+ self.interactiveMode = interactiveMode
+ self.interactiveGen = -1
+ self.GPMode = False
+
+ self.selector = FunctionSlot("Selector")
+ self.stepCallback = FunctionSlot("Generation Step Callback")
+ self.terminationCriteria = FunctionSlot("Termination Criteria")
+ self.selector.set(Consts.CDefGASelector)
+ self.allSlots = [ self.selector, self.stepCallback, self.terminationCriteria ]
+
+ self.internalParams = {}
+
+ self.currentGeneration = 0
+
+ # GP Testing
+ for classes in Consts.CDefGPGenomes:
+ if isinstance(self.internalPop.oneSelfGenome, classes):
+ self.setGPMode(True)
+ break
+
+ logging.debug("A GA Engine was created, nGenerations=%d", self.nGenerations)
+
+ def setGPMode(self, bool_value):
+ """ Sets the Genetic Programming mode of the GA Engine
+
+ :param bool_value: True or False
+ """
+ self.GPMode = bool_value
+
+ def getGPMode(self):
+ """ Get the Genetic Programming mode of the GA Engine
+
+ :rtype: True or False
+ """
+ return self.GPMode
+
+ def __call__(self, *args, **kwargs):
+ """ A method to implement a callable object
+
+ Example:
+ >>> ga_engine(freq_stats=10)
+
+ .. versionadded:: 0.6
+ The callable method.
+ """
+ if kwargs.get("freq_stats", None):
+ return self.evolve(kwargs.get("freq_stats"))
+ else:
+ return self.evolve()
+
+ def setParams(self, **args):
+ """ Set the internal params
+
+ Example:
+ >>> ga.setParams(gp_terminals=['x', 'y'])
+
+
+ :param args: params to save
+
+ ..versionaddd:: 0.6
+ Added the *setParams* method.
+ """
+ self.internalParams.update(args)
+
+ def getParam(self, key, nvl=None):
+ """ Gets an internal parameter
+
+ Example:
+ >>> ga.getParam("gp_terminals")
+ ['x', 'y']
+
+ :param key: the key of param
+ :param nvl: if the key doesn't exist, the nvl will be returned
+
+ ..versionaddd:: 0.6
+ Added the *getParam* method.
+ """
+ return self.internalParams.get(key, nvl)
+
+ def setInteractiveGeneration(self, generation):
+ """ Sets the generation in which the GA must enter in the
+ Interactive Mode
+
+ :param generation: the generation number, use "-1" to disable
+
+ .. versionadded::0.6
+ The *setInteractiveGeneration* method.
+ """
+ if generation < -1:
+ Util.raiseException("Generation must be >= -1", ValueError)
+ self.interactiveGen = generation
+
+ def getInteractiveGeneration(self):
+ """ returns the generation in which the GA must enter in the
+ Interactive Mode
+
+ :rtype: the generation number or -1 if not set
+
+ .. versionadded::0.6
+ The *getInteractiveGeneration* method.
+ """
+ return self.interactiveGen
+
+ def setElitismReplacement(self, numreplace):
+ """ Set the number of best individuals to copy to the next generation on the elitism
+
+ :param numreplace: the number of individuals
+
+ .. versionadded:: 0.6
+ The *setElitismReplacement* method.
+
+ """
+ if numreplace < 1:
+ Util.raiseException("Replacement number must be >= 1", ValueError)
+ self.nElitismReplacement = numreplace
+
+
+ def setInteractiveMode(self, flag=True):
+ """ Enable/disable the interactive mode
+
+ :param flag: True or False
+
+ .. versionadded: 0.6
+ The *setInteractiveMode* method.
+
+ """
+ if type(flag) != BooleanType:
+ Util.raiseException("Interactive Mode option must be True or False", TypeError)
+ self.interactiveMode = flag
+
+
+ def __repr__(self):
+ """ The string representation of the GA Engine """
+ ret = "- GSimpleGA\n"
+ ret += "\tGP Mode:\t\t %s\n" % self.getGPMode()
+ ret += "\tPopulation Size:\t %d\n" % (self.internalPop.popSize,)
+ ret += "\tGenerations:\t\t %d\n" % (self.nGenerations,)
+ ret += "\tCurrent Generation:\t %d\n" % (self.currentGeneration,)
+ ret += "\tMutation Rate:\t\t %.2f\n" % (self.pMutation,)
+ ret += "\tCrossover Rate:\t\t %.2f\n" % (self.pCrossover,)
+ ret += "\tMinimax Type:\t\t %s\n" % (Consts.minimaxType.keys()[Consts.minimaxType.values().index(self.minimax)].capitalize(),)
+ ret += "\tElitism:\t\t %s\n" % (self.elitism,)
+ ret += "\tElitism Replacement:\t %d\n" % (self.nElitismReplacement,)
+ ret += "\tDB Adapter:\t\t %s\n" % (self.dbAdapter,)
+ for slot in self.allSlots:
+ ret+= "\t" + slot.__repr__()
+ ret+="\n"
+ return ret
+
+ def setMultiProcessing(self, flag=True, full_copy=False):
+ """ Sets the flag to enable/disable the use of python multiprocessing module.
+ Use this option when you have more than one core on your CPU and when your
+ evaluation function is very slow.
+
+ Pyevolve will automaticly check if your Python version has **multiprocessing**
+ support and if you have more than one single CPU core. If you don't have support
+ or have just only one core, Pyevolve will not use the **multiprocessing**
+ feature.
+
+ Pyevolve uses the **multiprocessing** to execute the evaluation function over
+ the individuals, so the use of this feature will make sense if you have a
+ truly slow evaluation function (which is commom in GAs).
+
+ The parameter "full_copy" defines where the individual data should be copied back
+ after the evaluation or not. This parameter is useful when you change the
+ individual in the evaluation function.
+
+ :param flag: True (default) or False
+ :param full_copy: True or False (default)
+
+ .. warning:: Use this option only when your evaluation function is slow, so you'll
+ get a good tradeoff between the process communication speed and the
+ parallel evaluation. The use of the **multiprocessing** doesn't means
+ always a better performance.
+
+ .. note:: To enable the multiprocessing option, you **MUST** add the *__main__* check
+ on your application, otherwise, it will result in errors. See more on the
+ `Python Docs <http://docs.python.org/library/multiprocessing.html#multiprocessing-programming>`__
+ site.
+
+ .. versionadded:: 0.6
+ The `setMultiProcessing` method.
+
+ """
+ if type(flag) != BooleanType:
+ Util.raiseException("Multiprocessing option must be True or False", TypeError)
+
+ if type(full_copy) != BooleanType:
+ Util.raiseException("Multiprocessing 'full_copy' option must be True or False", TypeError)
+
+ self.internalPop.setMultiProcessing(flag, full_copy)
+
+ def setMigrationAdapter(self, migration_adapter=None):
+ """ Sets the Migration Adapter
+
+ .. versionadded:: 0.6
+ The `setMigrationAdapter` method.
+ """
+ if (migration_adapter is not None) and (not isinstance(migration_adapter, MigrationScheme)):
+ Util.raiseException("The Migration Adapter must be a MigrationScheme subclass", TypeError)
+
+ self.migrationAdapter = migration_adapter
+ if self.migrationAdapter is not None:
+ self.migrationAdapter.setGAEngine(self)
+
+ def setDBAdapter(self, dbadapter=None):
+ """ Sets the DB Adapter of the GA Engine
+
+ :param dbadapter: one of the :mod:`DBAdapters` classes instance
+
+ .. warning:: the use the of a DB Adapter can reduce the speed performance of the
+ Genetic Algorithm.
+ """
+ if (dbadapter is not None) and (not isinstance(dbadapter, DBBaseAdapter)):
+ Util.raiseException("The DB Adapter must be a DBBaseAdapter subclass", TypeError)
+ self.dbAdapter = dbadapter
+
+ def setPopulationSize(self, size):
+ """ Sets the population size, calls setPopulationSize() of GPopulation
+
+ :param size: the population size
+
+ .. note:: the population size must be >= 2
+
+ """
+ if size < 2:
+ Util.raiseException("population size must be >= 2", ValueError)
+ self.internalPop.setPopulationSize(size)
+
+ def setSortType(self, sort_type):
+ """ Sets the sort type, Consts.sortType["raw"]/Consts.sortType["scaled"]
+
+ Example:
+ >>> ga_engine.setSortType(Consts.sortType["scaled"])
+
+ :param sort_type: the Sort Type
+
+ """
+ if sort_type not in Consts.sortType.values():
+ Util.raiseException("sort type must be a Consts.sortType type", TypeError)
+ self.internalPop.sortType = sort_type
+
+ def setMutationRate(self, rate):
+ """ Sets the mutation rate, between 0.0 and 1.0
+
+ :param rate: the rate, between 0.0 and 1.0
+
+ """
+ if (rate>1.0) or (rate<0.0):
+ Util.raiseException("Mutation rate must be >= 0.0 and <= 1.0", ValueError)
+ self.pMutation = rate
+
+ def setCrossoverRate(self, rate):
+ """ Sets the crossover rate, between 0.0 and 1.0
+
+ :param rate: the rate, between 0.0 and 1.0
+
+ """
+ if (rate>1.0) or (rate<0.0):
+ Util.raiseException("Crossover rate must be >= 0.0 and <= 1.0", ValueError)
+ self.pCrossover = rate
+
+ def setGenerations(self, num_gens):
+ """ Sets the number of generations to evolve
+
+ :param num_gens: the number of generations
+
+ """
+ if num_gens < 1:
+ Util.raiseException("Number of generations must be >= 1", ValueError)
+ self.nGenerations = num_gens
+
+ def getGenerations(self):
+ """ Return the number of generations to evolve
+
+ :rtype: the number of generations
+
+ .. versionadded:: 0.6
+ Added the *getGenerations* method
+ """
+ return self.nGenerations
+
+ def getMinimax(self):
+ """ Gets the minimize/maximize mode
+
+ :rtype: the Consts.minimaxType type
+
+ """
+ return self.minimax
+
+ def setMinimax(self, mtype):
+ """ Sets the minimize/maximize mode, use Consts.minimaxType
+
+ :param mtype: the minimax mode, from Consts.minimaxType
+
+ """
+ if mtype not in Consts.minimaxType.values():
+ Util.raiseException("Minimax must be maximize or minimize", TypeError)
+ self.minimax = mtype
+
+ def getCurrentGeneration(self):
+ """ Gets the current generation
+
+ :rtype: the current generation
+
+ """
+ return self.currentGeneration
+
+ def setElitism(self, flag):
+ """ Sets the elitism option, True or False
+
+ :param flag: True or False
+
+ """
+ if type(flag) != BooleanType:
+ Util.raiseException("Elitism option must be True or False", TypeError)
+ self.elitism = flag
+
+ def getDBAdapter(self):
+ """ Gets the DB Adapter of the GA Engine
+
+ :rtype: a instance from one of the :mod:`DBAdapters` classes
+
+ """
+ return self.dbAdapter
+
+ def bestIndividual(self):
+ """ Returns the population best individual
+
+ :rtype: the best individual
+
+ """
+ return self.internalPop.bestRaw()
+
+ def __gp_catch_functions(self, prefix):
+ """ Internally used to catch functions with some specific prefix
+ as non-terminals of the GP core """
+ import __main__ as mod_main
+
+ function_set = {}
+
+ main_dict = mod_main.__dict__
+ for obj, addr in main_dict.items():
+ if obj[0:len(prefix)] == prefix:
+ try:
+ op_len = addr.func_code.co_argcount
+ except:
+ continue
+ function_set[obj] = op_len
+
+ if len(function_set) <= 0:
+ Util.raiseException("No function set found using function prefix '%s' !" % prefix, ValueError)
+
+ self.setParams(gp_function_set=function_set)
+
+ def initialize(self):
+ """ Initializes the GA Engine. Create and initialize population """
+ self.internalPop.create(minimax=self.minimax)
+ self.internalPop.initialize(ga_engine=self)
+ logging.debug("The GA Engine was initialized !")
+
+ def getPopulation(self):
+ """ Return the internal population of GA Engine
+
+ :rtype: the population (:class:`GPopulation.GPopulation`)
+
+ """
+ return self.internalPop
+
+ def getStatistics(self):
+ """ Gets the Statistics class instance of current generation
+
+ :rtype: the statistics instance (:class:`Statistics.Statistics`)
+
+ """
+ return self.internalPop.getStatistics()
+
+ def step(self):
+ """ Just do one step in evolution, one generation """
+ genomeMom = None
+ genomeDad = None
+
+ newPop = GPopulation(self.internalPop)
+ logging.debug("Population was cloned.")
+
+ size_iterate = len(self.internalPop)
+
+ # Odd population size
+ if size_iterate % 2 != 0: size_iterate -= 1
+
+ crossover_empty = self.select(popID=self.currentGeneration).crossover.isEmpty()
+
+ for i in xrange(0, size_iterate, 2):
+ genomeMom = self.select(popID=self.currentGeneration)
+ genomeDad = self.select(popID=self.currentGeneration)
+
+ if not crossover_empty and self.pCrossover >= 1.0:
+ for it in genomeMom.crossover.applyFunctions(mom=genomeMom, dad=genomeDad, count=2):
+ (sister, brother) = it
+ else:
+ if not crossover_empty and Util.randomFlipCoin(self.pCrossover):
+ for it in genomeMom.crossover.applyFunctions(mom=genomeMom, dad=genomeDad, count=2):
+ (sister, brother) = it
+ else:
+ sister = genomeMom.clone()
+ brother = genomeDad.clone()
+
+ sister.mutate(pmut=self.pMutation, ga_engine=self)
+ brother.mutate(pmut=self.pMutation, ga_engine=self)
+
+ newPop.internalPop.append(sister)
+ newPop.internalPop.append(brother)
+
+ if len(self.internalPop) % 2 != 0:
+ genomeMom = self.select(popID=self.currentGeneration)
+ genomeDad = self.select(popID=self.currentGeneration)
+
+ if Util.randomFlipCoin(self.pCrossover):
+ for it in genomeMom.crossover.applyFunctions(mom=genomeMom, dad=genomeDad, count=1):
+ (sister, brother) = it
+ else:
+ sister = random.choice([genomeMom, genomeDad])
+ sister = sister.clone()
+ sister.mutate(pmut=self.pMutation, ga_engine=self)
+
+ newPop.internalPop.append(sister)
+
+ logging.debug("Evaluating the new created population.")
+ newPop.evaluate()
+
+ if self.elitism:
+ logging.debug("Doing elitism.")
+ if self.getMinimax() == Consts.minimaxType["maximize"]:
+ for i in xrange(self.nElitismReplacement):
+ if self.internalPop.bestRaw(i).score > newPop.bestRaw(i).score:
+ newPop[len(newPop)-1-i] = self.internalPop.bestRaw(i)
+ elif self.getMinimax() == Consts.minimaxType["minimize"]:
+ for i in xrange(self.nElitismReplacement):
+ if self.internalPop.bestRaw(i).score < newPop.bestRaw(i).score:
+ newPop[len(newPop)-1-i] = self.internalPop.bestRaw(i)
+
+ self.internalPop = newPop
+ self.internalPop.sort()
+
+ logging.debug("The generation %d was finished.", self.currentGeneration)
+
+ self.currentGeneration += 1
+
+ return (self.currentGeneration == self.nGenerations)
+
+ def printStats(self):
+ """ Print generation statistics
+
+ :rtype: the printed statistics as string
+
+ .. versionchanged:: 0.6
+ The return of *printStats* method.
+ """
+ percent = self.currentGeneration * 100 / float(self.nGenerations)
+ message = "Gen. %d (%.2f%%):" % (self.currentGeneration, percent)
+ logging.info(message)
+ print message,
+ sys_stdout.flush()
+ self.internalPop.statistics()
+ stat_ret = self.internalPop.printStats()
+ return message + stat_ret
+
+ def printTimeElapsed(self):
+ """ Shows the time elapsed since the begin of evolution """
+ total_time = time()-self.time_init
+ print "Total time elapsed: %.3f seconds." % total_time
+ return total_time
+
+ def dumpStatsDB(self):
+ """ Dumps the current statistics to database adapter """
+ logging.debug("Dumping stats to the DB Adapter")
+ self.internalPop.statistics()
+ self.dbAdapter.insert(self)
+
+ def evolve(self, freq_stats=0):
+ """ Do all the generations until the termination criteria, accepts
+ the freq_stats (default is 0) to dump statistics at n-generation
+
+ Example:
+ >>> ga_engine.evolve(freq_stats=10)
+ (...)
+
+ :param freq_stats: if greater than 0, the statistics will be
+ printed every freq_stats generation.
+ :rtype: returns the best individual of the evolution
+
+ .. versionadded:: 0.6
+ the return of the best individual
+
+ """
+
+ stopFlagCallback = False
+ stopFlagTerminationCriteria = False
+
+ self.time_init = time()
+
+ logging.debug("Starting the DB Adapter and the Migration Adapter if any")
+ if self.dbAdapter: self.dbAdapter.open(self)
+ if self.migrationAdapter: self.migrationAdapter.start()
+
+
+ if self.getGPMode():
+ gp_function_prefix = self.getParam("gp_function_prefix")
+ if gp_function_prefix is not None:
+ self.__gp_catch_functions(gp_function_prefix)
+
+ self.initialize()
+ self.internalPop.evaluate()
+ self.internalPop.sort()
+ logging.debug("Starting loop over evolutionary algorithm.")
+
+ try:
+ while True:
+ if self.migrationAdapter:
+ logging.debug("Migration adapter: exchange")
+ self.migrationAdapter.exchange()
+ self.internalPop.clearFlags()
+ self.internalPop.sort()
+
+ if not self.stepCallback.isEmpty():
+ for it in self.stepCallback.applyFunctions(self):
+ stopFlagCallback = it
+
+ if not self.terminationCriteria.isEmpty():
+ for it in self.terminationCriteria.applyFunctions(self):
+ stopFlagTerminationCriteria = it
+
+ if freq_stats:
+ if (self.currentGeneration % freq_stats == 0) or (self.getCurrentGeneration() == 0):
+ self.printStats()
+
+ if self.dbAdapter:
+ if self.currentGeneration % self.dbAdapter.getStatsGenFreq() == 0:
+ self.dumpStatsDB()
+
+ if stopFlagTerminationCriteria:
+ logging.debug("Evolution stopped by the Termination Criteria !")
+ if freq_stats:
+ print "\n\tEvolution stopped by Termination Criteria function !\n"
+ break
+
+ if stopFlagCallback:
+ logging.debug("Evolution stopped by Step Callback function !")
+ if freq_stats:
+ print "\n\tEvolution stopped by Step Callback function !\n"
+ break
+
+ if self.interactiveMode:
+ if sys_platform[:3] == "win":
+ if msvcrt.kbhit():
+ if ord(msvcrt.getch()) == Consts.CDefESCKey:
+ print "Loading modules for Interactive Mode...",
+ logging.debug("Windows Interactive Mode key detected ! generation=%d", self.getCurrentGeneration())
+ from pyevolve import Interaction
+ print " done !"
+ interact_banner = "## Pyevolve v.%s - Interactive Mode ##\nPress CTRL-Z to quit interactive mode." % (pyevolve.__version__,)
+ session_locals = { "ga_engine" : self,
+ "population" : self.getPopulation(),
+ "pyevolve" : pyevolve,
+ "it" : Interaction}
+ print
+ code.interact(interact_banner, local=session_locals)
+
+ if (self.getInteractiveGeneration() >= 0) and (self.getInteractiveGeneration() == self.getCurrentGeneration()):
+ print "Loading modules for Interactive Mode...",
+ logging.debug("Manual Interactive Mode key detected ! generation=%d", self.getCurrentGeneration())
+ from pyevolve import Interaction
+ print " done !"
+ interact_banner = "## Pyevolve v.%s - Interactive Mode ##" % (pyevolve.__version__,)
+ session_locals = { "ga_engine" : self,
+ "population" : self.getPopulation(),
+ "pyevolve" : pyevolve,
+ "it" : Interaction}
+ print
+ code.interact(interact_banner, local=session_locals)
+
+ if self.step(): break
+
+ except KeyboardInterrupt:
+ logging.debug("CTRL-C detected, finishing evolution.")
+ if freq_stats: print "\n\tA break was detected, you have interrupted the evolution !\n"
+
+ if freq_stats != 0:
+ self.printStats()
+ self.printTimeElapsed()
+
+ if self.dbAdapter:
+ logging.debug("Closing the DB Adapter")
+ if not (self.currentGeneration % self.dbAdapter.getStatsGenFreq() == 0):
+ self.dumpStatsDB()
+ self.dbAdapter.commitAndClose()
+
+ if self.migrationAdapter:
+ logging.debug("Closing the Migration Adapter")
+ if freq_stats: print "Stopping the migration adapter... ",
+ self.migrationAdapter.stop()
+ if freq_stats: print "done !"
+
+ return self.bestIndividual()
+
+ def select(self, **args):
+ """ Select one individual from population
+
+ :param args: this parameters will be sent to the selector
+
+ """
+ for it in self.selector.applyFunctions(self.internalPop, **args):
+ return it
+
diff --git a/pyevolve/GTree.py b/pyevolve/GTree.py
new file mode 100644
index 0000000..de4fa24
--- /dev/null
+++ b/pyevolve/GTree.py
@@ -0,0 +1,741 @@
+"""
+
+:mod:`GTree` and GTreeGP -- the tree chromosomes
+=============================================================
+
+This is the rooted tree representation, this chromosome representation
+can carry any data-type.
+
+Default Parameters
+-------------------------------------------------------------
+
+*Initializator*
+
+ :func:`Initializators.GTreeInitializatorInteger`
+
+ The Integer Initializator for GTree
+
+*Mutator*
+
+ :func:`Mutators.GTreeMutatorIntegerRange`
+
+ The Integer Range mutator for GTree
+
+*Crossover*
+
+ :func:`Crossovers.GTreeCrossoverSinglePointStrict`
+
+ The Strict Single Point crossover for GTree
+
+.. versionadded:: 0.6
+ The *GTree* module.
+
+Classes
+-------------------------------------------------------------
+"""
+import random
+from GenomeBase import GenomeBase, GTreeBase, GTreeNodeBase
+import Consts
+import Util
+
+try:
+ import pydot
+ HAVE_PYDOT = True
+except ImportError:
+ HAVE_PYDOT = False
+
+#################################
+# GTree #
+#################################
+
+
+class GTree(GenomeBase, GTreeBase):
+ """ The GTree class - The tree chromosome representation
+
+ Inheritance diagram for :class:`GTree.GTree`:
+
+ .. inheritance-diagram:: GTree.GTree
+
+ :param root_node: the root node of the tree
+ """
+
+ evaluator = None
+ """ This is the :term:`evaluation function` slot, you can add
+ a function with the *set* method: ::
+
+ genome.evaluator.set(eval_func)
+ """
+
+ initializator = None
+ """ This is the initialization function of the genome, you
+ can change the default initializator using the function slot: ::
+
+ genome.initializator.set(Initializators.G1DListInitializatorAllele)
+
+ In this example, the initializator :func:`Initializators.G1DListInitializatorAllele`
+ will be used to create the initial population.
+ """
+
+ mutator = None
+ """ This is the mutator function slot, you can change the default
+ mutator using the slot *set* function: ::
+
+ genome.mutator.set(Mutators.G1DListMutatorSwap)
+
+ """
+
+ crossover = None
+ """ This is the reproduction function slot, the crossover. You
+ can change the default crossover method using: ::
+
+ genome.crossover.set(Crossovers.G1DListCrossoverUniform)
+ """
+
+ def __init__(self, root_node=None):
+ GenomeBase.__init__(self)
+ GTreeBase.__init__(self, root_node)
+ self.initializator.set(Consts.CDefGTreeInit)
+ self.mutator.set(Consts.CDefGGTreeMutator)
+ self.crossover.set(Consts.CDefGTreeCrossover)
+
+ def __repr__(self):
+ """ Return a string representation of Genome """
+ ret = GenomeBase.__repr__(self)
+ ret += GTreeBase.__repr__(self)
+ return ret
+
+ def copy(self, g):
+ """ Copy the contents to the destination g
+
+ :param g: the GTree genome destination
+ """
+ GenomeBase.copy(self, g)
+ GTreeBase.copy(self, g)
+
+ def clone(self):
+ """ Return a new instance of the genome
+
+ :rtype: new GTree instance
+ """
+ newcopy = GTree()
+ self.copy(newcopy)
+ newcopy.processNodes(True)
+ return newcopy
+
+class GTreeNode(GTreeNodeBase):
+ """ The GTreeNode class - The node representation
+
+ Inheritance diagram for :class:`GTree.GTreeNode`:
+
+ .. inheritance-diagram:: GTree.GTreeNode
+
+ :param data: the root node of the tree
+ :param parent: the parent node, if root, this
+ must be *None*
+ """
+
+ def __init__(self, data, parent=None):
+ GTreeNodeBase.__init__(self, parent)
+ self.node_data = data
+
+ def __repr__(self):
+ str_repr = GTreeNodeBase.__repr__(self)
+ str_repr += " - [%s]" % self.node_data
+ return str_repr
+
+ def setData(self, data):
+ """ Sets the data of the node
+
+ :param data: the data of the node
+ """
+ self.node_data = data
+
+ def getData(self):
+ """ Return the data of the node
+
+ :rtype: the data of the node
+ """
+ return self.node_data
+
+ def newNode(self, data):
+ """ Created a new child node
+
+ :param data: the data of the new created node
+ """
+ node = GTreeNode(data, self)
+ self.addChild(node)
+ return node
+
+ def swapNodeData(self, node):
+ """ Swaps the node data with another node
+
+ :param node: the node to do the data swap
+ """
+ tmp_data = self.node_data
+ self.setData(node.getData())
+ node.setData(tmp_data)
+
+ def copy(self, g):
+ """ Copy the contents to the destination g
+
+ :param g: the GTreeNode genome destination
+ """
+ GTreeNodeBase.copy(self, g)
+ g.node_data = self.node_data
+
+ def clone(self):
+ """ Return a new instance of the genome
+
+ :rtype: new GTree instance
+ """
+ newcopy = GTreeNode(None)
+ self.copy(newcopy)
+ return newcopy
+
+#################################
+# Tree Utility Functions #
+#################################
+
+
+def buildGTreeGrow(depth, value_callback, max_siblings, max_depth):
+ """ Random generates a Tree structure using the value_callback
+ for data generation and the method "Grow"
+
+ :param depth: the initial depth, zero
+ :param value_callback: the function which generates the random
+ values for nodes
+ :param max_siblings: the maximum number of sisters of a node
+ :param max_depth: the maximum depth of the tree
+
+ :rtype: the root node of created tree
+ """
+
+ random_value = value_callback()
+ n = GTreeNode(random_value)
+
+ if depth == max_depth: return n
+
+ for i in xrange(random.randint(0, abs(max_siblings))):
+ child = buildGTreeGrow(depth+1, value_callback, max_siblings, max_depth)
+ child.setParent(n)
+ n.addChild(child)
+ return n
+
+def buildGTreeFull(depth, value_callback, max_siblings, max_depth):
+ """ Random generates a Tree structure using the value_callback
+ for data generation and the method "Full"
+
+ :param depth: the initial depth, zero
+ :param value_callback: the function which generates the random
+ values for nodes
+ :param max_siblings: the maximum number of sisters of a node
+ :param max_depth: the maximum depth of the tree
+
+ :rtype: the root node of created tree
+ """
+
+ random_value = value_callback()
+ n = GTreeNode(random_value)
+
+ if depth == max_depth: return n
+
+ if max_siblings < 0: range_val = abs(max_siblings)
+ else: range_val = random.randint(1, abs(max_siblings))
+
+ for i in xrange(range_val):
+ child = buildGTreeFull(depth+1, value_callback, max_siblings, max_depth)
+ child.setParent(n)
+ n.addChild(child)
+ return n
+
+#################################
+# GTree GP #
+#################################
+
+class GTreeNodeGP(GTreeNodeBase):
+ """ The GTreeNodeGP Class - The Genetic Programming Node representation
+
+ Inheritance diagram for :class:`GTree.GTreeNodeGP`:
+
+ .. inheritance-diagram:: GTree.GTreeNodeGP
+
+ :param data: the node data
+ :param type: the node type
+ :param parent: the node parent
+
+ """
+ def __init__(self, data, node_type=0, parent=None):
+ GTreeNodeBase.__init__(self, parent)
+ self.node_type = node_type
+ self.node_data = data
+
+ def __repr__(self):
+ str_repr = GTreeNodeBase.__repr__(self)
+ str_repr += " - [%s]" % self.node_data
+ return str_repr
+
+ def compare(self, other):
+ """ Compare this node with other
+
+ :param other: the other GTreeNodeGP
+ """
+ if not isinstance(other, GTreeNodeGP):
+ Util.raiseException("The other node used to compare is not a GTreeNodeGP class", TypeError)
+
+ if other.node_type == self.node_type:
+ if other.node_data == self.node_data:
+ return 0
+ return -1
+
+ def setData(self, data):
+ """Sets the node internal data
+
+ :param data: the internal data
+ """
+ self.node_data = data
+
+ def getData(self):
+ """Gets the node internal data
+
+ :rtype: the internal data
+ """
+ return self.node_data
+
+ def setType(self, node_type):
+ """Sets the node type
+
+ :param node_type: the node type is type of Consts.nodeType
+ """
+ self.node_type = node_type
+
+ def getType(self):
+ """Get the node type
+
+ :rtype: the node type is type of Consts.nodeType
+ """
+ return self.node_type
+
+ def newNode(self, data):
+ """Creates a new node and adds this
+ node as children of current node
+
+ :param data: the internal node data
+ """
+ node = GTreeNodeGP(data, self)
+ self.addChild(node)
+ return node
+
+ def swapNodeData(self, node):
+ """Swaps the node data and type with another node
+
+ :param node: the node
+ """
+ tmp_data = self.node_data
+ tmp_type = self.node_type
+ self.setData(node.getData())
+ self.setType(node.getType())
+ node.setData(tmp_data)
+ node.setType(tmp_type)
+
+ def copy(self, g):
+ """ Copy the contents to the destination g
+
+ :param g: the GTreeNodeGP genome destination
+ """
+ GTreeNodeBase.copy(self, g)
+ g.node_data = self.node_data
+ g.node_type = self.node_type
+
+ def clone(self):
+ """ Return a new copy of the node
+
+ :rtype: the new GTreeNodeGP instance
+ """
+ newcopy = GTreeNodeGP(None)
+ self.copy(newcopy)
+ return newcopy
+
+class GTreeGP(GenomeBase, GTreeBase):
+ """ The GTreeGP Class - The Genetic Programming Tree representation
+
+ Inheritance diagram for :class:`GTree.GTreeGP`:
+
+ .. inheritance-diagram:: GTree.GTreeGP
+
+ :param root_node: the Root node of the GP Tree
+ """
+ def __init__(self, root_node=None, cloning=False):
+ GenomeBase.__init__(self)
+ GTreeBase.__init__(self, root_node)
+ if not cloning:
+ self.initializator.set(Consts.CDefGTreeGPInit)
+ self.mutator.set(Consts.CDefGGTreeGPMutator)
+ self.crossover.set(Consts.CDefGTreeGPCrossover)
+
+ def __repr__(self):
+ """ Return a string representation of Genome """
+ ret = GenomeBase.__repr__(self)
+ ret += GTreeBase.__repr__(self)
+ ret += "\n- GTreeGP\n"
+ ret += "\tExpression: %s\n" % self.getPreOrderExpression()
+ return ret
+
+ def writeDotImage(self, filename):
+ """ Writes a image representation of the individual
+
+ :param filename: the output file image
+ """
+ if not HAVE_PYDOT:
+ Util.raiseException("You must install Pydot to use this feature !")
+
+ graph = pydot.Dot()
+ self.writeDotGraph(graph)
+ graph.write_jpeg(filename, prog='dot')
+
+ def writeDotRaw(self, filename):
+ """ Writes the raw dot file (text-file used by dot/neato) with the
+ representation of the individual
+
+ :param filename: the output file, ex: individual.dot
+ """
+ if not HAVE_PYDOT:
+ Util.raiseException("You must install Pydot to use this feature !")
+
+ graph = pydot.Dot(graph_type="digraph")
+ self.writeDotGraph(graph)
+ graph.write(filename, prog='dot', format="raw")
+
+ def writeDotGraph(self, graph, startNode=0):
+ """ Write a graph to the pydot Graph instance
+
+ :param graph: the pydot Graph instance
+ :param startNode: used to plot more than one individual
+ """
+ if not HAVE_PYDOT:
+ print "You must install Pydot to use this feature !"
+ return
+
+ count = startNode
+ node_stack = []
+ nodes_dict = {}
+ tmp = None
+ import __main__ as main_module
+
+ for i in xrange(len(self.nodes_list)):
+ newnode = pydot.Node(str(count), style="filled")
+ count += 1
+
+ if self.nodes_list[i].getType() == Consts.nodeType["TERMINAL"]:
+ newnode.set_color("lightblue2")
+ else:
+ newnode.set_color("goldenrod2")
+
+ if self.nodes_list[i].getType() == Consts.nodeType["NONTERMINAL"]:
+ func = getattr(main_module, self.nodes_list[i].getData())
+
+ if hasattr(func, "shape"):
+ newnode.set_shape(func.shape)
+
+ if hasattr(func, "representation"):
+ newnode.set_label(func.representation)
+ else:
+ newnode.set_label(self.nodes_list[i].getData())
+ if hasattr(func, "color"): newnode.set_color(func.color)
+
+ else:
+ newnode.set_label(self.nodes_list[i].getData())
+
+ nodes_dict.update({self.nodes_list[i]: newnode})
+ graph.add_node(newnode)
+
+ node_stack.append(self.getRoot())
+ while len(node_stack) > 0:
+ tmp = node_stack.pop()
+
+ parent = tmp.getParent()
+ if parent is not None:
+ parent_node = nodes_dict[parent]
+ child_node = nodes_dict[tmp]
+
+ newedge = pydot.Edge(parent_node, child_node)
+ graph.add_edge(newedge)
+
+ rev_childs = tmp.getChilds()[:]
+ rev_childs.reverse()
+ node_stack.extend(rev_childs)
+
+ return count
+
+
+
+ def getSExpression(self, start_node=None):
+ """ Returns a tree-formated string (s-expression) of the tree.
+
+ :rtype: a S-Expression representing the tree
+ """
+ str_buff = ""
+ if start_node is None:
+ start_node = self.getRoot()
+ str_buff += "%s " % start_node.getData()
+
+ is_leaf = start_node.isLeaf()
+ if not is_leaf:
+ str_buff += "( "
+
+ for child_node in start_node.getChilds():
+ str_buff += "%s " % child_node.getData()
+ str_buff += self.getSExpression(child_node)
+
+ if not is_leaf:
+ str_buff += " )"
+ return str_buff
+
+ def getPreOrderExpression(self, start_node=None):
+ """ Return the pre order expression string of the Tree, used
+ to python *eval*.
+
+ :rtype: the expression string
+ """
+ if start_node is None:
+ start_node = self.getRoot()
+
+ str_buff = start_node.getData()
+
+ if not start_node.isLeaf():
+ all_childs = start_node.getChilds()
+ str_buff += "(" + self.getPreOrderExpression(all_childs[0])
+
+ for index in xrange(1, len(all_childs)):
+ child = all_childs[index]
+ str_buff += ", " + self.getPreOrderExpression(child)
+ str_buff += ")"
+
+ return str_buff
+
+ def getCompiledCode(self):
+ """ Get the compiled code for the Tree expression
+ After getting the compiled code object, you just need to evaluate it using
+ the :func:`eval` native Python method.
+
+ :rtype: compiled python code
+ """
+ expr = self.getPreOrderExpression()
+ return compile(expr, "<string>", "eval")
+
+ def copy(self, g):
+ """ Copy the contents to the destination g
+
+ :param g: the GTreeGP genome destination
+ """
+ GenomeBase.copy(self, g)
+ GTreeBase.copy(self, g)
+
+ def clone(self):
+ """ Return a new instance of the genome
+
+ :rtype: the new GTreeGP instance
+ """
+ newcopy = GTreeGP(cloning=True)
+ self.copy(newcopy)
+ newcopy.processNodes(True)
+ return newcopy
+
+ def compare(self, other):
+ """ This method will compare the currently tree with another one
+
+ :param other: the other GTreeGP to compare
+ """
+ if not isinstance(other, GTreeGP):
+ Util.raiseException("The other tree used to compare is not a GTreeGP class", TypeError)
+
+ stack_self = []
+ stack_other = []
+
+ tmp_self = None
+ tmp_other = None
+
+ stack_self.append(self.getRoot())
+ stack_other.append(other.getRoot())
+
+ while len(stack_self) > 0:
+
+ if (len(stack_self) <= 0) or (len(stack_other) <= 0):
+ return -1
+
+ tmp_self, tmp_other = stack_self.pop(), stack_other.pop()
+ if tmp_self.compare(tmp_other) <> 0:
+ return -1
+
+ stack_self.extend(tmp_self.getChilds())
+ stack_other.extend(tmp_other.getChilds())
+
+ return 0
+
+ @staticmethod
+ def writePopulationDot(ga_engine, filename, format="jpeg", start=0, end=0):
+ """ Writes to a graphical file using pydot, the population of trees
+
+ Example:
+ >>> GTreeGP.writePopulationDot(ga_engine, "pop.jpg", "jpeg", 0, 10)
+
+ This example will draw the first ten individuals of the population into
+ the file called "pop.jpg".
+
+ :param ga_engine: the GA Engine
+ :param filename: the filename, ie. population.jpg
+ :param start: the start index of individuals
+ :param end: the end index of individuals
+ """
+ if not HAVE_PYDOT:
+ Util.raiseException("You must install Pydot to use this feature !")
+
+ pop = ga_engine.getPopulation()
+ graph = pydot.Dot(graph_type="digraph")
+
+ if not isinstance(pop[0], GTreeGP):
+ Util.raiseException("The population must have individuals of the GTreeGP chromosome !")
+
+ n = 0
+ end_index = len(pop) if end==0 else end
+ for i in xrange(start, end_index):
+ ind = pop[i]
+ subg = pydot.Cluster("cluster_%d" % i, label="\"Ind. #%d - Score Raw/Fit.: %.4f/%.4f\"" % (i, ind.getRawScore(), ind.getFitnessScore()))
+ n = ind.writeDotGraph(subg, n)
+ graph.add_subgraph(subg)
+
+ graph.write(filename, prog='dot', format=format)
+
+ @staticmethod
+ def writePopulationDotRaw(ga_engine, filename, start=0, end=0):
+ """ Writes to a raw dot file using pydot, the population of trees
+
+ Example:
+ >>> GTreeGP.writePopulationDotRaw(ga_engine, "pop.dot", 0, 10)
+
+ This example will draw the first ten individuals of the population into
+ the file called "pop.dot".
+
+ :param ga_engine: the GA Engine
+ :param filename: the filename, ie. population.dot
+ :param start: the start index of individuals
+ :param end: the end index of individuals
+ """
+ if not HAVE_PYDOT:
+ Util.raiseException("You must install Pydot to use this feature !")
+
+ pop = ga_engine.getPopulation()
+ graph = pydot.Dot(graph_type="digraph")
+
+ if not isinstance(pop[0], GTreeGP):
+ Util.raiseException("The population must have individuals of the GTreeGP chromosome !")
+
+ n = 0
+ end_index = len(pop) if end==0 else end
+ for i in xrange(start, end_index):
+ ind = pop[i]
+ subg = pydot.Cluster("cluster_%d" % i, label="\"Ind. #%d - Score Raw/Fit.: %.4f/%.4f\"" % (i, ind.getRawScore(), ind.getFitnessScore()))
+ n = ind.writeDotGraph(subg, n)
+ graph.add_subgraph(subg)
+
+ graph.write(filename, prog='dot', format="raw")
+
+
+#################################
+# Tree GP Utility Functions #
+#################################
+
+def gpdec(**kwds):
+ """ This is a decorator to use with genetic programming non-terminals
+
+ It currently accepts the attributes: shape, color and representation.
+ """
+ def decorate(f):
+ for k in kwds:
+ setattr(f, k, kwds[k])
+ return f
+ return decorate
+
+def checkTerminal(terminal):
+ """ Do some check on the terminal, to evaluate ephemeral constants
+
+ :param terminal: the terminal string
+ """
+ if terminal.startswith("ephemeral:"):
+ splited = terminal.split(":")
+ ephemeral_constant = eval(splited[1])
+ return str(ephemeral_constant)
+ else:
+ return terminal
+
+def buildGTreeGPGrow(ga_engine, depth, max_depth):
+ """ Creates a new random GTreeGP root node with subtrees using
+ the "Grow" method.
+
+ :param ga_engine: the GA Core
+ :param depth: the initial depth
+ :max_depth: the maximum depth of the tree
+ :rtype: the root node
+ """
+
+ gp_terminals = ga_engine.getParam("gp_terminals")
+ assert gp_terminals is not None
+
+ gp_function_set = ga_engine.getParam("gp_function_set")
+ assert gp_function_set is not None
+
+ if depth == max_depth:
+ random_terminal = checkTerminal(random.choice(gp_terminals))
+ n = GTreeNodeGP(random_terminal, Consts.nodeType["TERMINAL"])
+ return n
+ else:
+ # Do not generate degenerative trees
+ if depth == 0:
+ random_node = random.choice(gp_function_set.keys())
+ else:
+ fchoice = random.choice([gp_function_set.keys(), gp_terminals])
+ random_node = random.choice(fchoice)
+
+ if random_node in gp_terminals:
+ n = GTreeNodeGP(checkTerminal(random_node), Consts.nodeType["TERMINAL"])
+ else:
+ n = GTreeNodeGP(random_node, Consts.nodeType["NONTERMINAL"])
+
+ if n.getType() == Consts.nodeType["NONTERMINAL"]:
+ for i in xrange(gp_function_set[n.getData()]):
+ child = buildGTreeGPGrow(ga_engine, depth+1, max_depth)
+ child.setParent(n)
+ n.addChild(child)
+
+ return n
+
+def buildGTreeGPFull(ga_engine, depth, max_depth):
+ """ Creates a new random GTreeGP root node with subtrees using
+ the "Full" method.
+
+ :param ga_engine: the GA Core
+ :param depth: the initial depth
+ :max_depth: the maximum depth of the tree
+ :rtype: the root node
+ """
+ gp_terminals = ga_engine.getParam("gp_terminals")
+ assert gp_terminals is not None
+
+ gp_function_set = ga_engine.getParam("gp_function_set")
+ assert gp_function_set is not None
+
+ if depth == max_depth:
+ random_terminal = checkTerminal(random.choice(gp_terminals))
+ n = GTreeNodeGP(random_terminal, Consts.nodeType["TERMINAL"])
+ return n
+ else:
+ random_oper = random.choice(gp_function_set.keys())
+ n = GTreeNodeGP(random_oper, Consts.nodeType["NONTERMINAL"])
+
+ if n.getType() == Consts.nodeType["NONTERMINAL"]:
+ for i in xrange(gp_function_set[n.getData()]):
+ child = buildGTreeGPFull(ga_engine, depth+1, max_depth)
+ child.setParent(n)
+ n.addChild(child)
+
+ return n
+
diff --git a/pyevolve/GenomeBase.py b/pyevolve/GenomeBase.py
new file mode 100644
index 0000000..088da7e
--- /dev/null
+++ b/pyevolve/GenomeBase.py
@@ -0,0 +1,633 @@
+"""
+
+:mod:`GenomeBase` -- the genomes base module
+================================================================
+
+This module have the class which every representation extends,
+if you are planning to create a new representation, you must
+take a inside look into this module.
+
+"""
+from random import choice as rand_choice
+import inspect
+
+from FunctionSlot import FunctionSlot
+import Util
+
+class GenomeBase:
+ """ GenomeBase Class - The base of all chromosome representation """
+
+ evaluator = None
+ """ This is the :term:`evaluation function` slot, you can add
+ a function with the *set* method: ::
+
+ genome.evaluator.set(eval_func)
+ """
+
+ initializator = None
+ """ This is the initialization function of the genome, you
+ can change the default initializator using the function slot: ::
+
+ genome.initializator.set(Initializators.G1DListInitializatorAllele)
+
+ In this example, the initializator :func:`Initializators.G1DListInitializatorAllele`
+ will be used to create the initial population.
+ """
+
+ mutator = None
+ """ This is the mutator function slot, you can change the default
+ mutator using the slot *set* function: ::
+
+ genome.mutator.set(Mutators.G1DListMutatorSwap)
+
+ """
+
+ crossover = None
+ """ This is the reproduction function slot, the crossover. You
+ can change the default crossover method using: ::
+
+ genome.crossover.set(Crossovers.G1DListCrossoverUniform)
+ """
+
+
+ def __init__(self):
+ """Genome Constructor"""
+ self.evaluator = FunctionSlot("Evaluator")
+ self.initializator = FunctionSlot("Initializator")
+ self.mutator = FunctionSlot("Mutator")
+ self.crossover = FunctionSlot("Crossover")
+
+ self.internalParams = {}
+ self.score = 0.0
+ self.fitness = 0.0
+
+ def getRawScore(self):
+ """ Get the Raw Score of the genome
+
+ :rtype: genome raw score
+
+ """
+ return self.score
+
+ def getFitnessScore(self):
+ """ Get the Fitness Score of the genome
+
+ :rtype: genome fitness score
+
+ """
+ return self.fitness
+
+ def __repr__(self):
+ """String representation of Genome"""
+ allSlots = self.allSlots = [ self.evaluator, self.initializator,
+ self.mutator, self.crossover ]
+
+ ret = "- GenomeBase\n"
+ ret+= "\tScore:\t\t\t %.6f\n" % (self.score,)
+ ret+= "\tFitness:\t\t %.6f\n\n" % (self.fitness,)
+ ret+= "\tParams:\t\t %s\n\n" % (self.internalParams,)
+
+ for slot in allSlots:
+ ret+= "\t" + slot.__repr__()
+ ret+="\n"
+
+ return ret
+
+ def setParams(self, **args):
+ """ Set the internal params
+
+ Example:
+ >>> genome.setParams(rangemin=0, rangemax=100, gauss_mu=0, gauss_sigma=1)
+
+ .. note:: All the individuals of the population shares this parameters and uses
+ the same instance of this dict.
+
+ :param args: this params will saved in every chromosome for genetic op. use
+
+ """
+ self.internalParams.update(args)
+
+ def getParam(self, key, nvl=None):
+ """ Gets an internal parameter
+
+ Example:
+ >>> genome.getParam("rangemax")
+ 100
+
+ .. note:: All the individuals of the population shares this parameters and uses
+ the same instance of this dict.
+
+ :param key: the key of param
+ :param nvl: if the key doesn't exist, the nvl will be returned
+
+ """
+ return self.internalParams.get(key, nvl)
+
+ def resetStats(self):
+ """ Clear score and fitness of genome """
+ self.score = 0.0
+ self.fitness = 0.0
+
+ def evaluate(self, **args):
+ """ Called to evaluate genome
+
+ :param args: this parameters will be passes to the evaluator
+
+ """
+ self.resetStats()
+ for it in self.evaluator.applyFunctions(self, **args):
+ self.score += it
+
+ def initialize(self, **args):
+ """ Called to initialize genome
+
+ :param args: this parameters will be passed to the initializator
+
+ """
+ for it in self.initializator.applyFunctions(self, **args):
+ pass
+
+ def mutate(self, **args):
+ """ Called to mutate the genome
+
+ :param args: this parameters will be passed to the mutator
+ :rtype: the number of mutations returned by mutation operator
+
+ """
+ nmuts = 0
+ for it in self.mutator.applyFunctions(self, **args):
+ nmuts+=it
+ return nmuts
+
+ def copy(self, g):
+ """ Copy the current GenomeBase to 'g'
+
+ :param g: the destination genome
+
+ .. note:: If you are planning to create a new chromosome representation, you
+ **must** implement this method on your class.
+
+ """
+ g.score = self.score
+ g.fitness = self.fitness
+ g.evaluator = self.evaluator
+ g.initializator = self.initializator
+ g.mutator = self.mutator
+ g.crossover = self.crossover
+ #g.internalParams = self.internalParams.copy()
+ g.internalParams = self.internalParams
+
+ def clone(self):
+ """ Clone this GenomeBase
+
+ :rtype: the clone genome
+
+ .. note:: If you are planning to create a new chromosome representation, you
+ **must** implement this method on your class.
+ """
+ newcopy = GenomeBase()
+ self.copy(newcopy)
+ return newcopy
+
+class G1DBase:
+ """ G1DBase Class - The base class for 1D chromosomes
+
+ :param size: the 1D list size
+
+ .. versionadded:: 0.6
+ Added te *G1DBase* class
+ """
+
+ def __init__(self, size):
+ self.genomeSize = size
+ self.genomeList = []
+
+ def __iadd__(self, item):
+ """ To add more items using the += operator """
+ self.genomeList.append(item)
+ return self
+
+ def __eq__(self, other):
+ """ Compares one chromosome with another """
+ cond1 = (self.genomeList == other.genomeList)
+ cond2 = (self.genomeSize == other.genomeSize)
+ return True if cond1 and cond2 else False
+
+ def __contains__(self, value):
+ """ Used on: *value in genome* """
+ return value in self.genomeList
+
+ def __getslice__(self, a, b):
+ """ Return the sliced part of chromosome """
+ return self.genomeList[a:b]
+
+ def __setslice__(self, a, b, val):
+ """ Sets the slice part of chromosome """
+ self.genomeList[a:b] = val
+
+ def __getitem__(self, key):
+ """ Return the specified gene of List """
+ return self.genomeList[key]
+
+ def __setitem__(self, key, value):
+ """ Set the specified value for an gene of List """
+ self.genomeList[key] = value
+
+ def __iter__(self):
+ """ Iterator support to the list """
+ return iter(self.genomeList)
+
+ def __len__(self):
+ """ Return the size of the List """
+ return len(self.genomeList)
+
+ def getListSize(self):
+ """ Returns the list supposed size
+
+ .. warning:: this is different from what the len(obj) returns
+ """
+ return self.genomeSize
+
+ def resumeString(self):
+ """ Returns a resumed string representation of the Genome """
+ return str(self.genomeList)
+
+ def append(self, value):
+ """ Appends an item to the end of the list
+
+ Example:
+ >>> genome.append(44)
+
+ :param value: value to be added
+
+ """
+ self.genomeList.append(value)
+
+ def remove(self, value):
+ """ Removes an item from the list
+
+ Example:
+ >>> genome.remove(44)
+
+ :param value: value to be added
+
+ """
+ self.genomeList.remove(value)
+
+ def clearList(self):
+ """ Remove all genes from Genome """
+ del self.genomeList[:]
+
+ def copy(self, g):
+ """ Copy genome to 'g'
+
+ Example:
+ >>> genome_origin.copy(genome_destination)
+
+ :param g: the destination instance
+
+ """
+ g.genomeSize = self.genomeSize
+ g.genomeList = self.genomeList[:]
+
+ def getInternalList(self):
+ """ Returns the internal list of the genome
+
+ ... note:: this method was created to solve performance issues
+ :rtype: the internal list
+ """
+ return self.genomeList
+
+ def setInternalList(self, lst):
+ """ Assigns a list to the internal list of the chromosome
+
+ :param lst: the list to assign the internal list of the chromosome
+ """
+ self.genomeList = lst
+
+class GTreeNodeBase:
+ """ GTreeNodeBase Class - The base class for the node tree genomes
+
+ :param parent: the parent node of the node
+ :param childs: the childs of the node, must be a list of nodes
+
+ .. versionadded:: 0.6
+ Added te *GTreeNodeBase* class
+ """
+
+ def __init__(self, parent, childs=None):
+ self.parent = parent
+ self.childs = []
+
+ if childs is not None:
+ if type(childs) != list:
+ Util.raiseException("Childs must be a list of nodes", TypeError)
+ typecheck_list = filter(lambda x: not isinstance(x, GTreeNodeBase), childs)
+ if len(typecheck_list) > 0:
+ Util.raiseException("Childs must be a list of nodes", TypeError)
+ self.childs += childs
+
+ def isLeaf(self):
+ """ Return True if the node is a leaf
+
+ :rtype: True or False
+ """
+ return len(self.childs)==0
+
+ def getChild(self, index):
+ """ Returns the index-child of the node
+
+ :rtype: child node
+ """
+ return self.childs[index]
+
+ def getChilds(self):
+ """ Return the childs of the node
+
+ .. warning :: use .getChilds()[:] if you'll change the list itself, like using childs.reverse(),
+ otherwise the original genome child order will be changed.
+
+ :rtype: a list of nodes
+ """
+ return self.childs
+
+ def addChild(self, child):
+ """ Adds a child to the node
+
+ :param child: the node to be added
+ """
+ if type(child) == list:
+ self.childs.extend(child)
+ else:
+ if not isinstance(child, GTreeNodeBase):
+ Util.raiseException("The child must be a node", TypeError)
+ self.childs.append(child)
+
+ def replaceChild(self, older, newer):
+ """ Replaces a child of the node
+
+ :param older: the child to be replaces
+ :param newer: the new child which replaces the older
+ """
+ index = self.childs.index(older)
+ self.childs[index] = newer
+
+ def setParent(self, parent):
+ """ Sets the parent of the node
+
+ :param parent: the parent node
+ """
+ #if not isinstance(parent, GTreeNodeBase):
+ # Util.raiseException("The parent must be a node", TypeError)
+ self.parent = parent
+
+ def getParent(self):
+ """ Get the parent node of the node
+
+ :rtype: the parent node
+ """
+ return self.parent
+
+ def __repr__(self):
+ parent = "None" if self.getParent() is None else "Present"
+ str_repr = "GTreeNodeBase [Childs=%d]" % len(self)
+ return str_repr
+
+ def __len__(self):
+ return len(self.childs)
+
+ def copy(self, g):
+ """ Copy the current contents GTreeNodeBase to 'g'
+
+ :param g: the destination node
+
+ .. note:: If you are planning to create a new chromosome representation, you
+ **must** implement this method on your class.
+ """
+ g.parent = self.parent
+ g.childs = self.childs[:]
+
+ def clone(self):
+ """ Clone this GenomeBase
+
+ :rtype: the clone genome
+
+ .. note:: If you are planning to create a new chromosome representation, you
+ **must** implement this method on your class.
+ """
+ newcopy = GTreeNodeBase(None)
+ self.copy(newcopy)
+ return newcopy
+
+
+class GTreeBase:
+ """ GTreeBase Class - The base class for the tree genomes
+
+ :param root_node: the root node of the tree
+
+ .. versionadded:: 0.6
+ Added te *GTreeBase* class
+ """
+
+ def __init__(self, root_node):
+ self.root_node = root_node
+ self.tree_height = None
+ self.nodes_list = None
+
+ def processNodes(self, cloning=False):
+ """ Creates a *cache* on the tree, this method must be called
+ every time you change the shape of the tree. It updates the
+ internal nodes list and the internal nodes properties such as
+ depth and height.
+ """
+ if self.root_node is None: return
+ self.nodes_list = self.getAllNodes()
+ self.nodes_leaf = filter(lambda n: n.isLeaf(), self.nodes_list)
+ self.nodes_branch = filter(lambda n: n.isLeaf()==False, self.nodes_list)
+
+ if not cloning:
+ self.tree_height = self.getNodeHeight(self.getRoot())
+
+ def getRoot(self):
+ """ Return the tree root node
+
+ :rtype: the tree root node
+ """
+ return self.root_node
+
+ def setRoot(self, root):
+ """ Sets the root of the tree
+
+ :param root: the tree root node
+ """
+ if not isinstance(root, GTreeNodeBase):
+ Util.raiseException("The root must be a node", TypeError)
+ self.root_node = root
+
+ def getNodeDepth(self, node):
+ """ Returns the depth of a node
+
+ :rtype: the depth of the node, the depth of root node is 0
+ """
+ if node==self.getRoot(): return 0
+ else: return 1 + self.getNodeDepth(node.getParent())
+
+ def getNodeHeight(self, node):
+ """ Returns the height of a node
+
+ .. note:: If the node has no childs, the height will be 0.
+
+ :rtype: the height of the node
+ """
+ height = 0
+ if len(node) <= 0:
+ return 0
+ for child in node.getChilds():
+ h_inner = self.getNodeHeight(child)+1
+ if h_inner > height:
+ height = h_inner
+ return height
+
+ def getHeight(self):
+ """ Return the tree height
+
+ :rtype: the tree height
+ """
+ return self.tree_height
+
+ def getNodesCount(self, start_node=None):
+ """ Return the number of the nodes on the tree
+ starting at the *start_node*, if *start_node* is None,
+ then the method will count all the tree nodes.
+
+ :rtype: the number of nodes
+ """
+ count = 1
+ if start_node is None:
+ start_node = self.getRoot()
+ for i in start_node.getChilds():
+ count += self.getNodesCount(i)
+ return count
+
+ def getTraversalString(self, start_node=None, spc=0):
+ """ Returns a tree-formated string of the tree. This
+ method is used by the __repr__ method of the tree
+
+ :rtype: a string representing the tree
+ """
+ str_buff = ""
+ if start_node is None:
+ start_node = self.getRoot()
+ str_buff += "%s\n" % start_node
+ spaces = spc + 2
+ for child_node in start_node.getChilds():
+ str_buff += "%s%s\n" % (" " * spaces, child_node)
+ str_buff += self.getTraversalString(child_node, spaces)
+ return str_buff
+
+
+ def traversal(self, callback, start_node=None):
+ """ Traversal the tree, this method will call the
+ user-defined callback function for each node on the tree
+
+ :param callback: a function
+ :param start_node: the start node to begin the traversal
+ """
+ if not inspect.isfunction(callback):
+ Util.raiseException("The callback for the tree traversal must be a function", TypeError)
+
+ if start_node is None:
+ start_node = self.getRoot()
+ callback(start_node)
+ for child_node in start_node.getChilds():
+ callback(child_node)
+ self.traversal(callback, child_node)
+
+ def getRandomNode(self, node_type=0):
+ """ Returns a random node from the Tree
+
+ :param node_type: 0 = Any, 1 = Leaf, 2 = Branch
+ :rtype: random node
+ """
+ lists = (self.nodes_list, self.nodes_leaf, self.nodes_branch)
+ cho = lists[node_type]
+ if len(cho) <= 0:
+ return None
+ return rand_choice(cho)
+
+ def getAllNodes(self):
+ """ Return a new list with all nodes
+
+ :rtype: the list with all nodes
+ """
+ node_stack = []
+ all_nodes = []
+ tmp = None
+
+ node_stack.append(self.getRoot())
+ while len(node_stack) > 0:
+ tmp = node_stack.pop()
+ all_nodes.append(tmp)
+ childs = tmp.getChilds()
+ node_stack.extend(childs)
+
+ return all_nodes
+
+ def __repr__(self):
+ str_buff = "- GTree\n"
+ str_buff += "\tHeight:\t\t\t%d\n" % self.getHeight()
+ str_buff += "\tNodes:\t\t\t%d\n" % self.getNodesCount()
+ str_buff += "\n" + self.getTraversalString()
+
+ return str_buff
+
+ def __len__(self):
+ return len(self.nodes_list)
+
+ def __getitem__(self, index):
+ return self.nodes_list[index]
+
+ def __iter__(self):
+ return iter(self.nodes_list)
+
+ def copy(self, g, node=None, node_parent=None):
+ """ Copy the current contents GTreeBase to 'g'
+
+ :param g: the destination GTreeBase tree
+
+ .. note:: If you are planning to create a new chromosome representation, you
+ **must** implement this method on your class.
+ """
+ if node is None:
+ g.tree_height = self.tree_height
+ node = self.root_node
+
+ if node is None: return None
+
+ newnode = node.clone()
+
+ if node_parent is None:
+ g.setRoot(newnode)
+ else:
+ newnode.setParent(node_parent)
+ node_parent.replaceChild(node, newnode)
+
+ for ci in xrange(len(newnode)):
+ GTreeBase.copy(self, g, newnode.getChild(ci), newnode)
+
+ return newnode
+
+ def clone(self):
+ """ Clone this GenomeBase
+
+ :rtype: the clone genome
+
+ .. note:: If you are planning to create a new chromosome representation, you
+ **must** implement this method on your class.
+ """
+ newcopy = GTreeBase(None)
+ self.copy(newcopy)
+ newcopy.processNodes()
+ return newcopy
+
+
diff --git a/pyevolve/Initializators.py b/pyevolve/Initializators.py
new file mode 100644
index 0000000..dd51548
--- /dev/null
+++ b/pyevolve/Initializators.py
@@ -0,0 +1,267 @@
+"""
+
+:mod:`Initializators` -- initialization methods module
+===================================================================
+
+In this module we have the genetic operators of initialization for each
+chromosome representation, the most part of initialization is done by
+choosing random data.
+
+.. note:: In Pyevolve, the Initializator defines the data type that will
+ be used on the chromosome, for example, the :func:`G1DListInitializatorInteger`
+ will initialize the G1DList with Integers.
+
+
+"""
+
+from random import randint as rand_randint, uniform as rand_uniform, choice as rand_choice
+import GTree
+import Util
+
+#############################
+## 1D Binary String ##
+#############################
+
+def G1DBinaryStringInitializator(genome, **args):
+ """ 1D Binary String initializator """
+ genome.genomeList = [ rand_choice((0,1)) for i in xrange(genome.getListSize()) ]
+
+#############################
+## 2D Binary String ##
+#############################
+
+def G2DBinaryStringInitializator(genome, **args):
+ """ Integer initialization function of 2D Binary String
+
+ .. versionadded:: 0.6
+ The *G2DBinaryStringInitializator* function
+ """
+ genome.clearString()
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ random_gene = rand_choice((0,1))
+ genome.setItem(i, j, random_gene)
+
+
+####################
+## 1D List ##
+####################
+
+def G1DListInitializatorAllele(genome, **args):
+ """ Allele initialization function of G1DList
+
+ To use this initializator, you must specify the *allele* genome parameter with the
+ :class:`GAllele.GAlleles` instance.
+
+ """
+
+ allele = genome.getParam("allele", None)
+ if allele is None:
+ Util.raiseException("to use the G1DListInitializatorAllele, you must specify the 'allele' parameter")
+
+ genome.genomeList = [ allele[i].getRandomAllele() for i in xrange(genome.getListSize()) ]
+
+def G1DListInitializatorInteger(genome, **args):
+ """ Integer initialization function of G1DList
+
+ This initializator accepts the *rangemin* and *rangemax* genome parameters.
+
+ """
+ range_min = genome.getParam("rangemin", 0)
+ range_max = genome.getParam("rangemax", 100)
+
+ genome.genomeList = [rand_randint(range_min, range_max) for i in xrange(genome.getListSize())]
+
+def G1DListInitializatorReal(genome, **args):
+ """ Real initialization function of G1DList
+
+ This initializator accepts the *rangemin* and *rangemax* genome parameters.
+
+ """
+ range_min = genome.getParam("rangemin", 0)
+ range_max = genome.getParam("rangemax", 100)
+
+ genome.genomeList = [rand_uniform(range_min, range_max) for i in xrange(genome.getListSize())]
+
+
+####################
+## 2D List ##
+####################
+
+def G2DListInitializatorInteger(genome, **args):
+ """ Integer initialization function of G2DList
+
+ This initializator accepts the *rangemin* and *rangemax* genome parameters.
+
+ """
+ genome.clearList()
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ randomInteger = rand_randint(genome.getParam("rangemin", 0),
+ genome.getParam("rangemax", 100))
+ genome.setItem(i, j, randomInteger)
+
+
+def G2DListInitializatorReal(genome, **args):
+ """ Integer initialization function of G2DList
+
+ This initializator accepts the *rangemin* and *rangemax* genome parameters.
+
+ """
+ genome.clearList()
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ randomReal = rand_uniform(genome.getParam("rangemin", 0),
+ genome.getParam("rangemax", 100))
+ genome.setItem(i, j, randomReal)
+
+def G2DListInitializatorAllele(genome, **args):
+ """ Allele initialization function of G2DList
+
+ To use this initializator, you must specify the *allele* genome parameter with the
+ :class:`GAllele.GAlleles` instance.
+
+ .. warning:: the :class:`GAllele.GAlleles` instance must have the homogeneous flag enabled
+
+ """
+
+ allele = genome.getParam("allele", None)
+ if allele is None:
+ Util.raiseException("to use the G2DListInitializatorAllele, you must specify the 'allele' parameter")
+
+ if allele.homogeneous == False:
+ Util.raiseException("to use the G2DListInitializatorAllele, the 'allele' must be homogeneous")
+
+ genome.clearList()
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ random_allele = allele[0].getRandomAllele()
+ genome.setItem(i, j, random_allele)
+
+####################
+## Tree ##
+####################
+
+def GTreeInitializatorInteger(genome, **args):
+ """ Integer initialization function of GTree
+
+ This initializator accepts the *rangemin* and *rangemax* genome parameters.
+ It accepts the following parameters too:
+
+ *max_depth*
+ The max depth of the tree
+
+ *max_siblings*
+ The number of maximum siblings of an node
+
+ *method*
+ The method, accepts "grow", "full" or "ramped".
+
+ .. versionadded:: 0.6
+ The *GTreeInitializatorInteger* function.
+ """
+ max_depth = genome.getParam("max_depth", 5)
+ max_siblings = genome.getParam("max_siblings", 2)
+
+ range_min = genome.getParam("rangemin", 0)
+ range_max = genome.getParam("rangemax", 100)
+
+ lambda_generator = lambda: rand_randint(range_min, range_max)
+
+ method = genome.getParam("method", "grow")
+
+ if method == "grow":
+ root = GTree.buildGTreeGrow(0, lambda_generator, max_siblings, max_depth)
+ elif method == "full":
+ root = GTree.buildGTreeFull(0, lambda_generator, max_siblings, max_depth)
+ elif method == "ramped":
+ if Util.randomFlipCoin(0.5):
+ root = GTree.buildGTreeGrow(0, lambda_generator, max_siblings, max_depth)
+ else:
+ root = GTree.buildGTreeFull(0, lambda_generator, max_siblings, max_depth)
+ else:
+ Util.raiseException("Unknown tree initialization method [%s] !" % method)
+
+ genome.setRoot(root)
+ genome.processNodes()
+ assert genome.getHeight() <= max_depth
+
+def GTreeInitializatorAllele(genome, **args):
+ """ Allele initialization function of GTree
+
+ To use this initializator, you must specify the *allele* genome parameter with the
+ :class:`GAllele.GAlleles` instance.
+
+ .. warning:: the :class:`GAllele.GAlleles` instance **must** have the homogeneous flag enabled
+
+ .. versionadded:: 0.6
+ The *GTreeInitializatorAllele* function.
+ """
+ max_depth = genome.getParam("max_depth", 5)
+ max_siblings = genome.getParam("max_siblings", 2)
+ method = genome.getParam("method", "grow")
+
+ allele = genome.getParam("allele", None)
+ if allele is None:
+ Util.raiseException("to use the GTreeInitializatorAllele, you must specify the 'allele' parameter")
+
+ if allele.homogeneous == False:
+ Util.raiseException("to use the GTreeInitializatorAllele, the 'allele' must be homogeneous")
+
+ if method == "grow":
+ root = GTree.buildGTreeGrow(0, allele[0].getRandomAllele, max_siblings, max_depth)
+ elif method == "full":
+ root = GTree.buildGTreeFull(0, allele[0].getRandomAllele, max_siblings, max_depth)
+ elif method == "ramped":
+ if Util.randomFlipCoin(0.5):
+ root = GTree.buildGTreeGrow(0, allele[0].getRandomAllele, max_siblings, max_depth)
+ else:
+ root = GTree.buildGTreeFull(0, allele[0].getRandomAllele, max_siblings, max_depth)
+ else:
+ Util.raiseException("Unknown tree initialization method [%s] !" % method)
+
+
+ genome.setRoot(root)
+ genome.processNodes()
+ assert genome.getHeight() <= max_depth
+
+####################
+## Tree GP ##
+####################
+
+def GTreeGPInitializator(genome, **args):
+ """This initializator accepts the follow parameters:
+
+ *max_depth*
+ The max depth of the tree
+
+ *method*
+ The method, accepts "grow", "full" or "ramped"
+
+ .. versionadded:: 0.6
+ The *GTreeGPInitializator* function.
+ """
+
+ max_depth = genome.getParam("max_depth", 5)
+ method = genome.getParam("method", "grow")
+ ga_engine = args["ga_engine"]
+
+ if method == "grow":
+ root = GTree.buildGTreeGPGrow(ga_engine, 0, max_depth)
+ elif method == "full":
+ root = GTree.buildGTreeGPFull(ga_engine, 0, max_depth)
+ elif method == "ramped":
+ if Util.randomFlipCoin(0.5):
+ root = GTree.buildGTreeGPFull(ga_engine, 0, max_depth)
+ else:
+ root = GTree.buildGTreeGPGrow(ga_engine, 0, max_depth)
+ else:
+ Util.raiseException("Unknown tree initialization method [%s] !" % method)
+
+ genome.setRoot(root)
+ genome.processNodes()
+ assert genome.getHeight() <= max_depth
diff --git a/pyevolve/Interaction.py b/pyevolve/Interaction.py
new file mode 100644
index 0000000..d08b5e4
--- /dev/null
+++ b/pyevolve/Interaction.py
@@ -0,0 +1,85 @@
+"""
+
+:mod:`Interaction` -- interaction module
+==========================================================================
+
+In this module, you will find the funcionality for the :term:`Interactive mode`.
+When you enter in the Interactive Mode, Pyevolve will automatic import this module
+and exposes to you in the name space called "it".
+
+To use this mode, the parameter *interactiveMode* must be enabled in the
+:class:`GSimpleGA.GSimpleGA`.
+
+You can use the manual method to enter in the Interactive Mode at specific
+generation using the :meth:`GSimpleGA.GSimpleGA.setInteractiveGeneration` method.
+
+"""
+import logging
+
+try:
+ import pylab
+except:
+ logging.debug("cannot import Matplotlib ! Plots will not be available !")
+ print "Warning: cannot import Matplotlib ! Plots will not be available !"
+
+try:
+ import numpy
+except:
+ logging.debug("cannot import Numpy ! Some functions will not be available !")
+ print "Warning: cannot import Numpy ! Some functions will not be available !"
+
+def getPopScores(population, fitness=False):
+ """ Returns a list of population scores
+
+ Example:
+ >>> lst = Interaction.getPopScores(population)
+
+ :param population: population object (:class:`GPopulation.GPopulation`)
+ :param fitness: if is True, the fitness score will be used, otherwise, the raw.
+ :rtype: list of population scores
+
+ """
+ score_list = []
+ for individual in population:
+ score_list.append(individual.fitness if fitness else individual.score)
+ return score_list
+
+def plotPopScore(population, fitness=False):
+ """ Plot the population score distribution
+
+ Example:
+ >>> Interaction.plotPopScore(population)
+
+ :param population: population object (:class:`GPopulation.GPopulation`)
+ :param fitness: if is True, the fitness score will be used, otherwise, the raw.
+ :rtype: None
+
+ """
+ score_list = getPopScores(population, fitness)
+ pylab.plot(score_list, 'o')
+ pylab.title("Plot of population score distribution")
+ pylab.xlabel('Individual')
+ pylab.ylabel('Score')
+ pylab.grid(True)
+ pylab.show()
+
+def plotHistPopScore(population, fitness=False):
+ """ Population score distribution histogram
+
+ Example:
+ >>> Interaction.plotHistPopScore(population)
+
+ :param population: population object (:class:`GPopulation.GPopulation`)
+ :param fitness: if is True, the fitness score will be used, otherwise, the raw.
+ :rtype: None
+
+ """
+ score_list = getPopScores(population, fitness)
+ n, bins, patches = pylab.hist(score_list, 50, facecolor='green', alpha=0.75, normed=1)
+ pylab.plot(bins, pylab.normpdf(bins, numpy.mean(score_list), numpy.std(score_list)), 'r--')
+ pylab.xlabel('Score')
+ pylab.ylabel('Frequency')
+ pylab.grid(True)
+ pylab.title("Plot of population score distribution")
+ pylab.show()
+
diff --git a/pyevolve/LICENSE.TXT b/pyevolve/LICENSE.TXT
new file mode 100644
index 0000000..e99e500
--- /dev/null
+++ b/pyevolve/LICENSE.TXT
@@ -0,0 +1,46 @@
+1. This LICENSE AGREEMENT is between Christian S. Perone ("CSP"), and the
+Individual or Organization ("Licensee") accessing and otherwise using
+Pyevolve software in source or binary form and its associated
+documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CSP
+hereby grants Licensee a nonexclusive, royalty-free, world-wide license
+to reproduce, analyze, test, perform and/or display publicly, prepare
+derivative works, distribute, and otherwise use Pyevolve 0.6
+alone or in any derivative version, provided, however, that CSP's
+License Agreement and CSP's notice of copyright, i.e., "Copyright (c)
+2007-2010 Christian S. Perone; All Rights Reserved" are retained in
+Pyevolve 0.6 alone or in any derivative version prepared by
+Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+incorporates Pyevolve 0.6 or any part thereof, and wants to
+make the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Pyevolve 0.6.
+
+4. CSP is making Pyevolve 0.6 available to Licensee on an "AS
+IS" basis. CSP MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CSP MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF Pyevolve 0.6
+WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CSP SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF Pyevolve
+0.6 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
+LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING
+Pyevolve 0.6, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF
+THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between CSP and
+Licensee. This License Agreement does not grant permission to use CSP
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Pyevolve 0.6,
+Licensee agrees to be bound by the terms and conditions of this License
+Agreement.
\ No newline at end of file
diff --git a/pyevolve/Migration.py b/pyevolve/Migration.py
new file mode 100644
index 0000000..8f2e8b2
--- /dev/null
+++ b/pyevolve/Migration.py
@@ -0,0 +1,268 @@
+"""
+:mod:`Migration` -- the migration schemes, distributed GA
+=====================================================================
+
+This module contains all the migration schemes and the distributed
+GA related functions.
+
+.. versionadded:: 0.6
+ The :mod:`Migration` module.
+
+"""
+
+import Util
+from random import randint as rand_randint, choice as rand_choice
+import Network
+import Consts
+from FunctionSlot import FunctionSlot
+import logging
+
+class MigrationScheme:
+ """ This is the base class for all migration schemes
+
+ :param host: the source hostname
+ :param port: the source host port
+ :param group_name: the group name
+ """
+
+ selector = None
+ """ This is the function slot for the selection method
+ if you want to change the default selector, you must do this: ::
+
+ migration_scheme.selector.set(Selectors.GRouletteWheel) """
+
+ def __init__(self, host, port, group_name):
+ self.myself = None
+ self.groupName = group_name
+ self.selector = FunctionSlot("Selector")
+ self.setMyself(host, port)
+ self.GAEngine = None
+ self.nMigrationRate = Consts.CDefGenMigrationRate
+ self.nIndividuals = Consts.CDefMigrationNIndividuals
+ self.nReplacement = Consts.CDefGenMigrationReplacement
+ self.networkCompression = 9
+
+ def isReady(self):
+ """ Returns true if is time to migrate """
+ return True if self.GAEngine.getCurrentGeneration() % self.nMigrationRate == 0 else False
+
+ def getCompressionLevel(self):
+ """ Get the zlib compression level of network data
+
+ The values are in the interval described on the :func:`Network.pickleAndCompress`
+ """
+ return self.networkCompression
+
+ def setCompressionLevel(self, level):
+ """ Set the zlib compression level of network data
+
+ The values are in the interval described on the :func:`Network.pickleAndCompress`
+
+ :param level: the zlib compression level
+ """
+ self.networkCompression = level
+
+ def getNumReplacement(self):
+ """ Return the number of individuals that will be
+ replaced in the migration process """
+ return self.nReplacement
+
+ def setNumReplacement(self, num_individuals):
+ """ Return the number of individuals that will be
+ replaced in the migration process
+
+ :param num_individuals: the number of individuals to be replaced
+ """
+ self.nReplacement = num_individuals
+
+ def getNumIndividuals(self):
+ """ Return the number of individuals that will migrate
+
+ :rtype: the number of individuals to be replaced
+ """
+ return self.nIndividuals
+
+ def setNumIndividuals(self, num_individuals):
+ """ Set the number of individuals that will migrate
+
+ :param num_individuals: the number of individuals
+ """
+ self.nIndividuals = num_individuals
+
+ def setMigrationRate(self, generations):
+ """ Sets the generation frequency supposed to migrate
+ and receive individuals.
+
+ :param generations: the number of generations
+ """
+ self.nMigrationRate = generations
+
+ def getMigrationRate(self):
+ """ Return the the generation frequency supposed to migrate
+ and receive individuals
+
+ :rtype: the number of generations
+ """
+ return self.nMigrationRate
+
+ def setGAEngine(self, ga_engine):
+ """ Sets the GA Engine handler """
+ self.GAEngine = ga_engine
+
+ def start(self):
+ """ Initializes the migration scheme """
+ pass
+
+ def stop(self):
+ """ Stops the migration engine """
+ pass
+
+ def getGroupName(self):
+ """ Gets the group name
+
+ .. note:: all islands of evolution which are supposed to exchange
+ individuals, must have the same group name.
+ """
+ return self.groupName
+
+ def setGroupName(self, name):
+ """ Sets the group name
+
+ :param name: the group name
+
+ .. note:: all islands of evolution which are supposed to exchange
+ individuals, must have the same group name.
+ """
+ self.groupName = name
+
+ def setMyself(self, host, port):
+ """ Which interface you will use to send/receive data
+
+ :param host: your hostname
+ :param port: your port
+ """
+ self.myself = (host, port)
+
+ def select(self):
+ """ Pickes an individual from population using specific selection method
+
+ :rtype: an individual object
+ """
+ if self.selector.isEmpty():
+ return self.GAEngine.select(popID=self.GAEngine.currentGeneration)
+ else:
+ for it in self.selector.applyFunctions(self.GAEngine.internalPop, popID=self.GAEngine.currentGeneration):
+ return it
+
+ def selectPool(self, num_individuals):
+ """ Select num_individuals number of individuals and return a pool
+
+ :param num_individuals: the number of individuals to select
+ :rtype: list with individuals
+ """
+ pool = [self.select() for i in xrange(num_individuals)]
+ return pool
+
+ def exchange(self):
+ """ Exchange individuals """
+ pass
+
+######################################################################################################
+
+class WANMigration(MigrationScheme):
+ """ This is the Simple Migration class for distributed GA
+
+ Example:
+ >>> mig = WANMigration("192.168.0.1", "10000", "group1")
+
+ :param host: the source hostname
+ :param port: the source port number
+ :param group_name: the group name
+ """
+
+ selector = None
+ """ This is the function slot for the selection method
+ if you want to change the default selector, you must do this: ::
+
+ migration_scheme.selector.set(Selectors.GRouletteWheel) """
+
+ def __init__(self, host, port, group_name):
+ MigrationScheme.__init__(self, host, port, group_name)
+ self.topologyGraph = None
+ self.serverThread = Network.UDPThreadServer(host, port)
+ self.clientThread = Network.UDPThreadUnicastClient(self.myself[0], rand_randint(30000, 65534))
+
+ def setTopology(self, graph):
+ """ Sets the topology of the migrations
+
+ :param graph: the :class:`Util.Graph` instance
+ """
+ self.topologyGraph = graph
+
+ def start(self):
+ """ Start capture of packets and initialize the migration scheme """
+ self.serverThread.start()
+
+ if self.topologyGraph is None:
+ Util.raiseException("You must add a topology graph to the migration scheme !")
+
+ # targets = [ (ip, port), (ip, port), ...]
+ targets = self.topologyGraph.getNeighbors(self.myself)
+ self.clientThread.setMultipleTargetHost(targets)
+ self.clientThread.start()
+
+ def stop(self):
+ """ Stops the migration engine """
+ self.serverThread.shutdown()
+ self.clientThread.shutdown()
+ server_timeout = self.serverThread.timeout
+ client_timeout = self.clientThread.timeout
+
+ self.serverThread.join(server_timeout+3)
+ self.clientThread.join(client_timeout+3)
+
+ if self.serverThread.isAlive():
+ logging.warning("warning: server thread not joined !")
+
+ if self.clientThread.isAlive():
+ logging.warning("warning: client thread not joined !")
+
+
+ def exchange(self):
+ """ This is the main method, is where the individuals
+ are exchanged """
+
+ if not self.isReady(): return
+
+ # Client section --------------------------------------
+ # How many will migrate ?
+ pool = self.selectPool(self.getNumIndividuals())
+
+ for individual in pool:
+ # (code, group name, individual)
+ networkObject = (Consts.CDefNetworkIndividual, self.getGroupName(), individual)
+ networkData = Network.pickleAndCompress(networkObject, self.getCompressionLevel())
+ # Send the individuals to the topology
+ self.clientThread.addData(networkData)
+
+ # Server section --------------------------------------
+ pool = []
+ while self.serverThread.isReady():
+ # (IP source, data)
+ networkData = self.serverThread.popPool()
+ networkObject = Network.unpickleAndDecompress(networkData[1])
+ # (code, group name, individual)
+ pool.append(networkObject)
+
+ # No individuals received
+ if len(pool) <= 0: return
+
+ population = self.GAEngine.getPopulation()
+
+ for i in xrange(self.getNumReplacement()):
+ if len(pool) <= 0: break
+ choice = rand_choice(pool)
+ pool.remove(choice)
+
+ # replace the worst
+ population[len(population)-1-i] = choice[2]
diff --git a/pyevolve/Mutators.py b/pyevolve/Mutators.py
new file mode 100644
index 0000000..c8f5fe4
--- /dev/null
+++ b/pyevolve/Mutators.py
@@ -0,0 +1,871 @@
+"""
+
+:mod:`Mutators` -- mutation methods module
+=====================================================================
+
+In this module we have the genetic operators of mutation for each chromosome representation.
+
+"""
+
+import Util
+from random import randint as rand_randint, gauss as rand_gauss, uniform as rand_uniform
+from random import choice as rand_choice
+import Consts
+import GTree
+
+#############################
+## 1D Binary String ##
+#############################
+
+def G1DBinaryStringMutatorSwap(genome, **args):
+ """ The 1D Binary String Swap Mutator """
+
+ if args["pmut"] <= 0.0: return 0
+ stringLength = len(genome)
+ mutations = args["pmut"] * (stringLength)
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(stringLength):
+ if Util.randomFlipCoin(args["pmut"]):
+ Util.listSwapElement(genome, it, rand_randint(0, stringLength-1))
+ mutations+=1
+
+ else:
+ for it in xrange(int(round(mutations))):
+ Util.listSwapElement(genome, rand_randint(0, stringLength-1),
+ rand_randint(0, stringLength-1))
+
+ return int(mutations)
+
+def G1DBinaryStringMutatorFlip(genome, **args):
+ """ The classical flip mutator for binary strings """
+ if args["pmut"] <= 0.0: return 0
+ stringLength = len(genome)
+ mutations = args["pmut"] * (stringLength)
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(stringLength):
+ if Util.randomFlipCoin(args["pmut"]):
+ if genome[it] == 0: genome[it] = 1
+ else: genome[it] = 0
+ mutations+=1
+
+ else:
+ for it in xrange(int(round(mutations))):
+ which = rand_randint(0, stringLength-1)
+ if genome[which] == 0: genome[which] = 1
+ else: genome[which] = 0
+
+ return int(mutations)
+
+####################
+## 1D List ##
+####################
+
+def G1DListMutatorSwap(genome, **args):
+ """ The mutator of G1DList, Swap Mutator
+
+ .. note:: this mutator is :term:`Data Type Independent`
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome) - 1
+ mutations = args["pmut"] * (listSize+1)
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize+1):
+ if Util.randomFlipCoin(args["pmut"]):
+ Util.listSwapElement(genome, it, rand_randint(0, listSize))
+ mutations+=1
+ else:
+ for it in xrange(int(round(mutations))):
+ Util.listSwapElement(genome, rand_randint(0, listSize), rand_randint(0, listSize))
+
+ return int(mutations)
+
+def G1DListMutatorSIM(genome, **args):
+ """ The mutator of G1DList, Simple Inversion Mutation
+
+ .. note:: this mutator is :term:`Data Type Independent`
+
+ """
+ mutations = 0
+ if args["pmut"] <= 0.0: return 0
+
+ cuts = [rand_randint(0, len(genome)), rand_randint(0, len(genome))]
+
+ if cuts[0] > cuts[1]:
+ Util.listSwapElement(cuts, 0, 1)
+
+ if (cuts[1]-cuts[0]) <= 0:
+ cuts[1] = rand_randint(cuts[0], len(genome))
+
+ if Util.randomFlipCoin(args["pmut"]):
+ part = genome[cuts[0]:cuts[1]]
+ if len(part) == 0: return 0
+ part.reverse()
+ genome[cuts[0]:cuts[1]] = part
+ mutations += 1
+
+ return mutations
+
+def G1DListMutatorIntegerRange(genome, **args):
+ """ Simple integer range mutator for G1DList
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome)
+ mutations = args["pmut"] * listSize
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize):
+ if Util.randomFlipCoin(args["pmut"]):
+ genome[it] = rand_randint(genome.getParam("rangemin", Consts.CDefRangeMin),
+ genome.getParam("rangemax", Consts.CDefRangeMax))
+ mutations += 1
+
+ else:
+ for it in xrange(int(round(mutations))):
+ which_gene = rand_randint(0, listSize-1)
+ genome[which_gene] = rand_randint(genome.getParam("rangemin", Consts.CDefRangeMin),
+ genome.getParam("rangemax", Consts.CDefRangeMax))
+
+ return int(mutations)
+
+
+def G1DListMutatorRealRange(genome, **args):
+ """ Simple real range mutator for G1DList
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome)
+ mutations = args["pmut"] * (listSize)
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize):
+ if Util.randomFlipCoin(args["pmut"]):
+ genome[it] = rand_uniform(genome.getParam("rangemin", Consts.CDefRangeMin),
+ genome.getParam("rangemax", Consts.CDefRangeMax))
+ mutations += 1
+
+ else:
+ for it in xrange(int(round(mutations))):
+ which_gene = rand_randint(0, listSize-1)
+ genome[which_gene] = rand_uniform(genome.getParam("rangemin", Consts.CDefRangeMin),
+ genome.getParam("rangemax", Consts.CDefRangeMax))
+
+ return int(mutations)
+
+def G1DListMutatorIntegerGaussian(genome, **args):
+ """ A gaussian mutator for G1DList of Integers
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also
+ accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively
+ represents the mean and the std. dev. of the random distribution.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome)
+ mutations = args["pmut"] * (listSize)
+
+ mu = genome.getParam("gauss_mu")
+ sigma = genome.getParam("gauss_sigma")
+
+ if mu is None:
+ mu = Consts.CDefG1DListMutIntMU
+
+ if sigma is None:
+ sigma = Consts.CDefG1DListMutIntSIGMA
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize):
+ if Util.randomFlipCoin(args["pmut"]):
+ final_value = genome[it] + int(rand_gauss(mu, sigma))
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome[it] = final_value
+ mutations += 1
+ else:
+ for it in xrange(int(round(mutations))):
+ which_gene = rand_randint(0, listSize-1)
+ final_value = genome[which_gene] + int(rand_gauss(mu, sigma))
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome[which_gene] = final_value
+
+ return int(mutations)
+
+
+def G1DListMutatorRealGaussian(genome, **args):
+ """ The mutator of G1DList, Gaussian Mutator
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also
+ accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively
+ represents the mean and the std. dev. of the random distribution.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome)
+ mutations = args["pmut"] * (listSize)
+
+ mu = genome.getParam("gauss_mu")
+ sigma = genome.getParam("gauss_sigma")
+
+ if mu is None:
+ mu = Consts.CDefG1DListMutRealMU
+
+ if sigma is None:
+ sigma = Consts.CDefG1DListMutRealSIGMA
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize):
+ if Util.randomFlipCoin(args["pmut"]):
+ final_value = genome[it] + rand_gauss(mu, sigma)
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome[it] = final_value
+ mutations += 1
+ else:
+ for it in xrange(int(round(mutations))):
+ which_gene = rand_randint(0, listSize-1)
+ final_value = genome[which_gene] + rand_gauss(mu, sigma)
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome[which_gene] = final_value
+
+ return int(mutations)
+
+def G1DListMutatorIntegerBinary(genome, **args):
+ """ The mutator of G1DList, the binary mutator
+
+ This mutator will random change the 0 and 1 elements of the 1D List.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome)
+ mutations = args["pmut"] * (listSize)
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize):
+ if Util.randomFlipCoin(args["pmut"]):
+ if genome[it] == 0: genome[it] = 1
+ elif genome[it] == 1: genome[it] = 0
+
+ mutations += 1
+ else:
+ for it in xrange(int(round(mutations))):
+ which_gene = rand_randint(0, listSize-1)
+ if genome[which_gene] == 0: genome[which_gene] = 1
+ elif genome[which_gene] == 1: genome[which_gene] = 0
+
+ return int(mutations)
+
+def G1DListMutatorAllele(genome, **args):
+ """ The mutator of G1DList, Allele Mutator
+
+ To use this mutator, you must specify the *allele* genome parameter with the
+ :class:`GAllele.GAlleles` instance.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome) - 1
+ mutations = args["pmut"] * (listSize+1)
+
+ allele = genome.getParam("allele", None)
+ if allele is None:
+ Util.raiseException("to use the G1DListMutatorAllele, you must specify the 'allele' parameter", TypeError)
+
+ if mutations < 1.0:
+ mutations = 0
+ for it in xrange(listSize+1):
+ if Util.randomFlipCoin(args["pmut"]):
+ new_val = allele[it].getRandomAllele()
+ genome[it] = new_val
+ mutations+=1
+ else:
+ for it in xrange(int(round(mutations))):
+ which_gene = rand_randint(0, listSize)
+ new_val = allele[which_gene].getRandomAllele()
+ genome[which_gene] = new_val
+
+ return int(mutations)
+
+####################
+## 2D List ##
+####################
+
+def G2DListMutatorSwap(genome, **args):
+ """ The mutator of G1DList, Swap Mutator
+
+ .. note:: this mutator is :term:`Data Type Independent`
+
+ """
+
+ if args["pmut"] <= 0.0: return 0
+ height, width = genome.getSize()
+ elements = height * width
+
+ mutations = args["pmut"] * elements
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(height):
+ for j in xrange(width):
+ if Util.randomFlipCoin(args["pmut"]):
+ index_b = (rand_randint(0, height-1), rand_randint(0, width-1))
+ Util.list2DSwapElement(genome.genomeList, (i,j), index_b)
+ mutations+=1
+ else:
+ for it in xrange(int(round(mutations))):
+ index_a = (rand_randint(0, height-1), rand_randint(0, width-1))
+ index_b = (rand_randint(0, height-1), rand_randint(0, width-1))
+ Util.list2DSwapElement(genome.genomeList, index_a, index_b)
+
+ return int(mutations)
+
+def G2DListMutatorIntegerRange(genome, **args):
+ """ Simple integer range mutator for G2DList
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ height, width = genome.getSize()
+ elements = height * width
+
+ mutations = args["pmut"] * elements
+
+ range_min = genome.getParam("rangemin", Consts.CDefRangeMin)
+ range_max = genome.getParam("rangemax", Consts.CDefRangeMax)
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ if Util.randomFlipCoin(args["pmut"]):
+ random_int = rand_randint(range_min, range_max)
+ genome.setItem(i, j, random_int)
+ mutations += 1
+
+ else:
+ for it in xrange(int(round(mutations))):
+ which_x = rand_randint(0, genome.getWidth()-1)
+ which_y = rand_randint(0, genome.getHeight()-1)
+ random_int = rand_randint(range_min, range_max)
+ genome.setItem(which_y, which_x, random_int)
+
+ return int(mutations)
+
+
+def G2DListMutatorIntegerGaussian(genome, **args):
+ """ A gaussian mutator for G2DList of Integers
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also
+ accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively
+ represents the mean and the std. dev. of the random distribution.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ height, width = genome.getSize()
+ elements = height * width
+
+ mutations = args["pmut"] * elements
+
+ mu = genome.getParam("gauss_mu")
+ sigma = genome.getParam("gauss_sigma")
+
+ if mu is None:
+ mu = Consts.CDefG2DListMutIntMU
+
+ if sigma is None:
+ sigma = Consts.CDefG2DListMutIntSIGMA
+
+ if mutations < 1.0:
+ mutations = 0
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ if Util.randomFlipCoin(args["pmut"]):
+ final_value = genome[i][j] + int(rand_gauss(mu, sigma))
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome.setItem(i, j, final_value)
+ mutations += 1
+ else:
+
+ for it in xrange(int(round(mutations))):
+ which_x = rand_randint(0, genome.getWidth()-1)
+ which_y = rand_randint(0, genome.getHeight()-1)
+
+ final_value = genome[which_y][which_x] + int(rand_gauss(mu, sigma))
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome.setItem(which_y, which_x, final_value)
+
+ return int(mutations)
+
+
+def G2DListMutatorAllele(genome, **args):
+ """ The mutator of G2DList, Allele Mutator
+
+ To use this mutator, you must specify the *allele* genome parameter with the
+ :class:`GAllele.GAlleles` instance.
+
+ .. warning:: the :class:`GAllele.GAlleles` instance must have the homogeneous flag enabled
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ listSize = len(genome) - 1
+ mutations = args["pmut"] * (listSize+1)
+
+ allele = genome.getParam("allele", None)
+ if allele is None:
+ Util.raiseException("to use the G2DListMutatorAllele, you must specify the 'allele' parameter", TypeError)
+
+ if allele.homogeneous == False:
+ Util.raiseException("to use the G2DListMutatorAllele, the 'allele' must be homogeneous")
+
+ if mutations < 1.0:
+ mutations = 0
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidht()):
+ if Util.randomFlipCoin(args["pmut"]):
+ new_val = allele[0].getRandomAllele()
+ genome.setItem(i, j, new_val)
+ mutations+=1
+ else:
+ for it in xrange(int(round(mutations))):
+ which_x = rand_randint(0, genome.getWidth()-1)
+ which_y = rand_randint(0, genome.getHeight()-1)
+
+ new_val = allele[0].getRandomAllele()
+ genome.setItem(which_x, which_y, new_val)
+
+ return int(mutations)
+
+
+def G2DListMutatorRealGaussian(genome, **args):
+ """ A gaussian mutator for G2DList of Real
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also
+ accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively
+ represents the mean and the std. dev. of the random distribution.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ height, width = genome.getSize()
+ elements = height * width
+
+ mutations = args["pmut"] * elements
+
+ mu = genome.getParam("gauss_mu")
+ sigma = genome.getParam("gauss_sigma")
+
+ if mu is None:
+ mu = Consts.CDefG2DListMutRealMU
+
+ if sigma is None:
+ sigma = Consts.CDefG2DListMutRealSIGMA
+
+ if mutations < 1.0:
+ mutations = 0
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ if Util.randomFlipCoin(args["pmut"]):
+ final_value = genome[i][j] + rand_gauss(mu, sigma)
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome.setItem(i, j, final_value)
+ mutations += 1
+ else:
+
+ for it in xrange(int(round(mutations))):
+ which_x = rand_randint(0, genome.getWidth()-1)
+ which_y = rand_randint(0, genome.getHeight()-1)
+
+ final_value = genome[which_y][which_x] + rand_gauss(mu, sigma)
+
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+
+ genome.setItem(which_y, which_x, final_value)
+
+ return int(mutations)
+
+
+#############################
+## 2D Binary String ##
+#############################
+
+def G2DBinaryStringMutatorSwap(genome, **args):
+ """ The mutator of G2DBinaryString, Swap Mutator
+
+ .. versionadded:: 0.6
+ The *G2DBinaryStringMutatorSwap* function
+ """
+
+ if args["pmut"] <= 0.0: return 0
+ height, width = genome.getSize()
+ elements = height * width
+
+ mutations = args["pmut"] * elements
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(height):
+ for j in xrange(width):
+ if Util.randomFlipCoin(args["pmut"]):
+ index_b = (rand_randint(0, height-1), rand_randint(0, width-1))
+ Util.list2DSwapElement(genome.genomeString, (i,j), index_b)
+ mutations+=1
+ else:
+ for it in xrange(int(round(mutations))):
+ index_a = (rand_randint(0, height-1), rand_randint(0, width-1))
+ index_b = (rand_randint(0, height-1), rand_randint(0, width-1))
+ Util.list2DSwapElement(genome.genomeString, index_a, index_b)
+
+ return int(mutations)
+
+
+def G2DBinaryStringMutatorFlip(genome, **args):
+ """ A flip mutator for G2DBinaryString
+
+ .. versionadded:: 0.6
+ The *G2DBinaryStringMutatorFlip* function
+ """
+ if args["pmut"] <= 0.0: return 0
+ height, width = genome.getSize()
+ elements = height * width
+
+ mutations = args["pmut"] * elements
+
+ if mutations < 1.0:
+ mutations = 0
+
+ for i in xrange(genome.getHeight()):
+ for j in xrange(genome.getWidth()):
+ if Util.randomFlipCoin(args["pmut"]):
+ if genome[i][j] == 0: genome.setItem(i, j, 1)
+ else: genome.setItem(i, j, 0)
+ mutations += 1
+ else:
+
+ for it in xrange(int(round(mutations))):
+ which_x = rand_randint(0, genome.getWidth()-1)
+ which_y = rand_randint(0, genome.getHeight()-1)
+
+ if genome[i][j] == 0: genome.setItem(which_y, which_x, 1)
+ else: genome.setItem(which_y, which_x, 0)
+
+ return int(mutations)
+
+#################
+## Tree ##
+#################
+def GTreeMutatorSwap(genome, **args):
+ """ The mutator of GTree, Swap Mutator
+
+ .. versionadded:: 0.6
+ The *GTreeMutatorSwap* function
+ """
+ if args["pmut"] <= 0.0: return 0
+ elements = len(genome)
+ mutations = args["pmut"] * elements
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(len(genome)):
+ if Util.randomFlipCoin(args["pmut"]):
+ mutations += 1
+ nodeOne = genome.getRandomNode()
+ nodeTwo = genome.getRandomNode()
+ nodeOne.swapNodeData(nodeTwo)
+ else:
+ for it in xrange(int(round(mutations))):
+ nodeOne = genome.getRandomNode()
+ nodeTwo = genome.getRandomNode()
+ nodeOne.swapNodeData(nodeTwo)
+
+ return int(mutations)
+
+
+def GTreeMutatorIntegerRange(genome, **args):
+ """ The mutator of GTree, Integer Range Mutator
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional.
+
+ .. versionadded:: 0.6
+ The *GTreeMutatorIntegerRange* function
+ """
+ if args["pmut"] <= 0.0: return 0
+ elements = len(genome)
+ mutations = args["pmut"] * elements
+
+ range_min = genome.getParam("rangemin", Consts.CDefRangeMin)
+ range_max = genome.getParam("rangemax", Consts.CDefRangeMax)
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(len(genome)):
+ if Util.randomFlipCoin(args["pmut"]):
+ mutations += 1
+ rand_node = genome.getRandomNode()
+ random_int = rand_randint(range_min, range_max)
+ rand_node.setData(random_int)
+
+ else:
+ for it in xrange(int(round(mutations))):
+ rand_node = genome.getRandomNode()
+ random_int = rand_randint(range_min, range_max)
+ rand_node.setData(random_int)
+
+ return int(mutations)
+
+
+def GTreeMutatorRealRange(genome, **args):
+ """ The mutator of GTree, Real Range Mutator
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional.
+
+ .. versionadded:: 0.6
+ The *GTreeMutatorRealRange* function
+ """
+ if args["pmut"] <= 0.0: return 0
+ elements = len(genome)
+ mutations = args["pmut"] * elements
+
+ range_min = genome.getParam("rangemin", Consts.CDefRangeMin)
+ range_max = genome.getParam("rangemax", Consts.CDefRangeMax)
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(len(genome)):
+ if Util.randomFlipCoin(args["pmut"]):
+ mutations += 1
+ rand_node = genome.getRandomNode()
+ random_real = rand_uniform(range_min, range_max)
+ rand_node.setData(random_real)
+
+ else:
+ for it in xrange(int(round(mutations))):
+ rand_node = genome.getRandomNode()
+ random_real = rand_uniform(range_min, range_max)
+ rand_node.setData(random_real)
+
+ return int(mutations)
+
+
+def GTreeMutatorIntegerGaussian(genome, **args):
+ """ A gaussian mutator for GTree of Integers
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also
+ accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively
+ represents the mean and the std. dev. of the random distribution.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ elements = len(genome)
+ mutations = args["pmut"] * elements
+
+ mu = genome.getParam("gauss_mu", Consts.CDefG1DListMutIntMU)
+ sigma = genome.getParam("gauss_sigma", Consts.CDefG1DListMutIntSIGMA)
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(len(genome)):
+ if Util.randomFlipCoin(args["pmut"]):
+ mutations += 1
+ rand_node = genome.getRandomNode()
+ final_value = rand_node.getData() + int(rand_gauss(mu, sigma))
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+ rand_node.setData(final_value)
+ else:
+ for it in xrange(int(round(mutations))):
+ rand_node = genome.getRandomNode()
+ final_value = rand_node.getData() + int(rand_gauss(mu, sigma))
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+ rand_node.setData(final_value)
+
+ return int(mutations)
+
+
+def GTreeMutatorRealGaussian(genome, **args):
+ """ A gaussian mutator for GTree of Real numbers
+
+ Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also
+ accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively
+ represents the mean and the std. dev. of the random distribution.
+
+ """
+ if args["pmut"] <= 0.0: return 0
+ elements = len(genome)
+ mutations = args["pmut"] * elements
+
+ mu = genome.getParam("gauss_mu", Consts.CDefG1DListMutRealMU)
+ sigma = genome.getParam("gauss_sigma", Consts.CDefG1DListMutRealSIGMA)
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(len(genome)):
+ if Util.randomFlipCoin(args["pmut"]):
+ mutations += 1
+ rand_node = genome.getRandomNode()
+ final_value = rand_node.getData() + rand_gauss(mu, sigma)
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+ rand_node.setData(final_value)
+ else:
+ for it in xrange(int(round(mutations))):
+ rand_node = genome.getRandomNode()
+ final_value = rand_node.getData() + rand_gauss(mu, sigma)
+ final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+ final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+ rand_node.setData(final_value)
+
+ return int(mutations)
+
+
+
+###################
+## Tree GP ##
+###################
+
+def GTreeGPMutatorOperation(genome, **args):
+ """ The mutator of GTreeGP, Operation Mutator
+
+ .. versionadded:: 0.6
+ The *GTreeGPMutatorOperation* function
+ """
+
+ if args["pmut"] <= 0.0: return 0
+ elements = len(genome)
+ mutations = args["pmut"] * elements
+ ga_engine = args["ga_engine"]
+
+
+ gp_terminals = ga_engine.getParam("gp_terminals")
+ assert gp_terminals is not None
+
+ gp_function_set = ga_engine.getParam("gp_function_set")
+ assert gp_function_set is not None
+
+ if mutations < 1.0:
+ mutations = 0
+ for i in xrange(len(genome)):
+ if Util.randomFlipCoin(args["pmut"]):
+ mutations += 1
+ rand_node = genome.getRandomNode()
+ assert rand_node is not None
+ if rand_node.getType() == Consts.nodeType["TERMINAL"]:
+ term_operator = rand_choice(gp_terminals)
+ else:
+ op_len = gp_function_set[rand_node.getData()]
+ fun_candidates = []
+ for o, l in gp_function_set.items():
+ if l==op_len:
+ fun_candidates.append(o)
+
+ if len(fun_candidates) <= 0:
+ continue
+
+ term_operator = rand_choice(fun_candidates)
+ rand_node.setData(term_operator)
+ else:
+ for it in xrange(int(round(mutations))):
+ rand_node = genome.getRandomNode()
+ assert rand_node is not None
+ if rand_node.getType() == Consts.nodeType["TERMINAL"]:
+ term_operator = rand_choice(gp_terminals)
+ else:
+ op_len = gp_function_set[rand_node.getData()]
+ fun_candidates = []
+ for o, l in gp_function_set.items():
+ if l==op_len:
+ fun_candidates.append(o)
+
+ if len(fun_candidates) <= 0:
+ continue
+
+ term_operator = rand_choice(fun_candidates)
+ rand_node.setData(term_operator)
+
+ return int(mutations)
+
+
+def GTreeGPMutatorSubtree(genome, **args):
+ """ The mutator of GTreeGP, Subtree Mutator
+
+ This mutator will recreate random subtree of the tree using the grow algorithm.
+
+ .. versionadded:: 0.6
+ The *GTreeGPMutatorSubtree* function
+ """
+
+ if args["pmut"] <= 0.0: return 0
+ ga_engine = args["ga_engine"]
+ max_depth = genome.getParam("max_depth", None)
+ mutations = 0
+
+ if max_depth is None:
+ Util.raiseException("You must specify the max_depth genome parameter !", ValueError)
+
+ if max_depth < 0:
+ Util.raiseException("The max_depth must be >= 1, if you want to use GTreeGPMutatorSubtree crossover !", ValueError)
+
+ branch_list = genome.nodes_branch
+ elements = len(branch_list)
+
+ for i in xrange(elements):
+
+ node = branch_list[i]
+ assert node is not None
+
+ if Util.randomFlipCoin(args["pmut"]):
+ depth = genome.getNodeDepth(node)
+ mutations += 1
+
+ root_subtree = GTree.buildGTreeGPGrow(ga_engine, 0, max_depth-depth)
+ node_parent = node.getParent()
+
+ if node_parent is None:
+ genome.setRoot(root_subtree)
+ genome.processNodes()
+ return mutations
+ else:
+ root_subtree.setParent(node_parent)
+ node_parent.replaceChild(node, root_subtree)
+ genome.processNodes()
+
+ return int(mutations)
+
+
diff --git a/pyevolve/Network.py b/pyevolve/Network.py
new file mode 100644
index 0000000..f885bd7
--- /dev/null
+++ b/pyevolve/Network.py
@@ -0,0 +1,446 @@
+"""
+
+:mod:`Network` -- network utility module
+============================================================================
+
+In this module you'll find all the network related implementation
+
+.. versionadded:: 0.6
+ The *Network* module.
+
+"""
+from __future__ import with_statement
+import threading
+import socket
+import time
+import sys
+import Util
+import cPickle
+
+try:
+ import zlib
+ ZLIB_SUPPORT = True
+except ImportError:
+ ZLIB_SUPPORT = False
+
+import Consts
+import logging
+
+def getMachineIP():
+ """ Return all the IPs from current machine.
+
+ Example:
+ >>> Util.getMachineIP()
+ ['200.12.124.181', '192.168.0.1']
+
+ :rtype: a python list with the string IPs
+
+ """
+ hostname = socket.gethostname()
+ addresses = socket.getaddrinfo(hostname, None)
+ ips = [x[4][0] for x in addresses]
+ return ips
+
+class UDPThreadBroadcastClient(threading.Thread):
+ """ The Broadcast UDP client thread class.
+
+ This class is a thread to serve as Pyevolve client on the UDP
+ datagrams, it is used to send data over network lan/wan.
+
+ Example:
+ >>> s = Network.UDPThreadClient('192.168.0.2', 1500, 666)
+ >>> s.setData("Test data")
+ >>> s.start()
+ >>> s.join()
+
+ :param host: the hostname to bind the socket on sender (this is NOT the target host)
+ :param port: the sender port (this is NOT the target port)
+ :param target_port: the destination port target
+
+ """
+ def __init__(self, host, port, target_port):
+ threading.Thread.__init__(self)
+ self.host = host
+ self.port = port
+ self.targetPort = target_port
+ self.data = None
+ self.sentBytes = None
+ self.sentBytesLock = threading.Lock()
+
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
+ self.sock.bind((host, port))
+
+ def setData(self, data):
+ """ Set the data to send
+
+ :param data: the data to send
+
+ """
+ self.data = data
+
+ def getData(self):
+ """ Get the data to send
+
+ :rtype: data to send
+
+ """
+ return self.data
+
+ def close(self):
+ """ Close the internal socket """
+ self.sock.close()
+
+ def getSentBytes(self):
+ """ Returns the number of sent bytes. The use of this method makes sense
+ when you already have sent the data
+
+ :rtype: sent bytes
+
+ """
+ sent = None
+ with self.sentBytesLock:
+ if self.sentBytes is None:
+ Util.raiseException('Bytes sent is None')
+ else: sent = self.sentBytes
+ return sent
+
+ def send(self):
+ """ Broadcasts the data """
+ return self.sock.sendto(self.data, (Consts.CDefBroadcastAddress, self.targetPort))
+
+ def run(self):
+ """ Method called when you call *.start()* of the thread """
+ if self.data is None:
+ Util.raiseException('You must set the data with setData method', ValueError)
+
+ with self.sentBytesLock:
+ self.sentBytes = self.send()
+ self.close()
+
+class UDPThreadUnicastClient(threading.Thread):
+ """ The Unicast UDP client thread class.
+
+ This class is a thread to serve as Pyevolve client on the UDP
+ datagrams, it is used to send data over network lan/wan.
+
+ Example:
+ >>> s = Network.UDPThreadClient('192.168.0.2', 1500)
+ >>> s.setData("Test data")
+ >>> s.setTargetHost('192.168.0.50', 666)
+ >>> s.start()
+ >>> s.join()
+
+ :param host: the hostname to bind the socket on sender (this is not the target host)
+ :param port: the sender port (this is not the target port)
+ :param pool_size: the size of send pool
+ :param timeout: the time interval to check if the client have data to send
+
+ """
+ def __init__(self, host, port, pool_size=10, timeout=0.5):
+ threading.Thread.__init__(self)
+ self.host = host
+ self.port = port
+ self.target = []
+ self.sendPool = []
+ self.poolSize = pool_size
+ self.sendPoolLock = threading.Lock()
+ self.timeout = timeout
+
+ self.doshutdown = False
+
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.sock.bind((host, port))
+
+ def poolLength(self):
+ """ Returns the size of the pool
+
+ :rtype: integer
+
+ """
+ with self.sendPoolLock:
+ ret = len(self.sendPool)
+ return ret
+
+ def popPool(self):
+ """ Return the last data received on the pool
+
+ :rtype: object
+
+ """
+ with self.sendPoolLock:
+ ret = self.sendPool.pop()
+ return ret
+
+ def isReady(self):
+ """ Returns True when there is data on the pool or False when not
+
+ :rtype: boolean
+
+ """
+ with self.sendPoolLock:
+ ret = True if len(self.sendPool) >= 1 else False
+ return ret
+
+ def shutdown(self):
+ """ Shutdown the server thread, when called, this method will stop
+ the thread on the next socket timeout """
+ self.doshutdown = True
+
+ def addData(self, data):
+ """ Set the data to send
+
+ :param data: the data to send
+
+ """
+ if self.poolLength() >= self.poolSize:
+ logging.warning('the send pool is full, consider increasing the pool size or decreasing the timeout !')
+ return
+
+ with self.sendPoolLock:
+ self.sendPool.append(data)
+
+ def setTargetHost(self, host, port):
+ """ Set the host/port of the target, the destination
+
+ :param host: the target host
+ :param port: the target port
+
+ .. note:: the host will be ignored when using broadcast mode
+ """
+ del self.target[:]
+ self.target.append((host, port))
+
+ def setMultipleTargetHost(self, address_list):
+ """ Sets multiple host/port targets, the destinations
+
+ :param address_list: a list with tuples (ip, port)
+ """
+ del self.target[:]
+ self.target = address_list[:]
+
+ def close(self):
+ """ Close the internal socket """
+ self.sock.close()
+
+ def send(self, data):
+ """ Send the data
+
+ :param data: the data to send
+ :rtype: bytes sent to each destination
+ """
+ bytes = -1
+ for destination in self.target:
+ bytes = self.sock.sendto(data, destination)
+ return bytes
+
+ def run(self):
+ """ Method called when you call *.start()* of the thread """
+ if len(self.target) <= 0:
+ Util.raiseException('You must set the target(s) before send data', ValueError)
+
+ while True:
+ if self.doshutdown: break
+
+ while self.isReady():
+ data = self.popPool()
+ self.send(data)
+
+ time.sleep(self.timeout)
+
+ self.close()
+
+class UDPThreadServer(threading.Thread):
+ """ The UDP server thread class.
+
+ This class is a thread to serve as Pyevolve server on the UDP
+ datagrams, it is used to receive data from network lan/wan.
+
+ Example:
+ >>> s = UDPThreadServer("192.168.0.2", 666, 10)
+ >>> s.start()
+ >>> s.shutdown()
+
+ :param host: the host to bind the server
+ :param port: the server port to bind
+ :param poolSize: the size of the server pool
+ :param timeout: the socket timeout
+
+ .. note:: this thread implements a pool to keep the received data,
+ the *poolSize* parameter specifies how much individuals
+ we must keep on the pool until the *popPool* method
+ is called; when the pool is full, the sever will
+ discard the received individuals.
+
+ """
+ def __init__(self, host, port, poolSize=10, timeout=3):
+ threading.Thread.__init__(self)
+ self.recvPool = []
+ self.recvPoolLock = threading.Lock()
+ self.bufferSize = 4096
+ self.host = host
+ self.port = port
+ self.timeout = timeout
+ self.doshutdown = False
+ self.poolSize = poolSize
+
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.sock.bind((host, port))
+ self.sock.settimeout(self.timeout)
+
+ def shutdown(self):
+ """ Shutdown the server thread, when called, this method will stop
+ the thread on the next socket timeout """
+ self.doshutdown = True
+
+ def isReady(self):
+ """ Returns True when there is data on the pool or False when not
+
+ :rtype: boolean
+
+ """
+ with self.recvPoolLock:
+ ret = True if len(self.recvPool) >= 1 else False
+ return ret
+
+ def poolLength(self):
+ """ Returns the size of the pool
+
+ :rtype: integer
+
+ """
+ with self.recvPoolLock:
+ ret = len(self.recvPool)
+ return ret
+
+ def popPool(self):
+ """ Return the last data received on the pool
+
+ :rtype: object
+
+ """
+ with self.recvPoolLock:
+ ret = self.recvPool.pop()
+ return ret
+
+ def close(self):
+ """ Closes the internal socket """
+ self.sock.close()
+
+ def setBufferSize(self, size):
+ """ Sets the receive buffer size
+
+ :param size: integer
+
+ """
+ self.bufferSize = size
+
+ def getBufferSize(self):
+ """ Gets the current receive buffer size
+
+ :rtype: integer
+
+ """
+ return self.bufferSize
+
+ def getData(self):
+ """ Calls the socket *recvfrom* method and waits for the data,
+ when the data is received, the method will return a tuple
+ with the IP of the sender and the data received. When a timeout
+ exception occurs, the method return None.
+
+ :rtype: tuple (sender ip, data) or None when timeout exception
+
+ """
+ try:
+ data, sender = self.sock.recvfrom(self.bufferSize)
+ except socket.timeout:
+ return None
+ return (sender[0], data)
+
+ def run(self):
+ """ Called when the thread is started by the user. This method
+ is the main of the thread, when called, it will enter in loop
+ to wait data or shutdown when needed.
+ """
+ while True:
+ # Get the data
+ data = self.getData()
+ # Shutdown called
+ if self.doshutdown: break
+ # The pool is full
+ if self.poolLength() >= self.poolSize:
+ continue
+ # There is no data received
+ if data == None: continue
+ # It's a packet from myself
+ if data[0] == self.host:
+ continue
+ with self.recvPoolLock:
+ self.recvPool.append(data)
+
+ self.close()
+
+def pickleAndCompress(obj, level=9):
+ """ Pickles the object and compress the dumped string with zlib
+
+ :param obj: the object to be pickled
+ :param level: the compression level, 9 is the best
+ and -1 is to not compress
+
+ """
+ pickled = cPickle.dumps(obj)
+ if level < 0: return pickled
+ else:
+ if not ZLIB_SUPPORT:
+ Util.raiseException('zlib not found !', ImportError)
+ pickled_zlib = zlib.compress(pickled, level)
+ return pickled_zlib
+
+def unpickleAndDecompress(obj_dump, decompress=True):
+ """ Decompress a zlib compressed string and unpickle the data
+
+ :param obj: the object to be decompressend and unpickled
+ """
+ if decompress:
+ if not ZLIB_SUPPORT:
+ Util.raiseException('zlib not found !', ImportError)
+ obj_decompress = zlib.decompress(obj_dump)
+ else:
+ obj_decompress = obj_dump
+ return cPickle.loads(obj_decompress)
+
+if __name__ == "__main__":
+ arg = sys.argv[1]
+ myself = getMachineIP()
+
+ if arg == "server":
+ s = UDPThreadServer(myself[0], 666)
+ s.start()
+
+ while True:
+ print ".",
+ time.sleep(10)
+ if s.isReady():
+ item = s.popPool()
+ print item
+ time.sleep(4)
+ s.shutdown()
+ break
+
+
+ elif arg == "client":
+ print "Binding on %s..." % myself[0]
+ s = UDPThreadUnicastClient(myself[0], 1500)
+ s.setData("dsfssdfsfddf")
+ s.setTargetHost(myself[0], 666)
+ s.start()
+ s.join()
+ print s.getSentBytes()
+
+ print "end..."
+
+
+
diff --git a/pyevolve/Scaling.py b/pyevolve/Scaling.py
new file mode 100644
index 0000000..70c4dea
--- /dev/null
+++ b/pyevolve/Scaling.py
@@ -0,0 +1,131 @@
+"""
+
+:mod:`Scaling` -- scaling schemes module
+===========================================================
+
+This module have the *scaling schemes* like Linear scaling, etc.
+
+"""
+import Consts
+import Util
+import math
+import logging
+
+def LinearScaling(pop):
+ """ Linear Scaling scheme
+
+ .. warning :: Linear Scaling is only for positive raw scores
+
+ """
+ logging.debug("Running linear scaling.")
+ pop.statistics()
+ c = Consts.CDefScaleLinearMultiplier
+ a = b = delta = 0.0
+
+ pop_rawAve = pop.stats["rawAve"]
+ pop_rawMax = pop.stats["rawMax"]
+ pop_rawMin = pop.stats["rawMin"]
+
+ if pop_rawAve == pop_rawMax:
+ a = 1.0
+ b = 0.0
+ elif pop_rawMin > (c * pop_rawAve - pop_rawMax / c - 1.0):
+ delta = pop_rawMax - pop_rawAve
+ a = (c - 1.0) * pop_rawAve / delta
+ b = pop_rawAve * (pop_rawMax - (c * pop_rawAve)) / delta
+ else:
+ delta = pop_rawAve - pop_rawMin
+ a = pop_rawAve / delta
+ b = -pop_rawMin * pop_rawAve / delta
+
+ for i in xrange(len(pop)):
+ f = pop[i].score
+ if f < 0.0:
+ Util.raiseException("Negative score, linear scaling not supported !", ValueError)
+ f = f * a + b
+ if f < 0:
+ f = 0.0
+ pop[i].fitness = f
+
+def SigmaTruncScaling(pop):
+ """ Sigma Truncation scaling scheme, allows negative scores """
+ logging.debug("Running sigma truncation scaling.")
+ pop.statistics()
+ c = Consts.CDefScaleSigmaTruncMultiplier
+ pop_rawAve = pop.stats["rawAve"]
+ pop_rawDev = pop.stats["rawDev"]
+ for i in xrange(len(pop)):
+ f = pop[i].score - pop_rawAve
+ f+= c * pop_rawDev
+ if f < 0: f = 0.0
+ pop[i].fitness = f
+
+def PowerLawScaling(pop):
+ """ Power Law scaling scheme
+
+ .. warning :: Power Law Scaling is only for positive raw scores
+
+ """
+ logging.debug("Running power law scaling.")
+ k = Consts.CDefScalePowerLawFactor
+ for i in xrange(len(pop)):
+ f = pop[i].score
+ if f < 0.0:
+ Util.raiseException("Negative score, power law scaling not supported !", ValueError)
+ f = math.pow(f, k)
+ pop[i].fitness = f
+
+
+def BoltzmannScaling(pop):
+ """ Boltzmann scaling scheme. You can specify the **boltz_temperature** to the
+ population parameters, this parameter will set the start temperature. You
+ can specify the **boltz_factor** and the **boltz_min** parameters, the **boltz_factor**
+ is the value that the temperature will be subtracted and the **boltz_min** is the
+ mininum temperature of the scaling scheme.
+
+ .. versionadded: 0.6
+ The `BoltzmannScaling` function.
+
+ """
+ boltz_temperature = pop.getParam("boltz_temperature", Consts.CDefScaleBoltzStart)
+ boltz_factor = pop.getParam("boltz_factor", Consts.CDefScaleBoltzFactor)
+ boltz_min = pop.getParam("boltz_min", Consts.CDefScaleBoltzMinTemp)
+
+ boltz_temperature-= boltz_factor
+ boltz_temperature = max(boltz_temperature, boltz_min)
+ pop.setParams(boltzTemperature=boltz_temperature)
+
+ boltz_e = []
+ avg = 0.0
+
+ for i in xrange(len(pop)):
+ val = math.exp(pop[i].score / boltz_temperature)
+ boltz_e.append(val)
+ avg += val
+
+ avg /= len(pop)
+
+ for i in xrange(len(pop)):
+ pop[i].fitness = boltz_e[i] / avg
+
+def ExponentialScaling(pop):
+ """ Exponential Scaling Scheme. The fitness will be the same as (e^score).
+
+ .. versionadded: 0.6
+ The `ExponentialScaling` function.
+ """
+ for i in xrange(len(pop)):
+ score = pop[i].score
+ pop[i].fitness = math.exp(score)
+
+def SaturatedScaling(pop):
+ """ Saturated Scaling Scheme. The fitness will be the same as 1.0-(e^score)
+
+ .. versionadded: 0.6
+ The `SaturatedScaling` function.
+ """
+ for i in xrange(len(pop)):
+ score = pop[i].score
+ pop[i].fitness = 1.0 - math.exp(score)
+
+
diff --git a/pyevolve/Selectors.py b/pyevolve/Selectors.py
new file mode 100644
index 0000000..7367480
--- /dev/null
+++ b/pyevolve/Selectors.py
@@ -0,0 +1,177 @@
+"""
+
+:mod:`Selectors` -- selection methods module
+==============================================================
+
+This module have the *selection methods*, like roulette wheel, tournament, ranking, etc.
+
+"""
+
+import random
+import Consts
+import operator
+
+def GRankSelector(population, **args):
+ """ The Rank Selector - This selector will pick the best individual of
+ the population every time.
+ """
+ count = 0
+
+ if args["popID"] != GRankSelector.cachePopID:
+ if population.sortType == Consts.sortType["scaled"]:
+ best_fitness = population.bestFitness().fitness
+ for index in xrange(1, len(population.internalPop)):
+ if population[index].fitness == best_fitness:
+ count += 1
+ else:
+ best_raw = population.bestRaw().score
+ for index in xrange(1, len(population.internalPop)):
+ if population[index].score == best_raw:
+ count += 1
+
+ GRankSelector.cachePopID = args["popID"]
+ GRankSelector.cacheCount = count
+
+ else: count = GRankSelector.cacheCount
+
+ return population[random.randint(0, count)]
+
+GRankSelector.cachePopID = None
+GRankSelector.cacheCount = None
+
+def GUniformSelector(population, **args):
+ """ The Uniform Selector """
+ return population[random.randint(0, len(population)-1)]
+
+def GTournamentSelector(population, **args):
+ """ The Tournament Selector
+
+ It accepts the *tournamentPool* population parameter.
+
+ .. note::
+ the Tournament Selector uses the Roulette Wheel to
+ pick individuals for the pool
+
+ .. versionchanged:: 0.6
+ Changed the parameter `poolSize` to the `tournamentPool`, now the selector
+ gets the pool size from the population.
+
+ """
+ choosen = None
+ should_minimize = population.minimax == Consts.minimaxType["minimize"]
+ minimax_operator = min if should_minimize else max
+
+ poolSize = population.getParam("tournamentPool", Consts.CDefTournamentPoolSize)
+ tournament_pool = [GRouletteWheel(population, **args) for i in xrange(poolSize) ]
+
+ if population.sortType == Consts.sortType["scaled"]:
+ choosen = minimax_operator(tournament_pool, key=lambda ind: ind.fitness)
+ else:
+ choosen = minimax_operator(tournament_pool, key=lambda ind: ind.score)
+
+ return choosen
+
+def GTournamentSelectorAlternative(population, **args):
+ """ The alternative Tournament Selector
+
+ This Tournament Selector don't uses the Roulette Wheel
+
+ It accepts the *tournamentPool* population parameter.
+
+ .. versionadded: 0.6
+ Added the GTournamentAlternative function.
+
+ """
+ pool_size = population.getParam("tournamentPool", Consts.CDefTournamentPoolSize)
+ len_pop = len(population)
+ should_minimize = population.minimax == Consts.minimaxType["minimize"]
+ minimax_operator = min if should_minimize else max
+ tournament_pool = [population[random.randint(0, len_pop-1)] for i in xrange(pool_size)]
+
+ if population.sortType == Consts.sortType["scaled"]:
+ choosen = minimax_operator(tournament_pool, key=lambda ind: ind.fitness)
+ else:
+ choosen = minimax_operator(tournament_pool, key=lambda ind: ind.score)
+
+ return choosen
+
+def GRouletteWheel(population, **args):
+ """ The Roulette Wheel selector """
+ psum = None
+ if args["popID"] != GRouletteWheel.cachePopID:
+ GRouletteWheel.cachePopID = args["popID"]
+ psum = GRouletteWheel_PrepareWheel(population)
+ GRouletteWheel.cacheWheel = psum
+ else:
+ psum = GRouletteWheel.cacheWheel
+
+ cutoff = random.random()
+ lower = 0
+ upper = len(population) - 1
+ while(upper >= lower):
+ i = lower + ((upper-lower)/2)
+ if psum[i] > cutoff: upper = i-1
+ else: lower = i+1
+
+ lower = min(len(population)-1, lower)
+ lower = max(0, lower)
+
+ return population.bestFitness(lower)
+
+GRouletteWheel.cachePopID = None
+GRouletteWheel.cacheWheel = None
+
+def GRouletteWheel_PrepareWheel(population):
+ """ A preparation for Roulette Wheel selection """
+
+ len_pop = len(population)
+
+ psum = [i for i in xrange(len_pop)]
+
+ population.statistics()
+
+ if population.sortType == Consts.sortType["scaled"]:
+ pop_fitMax = population.stats["fitMax"]
+ pop_fitMin = population.stats["fitMin"]
+
+ if pop_fitMax == pop_fitMin:
+ for index in xrange(len_pop):
+ psum[index] = (index+1) / float(len_pop)
+ elif (pop_fitMax > 0 and pop_fitMin >= 0) or (pop_fitMax <= 0 and pop_fitMin < 0):
+ population.sort()
+ if population.minimax == Consts.minimaxType["maximize"]:
+ psum[0] = population[0].fitness
+ for i in xrange(1, len_pop):
+ psum[i] = population[i].fitness + psum[i-1]
+ for i in xrange(len_pop):
+ psum[i] /= float(psum[len_pop - 1])
+ else:
+ psum[0] = -population[0].fitness + pop_fitMax + pop_fitMin
+ for i in xrange(1, len_pop):
+ psum[i] = -population[i].fitness + pop_fitMax + pop_fitMin + psum[i-1]
+ for i in xrange(len_pop):
+ psum[i] /= float(psum[len_pop - 1])
+ else:
+ pop_rawMax = population.stats["rawMax"]
+ pop_rawMin = population.stats["rawMin"]
+
+ if pop_rawMax == pop_rawMin:
+ for index in xrange(len_pop):
+ psum[index] = (index+1) / float(len_pop)
+
+ elif (pop_rawMax > 0 and pop_rawMin >= 0) or (pop_rawMax <= 0 and pop_rawMin < 0):
+ population.sort()
+ if population.minimax == Consts.minimaxType["maximize"]:
+ psum[0] = population[0].score
+ for i in xrange(1, len_pop):
+ psum[i] = population[i].score + psum[i-1]
+ for i in xrange(len_pop):
+ psum[i] /= float(psum[len_pop-1])
+ else:
+ psum[0] = - population[0].score + pop_rawMax + pop_rawMin
+ for i in xrange(1, len_pop):
+ psum[i] = - population[i].score + pop_rawMax + pop_rawMin + psum[i-1]
+ for i in xrange(len_pop):
+ psum[i] /= float(psum[len_pop-1])
+
+ return psum
diff --git a/pyevolve/Statistics.py b/pyevolve/Statistics.py
new file mode 100644
index 0000000..037bb93
--- /dev/null
+++ b/pyevolve/Statistics.py
@@ -0,0 +1,102 @@
+"""
+
+:mod:`Statistics` -- statistical structure module
+==========================================================================
+
+This module have the class which is reponsible to keep statistics of each
+generation. This class is used by the adapters and other statistics dump objects.
+
+"""
+class Statistics:
+ """ Statistics Class - A class bean-like to store the statistics
+
+ The statistics hold by this class are:
+
+ **rawMax, rawMin, rawAve**
+ Maximum, minimum and average of raw scores
+
+ **rawDev, rawVar**
+ Standard Deviation and Variance of raw scores
+
+ **fitMax, fitMin, fitAve**
+ Maximum, mininum and average of fitness scores
+
+ **rawTot, fitTot**
+ The total (sum) of raw scores and the fitness scores
+
+ Example:
+ >>> stats = ga_engine.getStatistics()
+ >>> st["rawMax"]
+ 10.2
+ """
+
+ def __init__(self):
+ """ The Statistics Class creator """
+
+ # 'fit' means 'fitness'
+ self.internalDict = { "rawMax" : 0.0,
+ "rawMin" : 0.0,
+ "rawAve" : 0.0,
+ "rawDev" : 0.0,
+ "rawVar" : 0.0,
+ "fitMax" : 0.0,
+ "fitMin" : 0.0,
+ "fitAve" : 0.0 }
+
+ self.descriptions = { "rawMax" : "Maximum raw score",
+ "rawMin" : "Minimum raw score",
+ "rawAve" : "Average of raw scores",
+ "rawDev" : "Standard deviation of raw scores",
+ "rawVar" : "Raw scores variance",
+ "fitMax" : "Maximum fitness",
+ "fitMin" : "Minimum fitness",
+ "fitAve" : "Fitness average" }
+ def __getitem__(self, key):
+ """ Return the specific statistic by key """
+ return self.internalDict[key]
+
+ def __setitem__(self, key, value):
+ """ Set the statistic """
+ self.internalDict[key] = value
+
+ def __len__(self):
+ """ Return the lenght of internal stats dictionary """
+ return len(self.internalDict)
+
+ def __repr__(self):
+ """ Return a string representation of the statistics """
+ strBuff = "- Statistics\n"
+ for k,v in self.internalDict.items():
+ strBuff += "\t%-45s = %.2f\n" % (self.descriptions.get(k, k), v)
+ return strBuff
+
+ def asTuple(self):
+ """ Returns the stats as a python tuple """
+ return tuple(self.internalDict.values())
+
+ def clear(self):
+ """ Set all statistics to zero """
+ for k in self.internalDict.keys():
+ self.internalDict[k] = 0
+
+ def items(self):
+ """ Return a tuple (name, value) for all stored statistics """
+ return self.internalDict.items()
+
+ def clone(self):
+ """ Instantiate a new Statistic class with the same contents """
+ clone_stat = Statistics()
+ self.copy(clone_stat)
+ return clone_stat
+
+ def copy(self, obj):
+ """ Copy the values to the obj variable of the same class
+
+ :param obj: the Statistics object destination
+
+ """
+ obj.internalDict = self.internalDict.copy()
+ obj.descriptions = self.descriptions.copy()
+
+
+
\ No newline at end of file
diff --git a/pyevolve/Util.py b/pyevolve/Util.py
new file mode 100644
index 0000000..7f75140
--- /dev/null
+++ b/pyevolve/Util.py
@@ -0,0 +1,332 @@
+"""
+
+:mod:`Util` -- utility module
+============================================================================
+
+This is the utility module, with some utility functions of general
+use, like list item swap, random utilities and etc.
+
+"""
+
+from random import random as rand_random
+from math import sqrt as math_sqrt
+import logging
+import Consts
+
+def randomFlipCoin(p):
+ """ Returns True with the *p* probability. If the *p* is 1.0,
+ the function will always return True, or if is 0.0, the
+ function will return always False.
+
+ Example:
+ >>> Util.randomFlipCoin(1.0)
+ True
+
+ :param p: probability, between 0.0 and 1.0
+ :rtype: True or False
+
+ """
+ if p == 1.0: return True
+ if p == 0.0: return False
+
+ return True if rand_random() <= p else False
+
+def listSwapElement(lst, indexa, indexb):
+ """ Swaps elements A and B in a list.
+
+ Example:
+ >>> l = [1, 2, 3]
+ >>> Util.listSwapElement(l, 1, 2)
+ >>> l
+ [1, 3, 2]
+
+ :param lst: the list
+ :param indexa: the swap element A
+ :param indexb: the swap element B
+ :rtype: None
+
+ """
+ lst[indexa], lst[indexb] = lst[indexb], lst[indexa]
+
+def list2DSwapElement(lst, indexa, indexb):
+ """ Swaps elements A and B in a 2D list (matrix).
+
+ Example:
+ >>> l = [ [1,2,3], [4,5,6] ]
+ >>> Util.list2DSwapElement(l, (0,1), (1,1) )
+ >>> l
+ [[1, 5, 3], [4, 2, 6]]
+
+ :param lst: the list
+ :param indexa: the swap element A
+ :param indexb: the swap element B
+ :rtype: None
+
+ """
+ temp = lst[indexa[0]][indexa[1]]
+ lst[indexa[0]][indexa[1]] = lst[indexb[0]][indexb[1]]
+ lst[indexb[0]][indexb[1]] = temp
+
+def raiseException(message, expt=None):
+ """ Raise an exception and logs the message.
+
+ Example:
+ >>> Util.raiseException('The value is not an integer', ValueError)
+
+ :param message: the message of exception
+ :param expt: the exception class
+ :rtype: None
+
+ """
+ logging.critical(message)
+ if expt is None:
+ raise Exception(message)
+ else:
+ raise expt, message
+
+
+def cmp_individual_raw(a, b):
+ """ Compares two individual raw scores
+
+ Example:
+ >>> GPopulation.cmp_individual_raw(a, b)
+
+ :param a: the A individual instance
+ :param b: the B individual instance
+ :rtype: 0 if the two individuals raw score are the same,
+ -1 if the B individual raw score is greater than A and
+ 1 if the A individual raw score is greater than B.
+
+ .. note:: this function is used to sorte the population individuals
+
+ """
+ if a.score < b.score: return -1
+ if a.score > b.score: return 1
+ return 0
+
+def cmp_individual_scaled(a, b):
+ """ Compares two individual fitness scores, used for sorting population
+
+ Example:
+ >>> GPopulation.cmp_individual_scaled(a, b)
+
+ :param a: the A individual instance
+ :param b: the B individual instance
+ :rtype: 0 if the two individuals fitness score are the same,
+ -1 if the B individual fitness score is greater than A and
+ 1 if the A individual fitness score is greater than B.
+
+ .. note:: this function is used to sorte the population individuals
+
+ """
+ if a.fitness < b.fitness: return -1
+ if a.fitness > b.fitness: return 1
+ return 0
+
+def importSpecial(name):
+ """ This function will import the *name* module, if fails,
+ it will raise an ImportError exception and a message
+
+ :param name: the module name
+ :rtype: the module object
+
+ .. versionadded:: 0.6
+ The *import_special* function
+ """
+ try:
+ imp_mod = __import__(name)
+ except ImportError:
+ raiseException("Cannot import module %s: %s" % (name, Consts.CDefImportList[name]), expt=ImportError)
+ return imp_mod
+
+class ErrorAccumulator:
+ """ An accumulator for the Root Mean Square Error (RMSE) and the
+ Mean Square Error (MSE)
+ """
+ def __init__(self):
+ self.acc = 0.0
+ self.acc_square = 0.0
+ self.acc_len = 0
+
+ def reset(self):
+ """ Reset the accumulator """
+ self.acc_square = 0.0
+ self.acc = 0.0
+ self.acc_len = 0
+
+ def append(self, target, evaluated):
+ """ Add value to the accumulator
+
+ :param target: the target value
+ :param evaluated: the evaluated value
+ """
+ self.acc_square += (target - evaluated)**2
+ self.acc += (target - evaluated)
+ self.acc_len +=1
+
+ def __iadd__(self, value):
+ """ The same as append, but you must pass a tuple """
+ self.acc_square += (value[0] - value[1])**2
+ self.acc += abs(value[0] - value[1])
+ self.acc_len +=1
+ return self
+
+ def getMean(self):
+ """ Return the mean of the non-squared accumulator """
+ return self.acc / self.acc_len
+
+ def getSquared(self):
+ """ Returns the squared accumulator """
+ return self.acc_square
+
+ def getNonSquared(self):
+ """ Returns the non-squared accumulator """
+ return self.acc
+
+ def getAdjusted(self):
+ """ Returns the adjusted fitness
+ This fitness is calculated as 1 / (1 + standardized fitness)
+ """
+ return 1.0/(1.0 + self.acc)
+
+ def getRMSE(self):
+ """ Return the root mean square error
+
+ :rtype: float RMSE
+ """
+ return math_sqrt(self.acc_square / float(self.acc_len))
+
+ def getMSE(self):
+ """ Return the mean square error
+
+ :rtype: float MSE
+ """
+ return (self.acc_square / float(self.acc_len))
+
+
+class Graph:
+ """ The Graph class
+
+ Example:
+ >>> g = Graph()
+ >>> g.addEdge("a", "b")
+ >>> g.addEdge("b", "c")
+ >>> for node in g:
+ ... print node
+ a
+ b
+ c
+
+ .. versionadded:: 0.6
+ The *Graph* class.
+ """
+
+ def __init__(self):
+ """ The constructor """
+ self.adjacent = {}
+
+ def __iter__(self):
+ """ Returns an iterator to the all graph elements """
+ return iter(self.adjacent)
+
+ def addNode(self, node):
+ """ Add the node
+
+ :param node: the node to add
+ """
+ if node not in self.adjacent:
+ self.adjacent[node] = {}
+
+ def __iadd__(self, node):
+ """ Add a node using the += operator """
+ self.addNode(node)
+ return self
+
+ def addEdge(self, a, b):
+ """ Add an edge between two nodes, if the nodes
+ doesn't exists, they will be created
+
+ :param a: the first node
+ :param b: the second node
+ """
+ if a not in self.adjacent:
+ self.adjacent[a] = {}
+
+ if b not in self.adjacent:
+ self.adjacent[b] = {}
+
+ self.adjacent[a][b] = True
+ self.adjacent[b][a] = True
+
+ def getNodes(self):
+ """ Returns all the current nodes on the graph
+
+ :rtype: the list of nodes
+ """
+ return self.adjacent.keys()
+
+ def reset(self):
+ """ Deletes all nodes of the graph """
+ self.adjacent.clear()
+
+ def getNeighbors(self, node):
+ """ Returns the neighbors of the node
+
+ :param node: the node
+ """
+ return self.adjacent[node].keys()
+
+ def __getitem__(self, node):
+ """ Returns the adjacent nodes of the node """
+ return self.adjacent[node].keys()
+
+ def __repr__(self):
+ ret = "- Graph\n"
+ ret += "\tNode list:\n"
+ for node in self:
+ ret += "\t\tNode [%s] = %s\n" % (node, self.getNeighbors(node))
+ return ret
+
+
+def G1DListGetEdgesComposite(mom, dad):
+ """ Get the edges and the merge between the edges of two G1DList individuals
+
+ :param mom: the mom G1DList individual
+ :param dad: the dad G1DList individual
+ :rtype: a tuple (mom edges, dad edges, merge)
+ """
+ mom_edges = G1DListGetEdges(mom)
+ dad_edges = G1DListGetEdges(dad)
+ return (mom_edges, dad_edges, G1DListMergeEdges(mom_edges, dad_edges))
+
+def G1DListGetEdges(individual):
+ """ Get the edges of a G1DList individual
+
+ :param individual: the G1DList individual
+ :rtype: the edges dictionary
+ """
+ edg = {}
+ ind_list = individual.getInternalList()
+ for i in xrange(len(ind_list)):
+ a, b = ind_list[i], ind_list[i-1]
+
+ if a not in edg: edg[a] = []
+ else: edg[a].append(b)
+
+ if b not in edg: edg[b] = []
+ else: edg[b].append(a)
+ return edg
+
+def G1DListMergeEdges(eda, edb):
+ """ Get the merge between the two individual edges
+
+ :param eda: the edges of the first G1DList genome
+ :param edb: the edges of the second G1DList genome
+ :rtype: the merged dictionary
+ """
+ edges = {}
+ for value, near in eda.items():
+ for adj in near:
+ if (value in edb) and (adj in edb[value]):
+ edges.setdefault(value, []).append(adj)
+ return edges
diff --git a/pyevolve/__init__.py b/pyevolve/__init__.py
new file mode 100644
index 0000000..1bd8945
--- /dev/null
+++ b/pyevolve/__init__.py
@@ -0,0 +1,44 @@
+"""
+:mod:`pyevolve` -- the main pyevolve namespace
+================================================================
+
+This is the main module of the pyevolve, every other module
+is above this namespace, for example, to import :mod:`Mutators`:
+
+ >>> from pyevolve import Mutators
+
+
+"""
+__all__ = ["Consts", "Crossovers", "DBAdapters", "FunctionSlot",
+ "G1DBinaryString", "G1DList", "G2DBinaryString",
+ "G2DList", "GAllele", "GenomeBase", "GPopulation",
+ "GSimpleGA", "GTree", "Initializators",
+ "Migration", "Mutators", "Network", "Scaling", "Selectors",
+ "Statistics", "Util"]
+
+__version__ = '0.6'
+__author__ = 'Christian S. Perone'
+
+import pyevolve.Consts
+import sys
+
+if sys.version_info[:2] < Consts.CDefPythonRequire:
+ raise Exception("Python 2.5+ required, the version %s was found on your system !" % (sys.version_info[:2],))
+
+del sys
+
+def logEnable(filename=Consts.CDefLogFile, level=Consts.CDefLogLevel):
+ """ Enable the log system for pyevolve
+
+ :param filename: the log filename
+ :param level: the debugging level
+
+ Example:
+ >>> pyevolve.logEnable()
+
+ """
+ import logging
+ logging.basicConfig(level=level,
+ format='%(asctime)s [%(module)s:%(funcName)s:%(lineno)d] %(levelname)s %(message)s',
+ filename=filename,
+ filemode='w')
logging.info("Pyevolve v.%s, the log was enabled by user.", __version__)
diff --git a/pyevolve/clean_pyc.bat b/pyevolve/clean_pyc.bat
new file mode 100644
index 0000000..47ba57e
--- /dev/null
+++ b/pyevolve/clean_pyc.bat
@@ -0,0 +1,5 @@
+ at echo off
+del *.pyc
+del *.pyo
+del *.bak
+del *.class
\ No newline at end of file
diff --git a/pyevolve/clean_pyc.sh b/pyevolve/clean_pyc.sh
new file mode 100644
index 0000000..d31455e
--- /dev/null
+++ b/pyevolve/clean_pyc.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+rm -rf *.pyc
+rm -rf *.class
\ No newline at end of file
diff --git a/pyevolve_graph.py b/pyevolve_graph.py
new file mode 100644
index 0000000..1b06858
--- /dev/null
+++ b/pyevolve_graph.py
@@ -0,0 +1,610 @@
+#!/usr/bin/python
+
+# This code is part of Pyevolve.
+# It requires matplotlib v.0.98.5.0+
+from optparse import OptionParser
+from optparse import OptionGroup
+
+def graph_pop_heatmap_raw(all, minimize, colormap="jet", filesave=None):
+ pylab.imshow(all, aspect="auto", interpolation="gaussian", cmap=matplotlib.cm.__dict__[colormap])
+ pylab.title("Plot of pop. raw scores along the generations")
+ pylab.xlabel('Population')
+ pylab.ylabel('Generations')
+ pylab.grid(True)
+ pylab.colorbar()
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+def graph_pop_heatmap_fitness(all, minimize, colormap="jet", filesave=None):
+ pylab.imshow(all, aspect="equal", interpolation="gaussian", cmap=matplotlib.cm.__dict__[colormap])
+ pylab.title("Plot of pop. fitness scores along the generations")
+ pylab.xlabel('Population')
+ pylab.ylabel('Generations')
+ pylab.grid(True)
+ pylab.colorbar()
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+
+def graph_diff_raw(all, minimize, filesave=None):
+ x = []
+
+ diff_raw_y = []
+ diff_fit_y = []
+
+ for it in all:
+ x.append(it["generation"])
+ diff_raw_y.append(it["rawMax"] - it["rawMin"])
+ diff_fit_y.append(it["fitMax"] - it["fitMin"])
+
+ pylab.figure()
+ pylab.subplot(211)
+
+ pylab.plot(x, diff_raw_y, "g", label="Raw difference", linewidth=1.2)
+ pylab.fill_between(x, diff_raw_y, color="g", alpha=0.1)
+
+ diff_raw_max= max(diff_raw_y)
+ gen_max_raw = x[diff_raw_y.index(diff_raw_max)]
+
+ pylab.annotate("Maximum (%.2f)" % (diff_raw_max,), xy=(gen_max_raw, diff_raw_max), xycoords='data',
+ xytext=(-150, -20), textcoords='offset points',
+ arrowprops=dict(arrowstyle="->",
+ connectionstyle="arc"),
+ )
+
+ pylab.xlabel("Generation (#)")
+ pylab.ylabel("Raw difference")
+ pylab.title("Plot of evolution identified by '%s'" % (options.identify))
+
+ pylab.grid(True)
+ pylab.legend(prop=FontProperties(size="smaller"))
+
+ pylab.subplot(212)
+
+ pylab.plot(x, diff_fit_y, "b", label="Fitness difference", linewidth=1.2)
+ pylab.fill_between(x, diff_fit_y, color="b", alpha=0.1)
+
+
+ diff_fit_max= max(diff_fit_y)
+ gen_max_fit = x[diff_fit_y.index(diff_fit_max)]
+
+ pylab.annotate("Maximum (%.2f)" % (diff_fit_max,), xy=(gen_max_fit, diff_fit_max), xycoords='data',
+ xytext=(-150, -20), textcoords='offset points',
+ arrowprops=dict(arrowstyle="->",
+ connectionstyle="arc"),
+ )
+
+ pylab.xlabel("Generation (#)")
+ pylab.ylabel("Fitness difference")
+
+ pylab.grid(True)
+ pylab.legend(prop=FontProperties(size="smaller"))
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+def graph_maxmin_raw(all, minimize, filesave=None):
+ x = []
+ max_y = []
+ min_y = []
+ std_dev_y = []
+ avg_y = []
+
+ for it in all:
+ x.append(it["generation"])
+ max_y.append(it["rawMax"])
+ min_y.append(it["rawMin"])
+ std_dev_y.append(it["rawDev"])
+ avg_y.append(it["rawAve"])
+
+ pylab.figure()
+
+ pylab.plot(x, max_y, "g", label="Max raw", linewidth=1.2)
+ pylab.plot(x, min_y, "r", label="Min raw", linewidth=1.2)
+ pylab.plot(x, avg_y, "b", label="Avg raw", linewidth=1.2)
+ pylab.plot(x, std_dev_y, "k", label="Std Dev raw", linewidth=1.2)
+
+ pylab.fill_between(x, min_y, max_y, color="g", alpha=0.1, label="Diff max/min")
+
+ if minimize: raw_max = min(min_y)
+ else: raw_max= max(max_y)
+
+ if minimize: gen_max = x[min_y.index(raw_max)]
+ else: gen_max = x[max_y.index(raw_max)]
+
+ min_std = min(std_dev_y)
+ gen_min_std = x[std_dev_y.index(min_std)]
+
+ max_std = max(std_dev_y)
+ gen_max_std = x[std_dev_y.index(max_std)]
+
+ if minimize: annot_label = "Minimum (%.2f)" % (raw_max,)
+ else: annot_label = "Maximum (%.2f)" % (raw_max,)
+
+
+ pylab.annotate(annot_label, xy=(gen_max, raw_max), xycoords='data',
+ xytext=(8, 15), textcoords='offset points',
+ arrowprops=dict(arrowstyle="->",
+ connectionstyle="arc"),
+ )
+
+ pylab.annotate("Min StdDev (%.2f)" % (min_std,), xy=(gen_min_std, min_std), xycoords='data',
+ xytext=(8, 15), textcoords='offset points',
+ arrowprops=dict(arrowstyle="->",
+ connectionstyle="arc"),
+ )
+
+ pylab.annotate("Max StdDev (%.2f)" % (max_std,), xy=(gen_max_std, max_std), xycoords='data',
+ xytext=(8, 15), textcoords='offset points',
+ arrowprops=dict(arrowstyle="->",
+ connectionstyle="arc"),
+ )
+
+ pylab.xlabel("Generation (#)")
+ pylab.ylabel("Raw score")
+ pylab.title("Plot of evolution identified by '%s' (raw scores)" % (options.identify))
+
+ pylab.grid(True)
+ pylab.legend(prop=FontProperties(size="smaller"))
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+
+def graph_maxmin_fitness(all, minimize, filesave=None):
+ x = []
+ max_y = []
+ min_y = []
+ avg_y = []
+
+ for it in all:
+ x.append(it["generation"])
+ max_y.append(it["fitMax"])
+ min_y.append(it["fitMin"])
+ avg_y.append(it["fitAve"])
+
+ pylab.figure()
+ pylab.plot(x, max_y, "g", label="Max fitness")
+ pylab.plot(x, min_y, "r", label="Min fitness")
+ pylab.plot(x, avg_y, "b", label="Avg fitness")
+
+ pylab.fill_between(x, min_y, max_y, color="g", alpha=0.1, label="Diff max/min")
+
+ if minimize: raw_max = min(min_y)
+ else: raw_max = max(max_y)
+
+ if minimize: gen_max = x[min_y.index(raw_max)]
+ else: gen_max = x[max_y.index(raw_max)]
+
+ if minimize: annot_label = "Minimum (%.2f)" % (raw_max,)
+ else: annot_label = "Maximum (%.2f)" % (raw_max,)
+
+ pylab.annotate(annot_label, xy=(gen_max, raw_max), xycoords='data',
+ xytext=(8, 15), textcoords='offset points',
+ arrowprops=dict(arrowstyle="->",
+ connectionstyle="arc"),
+ )
+
+ pylab.xlabel("Generation (#)")
+ pylab.ylabel("Fitness score")
+ pylab.title("Plot of evolution identified by '%s' (fitness scores)" % (options.identify))
+ pylab.grid(True)
+ pylab.legend(prop=FontProperties(size="smaller"))
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+def graph_errorbars_raw(all, minimize, filesave=None):
+ x = []
+ y = []
+ yerr_max = []
+ yerr_min = []
+
+ for it in all:
+ x.append(it["generation"])
+ y.append(it["rawAve"])
+ ymax = it["rawMax"] - it["rawAve"]
+ ymin = it["rawAve"] - it["rawMin"]
+
+ yerr_max.append(ymax)
+ yerr_min.append(ymin)
+
+ pylab.figure()
+ pylab.errorbar(x, y, [yerr_min, yerr_max], ecolor="g")
+ pylab.xlabel('Generation (#)')
+ pylab.ylabel('Raw score Min/Avg/Max')
+ pylab.title("Plot of evolution identified by '%s' (raw scores)" % (options.identify))
+ pylab.grid(True)
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+def graph_errorbars_fitness(all, minimize, filesave=None):
+ x = []
+ y = []
+ yerr_max = []
+ yerr_min = []
+
+ for it in all:
+ x.append(it["generation"])
+ y.append(it["fitAve"])
+ ymax = it["fitMax"] - it["fitAve"]
+ ymin = it["fitAve"] - it["fitMin"]
+
+ yerr_max.append(ymax)
+ yerr_min.append(ymin)
+
+ pylab.figure()
+ pylab.errorbar(x, y, [yerr_min, yerr_max], ecolor="g")
+ pylab.xlabel('Generation (#)')
+ pylab.ylabel('Fitness score Min/Avg/Max')
+ pylab.title("Plot of evolution identified by '%s' (fitness scores)" % (options.identify))
+
+ pylab.grid(True)
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+def graph_compare_raw(all, minimize, id_list, filesave=None):
+ colors_list = ["g", "b", "r", "k", "m", "y"]
+ index = 0
+
+ pylab.figure()
+
+ for it_out in all:
+ x = []
+ max_y = []
+ min_y = []
+
+ for it in it_out:
+ x.append(it["generation"])
+ max_y.append(it["rawMax"])
+ min_y.append(it["rawMin"])
+
+
+ if minimize:
+ pylab.plot(x, max_y, colors_list[index], linewidth=0.05)
+ pylab.plot(x, min_y, colors_list[index], label="Raw min (%s)" % (id_list[index],), linewidth=1.3)
+ else:
+ pylab.plot(x, max_y, colors_list[index], label="Raw max (%s)" % (id_list[index],), linewidth=1.3)
+ pylab.plot(x, min_y, colors_list[index], linewidth=0.05)
+
+ pylab.fill_between(x, min_y, max_y, color=colors_list[index], alpha=0.06,)
+
+ index += 1
+
+ pylab.xlabel("Generation (#)")
+ pylab.ylabel("Raw score")
+ pylab.title("Plot of evolution identified by '%s' (raw scores)" % ('many',))
+ pylab.grid(True)
+ pylab.legend(prop=FontProperties(size="smaller"))
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+def graph_compare_fitness(all, minimize, id_list, filesave=None):
+ colors_list = ["g", "b", "r", "k", "m", "y"]
+ index = 0
+
+ pylab.figure()
+
+ for it_out in all:
+ x = []
+ max_y = []
+ min_y = []
+
+ for it in it_out:
+ x.append(it["generation"])
+ max_y.append(it["fitMax"])
+ min_y.append(it["fitMin"])
+
+ if minimize:
+ pylab.plot(x, max_y, colors_list[index], linewidth=0.05)
+ pylab.plot(x, min_y, colors_list[index], label="Fitness min (%s)" % (id_list[index],), linewidth=1.3)
+ else:
+ pylab.plot(x, max_y, colors_list[index], label="Fitness max (%s)" % (id_list[index],), linewidth=1.3)
+ pylab.plot(x, min_y, colors_list[index], linewidth=0.05)
+
+ pylab.fill_between(x, min_y, max_y, color=colors_list[index], alpha=0.06,)
+
+ index += 1
+
+ pylab.xlabel("Generation (#)")
+ pylab.ylabel("Fitness score")
+ pylab.title("Plot of evolution identified by '%s' (fitness scores)" % ('many',))
+ pylab.grid(True)
+ pylab.legend(prop=FontProperties(size="smaller"))
+
+ if filesave:
+ pylab.savefig(filesave)
+ print "Graph saved to %s file !" % (filesave,)
+ else:
+ pylab.show()
+
+
+if __name__ == "__main__":
+ from pyevolve import __version__ as pyevolve_version
+ from pyevolve import __author__ as pyevolve_author
+
+ popGraph = False
+
+ print "Pyevolve %s - Graph Plot Tool" % (pyevolve_version,)
+ print "By %s\n" % (pyevolve_author,)
+ parser = OptionParser()
+
+ parser.add_option("-f", "--file", dest="dbfile",
+ help="Database file to read (default is 'pyevolve.db').", metavar="FILENAME", default="pyevolve.db")
+
+ parser.add_option("-i", "--identify", dest="identify",
+ help="The identify of evolution.", metavar="IDENTIFY")
+
+ parser.add_option("-o", "--outfile", dest="outfile",
+ help="""Write the graph image to a file (don't use extension, just the filename, default is png format, but you can change using --extension (-e) parameter).""",
+ metavar="OUTFILE")
+
+ parser.add_option("-e", "--extension", dest="extension",
+ help="""Graph image file format. Supported options (formats) are: emf, eps, pdf, png, ps, raw, rgba, svg, svgz. Default is 'png'.""",
+ metavar="EXTENSION", default="png")
+
+ parser.add_option("-g", "--genrange", dest="genrange",
+ help="""This is the generation range of the graph, ex: 1:30 (interval between 1 and 30).""",
+ metavar="GENRANGE")
+
+ parser.add_option("-l", "--lindrange", dest="lindrange",
+ help="""This is the individual range of the graph, ex: 1:30 (individuals between 1 and 30), only applies to heatmaps.""",
+ metavar="LINDRANGE")
+
+ parser.add_option("-c", "--colormap", dest="colormap",
+ help="""Sets the Color Map for the graph types 8 and 9. Some options are: summer, bone, gray, hot, jet, cooper, spectral. The default is 'jet'.""",
+ metavar="COLORMAP", default="jet")
+
+ parser.add_option("-m", "--minimize", action="store_true",
+ help="Sets the 'Minimize' mode, default is the Maximize mode. This option makes sense if you are minimizing your evaluation function.", dest="minimize")
+
+ group = OptionGroup(parser, "Graph types", "This is the supported graph types")
+
+ group.add_option("-0", action="store_true", help="Write all graphs to files. Graph types: 1, 2, 3, 4 and 5.", dest="all_graphs")
+
+ group.add_option("-1", action="store_true", help="Error bars graph (raw scores).", dest="errorbars_raw")
+ group.add_option("-2", action="store_true", help="Error bars graph (fitness scores).", dest="errorbars_fitness")
+ group.add_option("-3", action="store_true", help="Max/min/avg/std. dev. graph (raw scores).", dest="maxmin_raw")
+ group.add_option("-4", action="store_true", help="Max/min/avg graph (fitness scores).", dest="maxmin_fitness")
+ group.add_option("-5", action="store_true", help="Raw and Fitness min/max difference graph.", dest="diff_raw")
+
+ group.add_option("-6", action="store_true", help="Compare best raw score of two or more evolutions (you must specify the identify comma-separed list with --identify (-i) parameter, like 'one, two, three'), the maximum is 6 items.", dest="compare_raw")
+ group.add_option("-7", action="store_true", help="Compare best fitness score of two or more evolutions (you must specify the identify comma-separed list with --identify (-i) parameter, like 'one, two, three'), the maximum is 6 items.", dest="compare_fitness")
+
+ group.add_option("-8", action="store_true", help="Show a heat map of population raw score distribution between generations.", dest="pop_heatmap_raw")
+ group.add_option("-9", action="store_true", help="Show a heat map of population fitness score distribution between generations.", dest="pop_heatmap_fitness")
+
+
+ parser.add_option_group(group)
+
+ (options, args) = parser.parse_args()
+
+ if options.identify and (not options.errorbars_raw
+ and not options.errorbars_fitness
+ and not options.maxmin_raw
+ and not options.maxmin_fitness
+ and not options.diff_raw
+ and not options.all_graphs
+ and not options.compare_raw
+ and not options.pop_heatmap_raw
+ and not options.pop_heatmap_fitness
+ and not options.compare_fitness):
+ parser.error("You must choose one graph type !")
+
+ if (not options.identify) or (not options.dbfile):
+ parser.print_help()
+ exit()
+
+ print "Loading modules...."
+
+ import os.path
+ if not os.path.exists(options.dbfile):
+ print "Database file '%s' not found !" % (options.dbfile, )
+ exit()
+
+ import pylab
+ from matplotlib.font_manager import FontProperties
+ import matplotlib.cm
+ import sqlite3
+ import math
+ import os
+
+ print "Loading database and creating graph..."
+
+ identify_list = options.identify.split(",")
+ identify_list = map(str.strip, identify_list)
+
+ all = None
+
+ if options.pop_heatmap_raw or options.pop_heatmap_fitness:
+ conn = sqlite3.connect(options.dbfile)
+ conn.row_factory = sqlite3.Row
+ c = conn.cursor()
+
+ if options.genrange:
+ genrange = options.genrange.split(":")
+ ret = c.execute("select distinct generation from population where identify = ? and generation between ? and ?", (options.identify, genrange[0], genrange[1]))
+ else:
+ ret = c.execute("select distinct generation from population where identify = ?", (options.identify,))
+
+ generations = ret.fetchall()
+ if len(generations) <= 0:
+ print "No generation data found for the identify '%s' !" % (options.identify,)
+ exit()
+
+ all = []
+ for gen in generations:
+ pop_tmp = []
+
+ if options.lindrange:
+ individual_range = options.lindrange.split(":")
+ ret = c.execute("""
+ select * from population
+ where identify = ?
+ and generation = ?
+ and individual between ? and ?
+ """, (options.identify, gen[0], individual_range[0], individual_range[1]))
+ else:
+ ret = c.execute("""
+ select * from population
+ where identify = ?
+ and generation = ?
+ """, (options.identify, gen[0]))
+
+ ret_fetch = ret.fetchall()
+ for it in ret_fetch:
+ if options.pop_heatmap_raw:
+ pop_tmp.append(it["raw"])
+ else:
+ pop_tmp.append(it["fitness"])
+ all.append(pop_tmp)
+
+ ret.close()
+ conn.close()
+
+ if len(all) <= 0:
+ print "No statistic data found for the identify '%s' !" % (options.identify,)
+ exit()
+
+ print "%d generations found !" % (len(all),)
+
+ popGraph = True
+
+
+ if len(identify_list) == 1 and not popGraph:
+ if options.compare_raw or options.compare_fitness:
+ parser.error("You can't use this graph type with only one identify !")
+
+ conn = sqlite3.connect(options.dbfile)
+ conn.row_factory = sqlite3.Row
+ c = conn.cursor()
+
+ if options.genrange:
+ genrange = options.genrange.split(":")
+ ret = c.execute("select * from statistics where identify = ? and generation between ? and ?", (options.identify, genrange[0], genrange[1]))
+ else:
+ ret = c.execute("select * from statistics where identify = ?", (options.identify,))
+
+ all = ret.fetchall()
+
+ ret.close()
+ conn.close()
+
+ if len(all) <= 0:
+ print "No statistic data found for the identify '%s' !" % (options.identify,)
+ exit()
+
+ print "%d generations found !" % (len(all),)
+
+ elif len(identify_list) > 1 and not popGraph:
+ all = []
+ if (not options.compare_raw) and (not options.compare_fitness):
+ parser.error("You can't use many ids with this graph type !")
+
+ conn = sqlite3.connect(options.dbfile)
+ conn.row_factory = sqlite3.Row
+ c = conn.cursor()
+ for item in identify_list:
+ if options.genrange:
+ genrange = options.genrange.split(":")
+ ret = c.execute("select * from statistics where identify = ? and generation between ? and ?", (item, genrange[0], genrange[1]))
+ else:
+ ret = c.execute("select * from statistics where identify = ?", (item,))
+ fetchall = ret.fetchall()
+ if len(fetchall) > 0:
+ all.append(fetchall)
+
+ ret.close()
+ conn.close()
+
+ if len(all) <= 0:
+ print "No statistic data found for the identify list '%s' !" % (options.identify,)
+ exit()
+
+ print "%d identify found !" % (len(all),)
+
+ if options.errorbars_raw:
+ if options.outfile: graph_errorbars_raw(all, options.minimize, options.outfile + "." + options.extension)
+ else: graph_errorbars_raw(all, options.minimize)
+
+ if options.errorbars_fitness:
+ if options.outfile: graph_errorbars_fitness(all, options.minimize, options.outfile + "." + options.extension)
+ else: graph_errorbars_fitness(all, options.minimize)
+
+ if options.maxmin_raw:
+ if options.outfile: graph_maxmin_raw(all, options.minimize, options.outfile + "." + options.extension)
+ else: graph_maxmin_raw(all, options.minimize)
+
+ if options.maxmin_fitness:
+ if options.outfile: graph_maxmin_fitness(all, options.minimize, options.outfile + "." + options.extension)
+ else: graph_maxmin_fitness(all, options.minimize)
+
+ if options.diff_raw:
+ if options.outfile: graph_diff_raw(all, options.minimize, options.outfile + "." + options.extension)
+ else: graph_diff_raw(all, options.minimize)
+
+ if options.all_graphs:
+ all_graph_functions = [graph_errorbars_raw, graph_errorbars_fitness, graph_maxmin_raw,
+ graph_maxmin_fitness, graph_diff_raw]
+ if options.outfile:
+ parser.error("You can't specify one file to all graphs !")
+
+ dirname = "graphs_" + options.identify
+ if not os.path.isdir(dirname):
+ os.mkdir(dirname)
+
+ for graph in all_graph_functions:
+ filename = dirname + "/"
+ filename += options.identify + "_" + graph.__name__[6:]
+ filename += "." + options.extension
+ graph(all, options.minimize, filename)
+
+ print "\n\tDone ! The graphs was saved in the directory '%s'" % (dirname)
+
+ if options.compare_raw:
+ if options.outfile: graph_compare_raw(all, options.minimize, identify_list, options.outfile + "." + options.extension)
+ else: graph_compare_raw(all, options.minimize, identify_list )
+
+ if options.compare_fitness:
+ if options.outfile: graph_compare_fitness(all, options.minimize, identify_list, options.outfile + "." + options.extension)
+ else: graph_compare_fitness(all, options.minimize, identify_list )
+
+ if options.pop_heatmap_raw:
+ if options.outfile: graph_pop_heatmap_raw(all, options.minimize, options.colormap, options.outfile + "." + options.extension)
+ else: graph_pop_heatmap_raw(all, options.minimize, options.colormap)
+
+ if options.pop_heatmap_fitness:
+ if options.outfile: graph_pop_heatmap_fitness(all, options.minimize, options.colormap, options.outfile + "." + options.extension)
+ else: graph_pop_heatmap_fitness(all, options.minimize, options.colormap)
+
+
+
diff --git a/pylintrc.conf b/pylintrc.conf
new file mode 100644
index 0000000..4003d4c
--- /dev/null
+++ b/pylintrc.conf
@@ -0,0 +1,309 @@
+# lint Python modules using external checkers.
+#
+# This is the main checker controlling the other ones and the reports
+# generation. It is itself both a raw checker and an astng checker in order
+# to:
+# * handle message activation / deactivation at the module level
+# * handle some basic but necessary stats'data (number of classes, methods...)
+#
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add <file or directory> to the black list. It should be a base name, not a
+# path. You may set this option multiple times.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Set the cache size for astng objects.
+cache-size=500
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable only checker(s) with the given id(s). This option conflicts with the
+# disable-checker option
+#enable-checker=
+
+# Enable all checker(s) except those with the given id(s). This option
+# conflicts with the enable-checker option
+#disable-checker=
+
+# Enable all messages in the listed categories (IRCWEF).
+#enable-msg-cat=
+
+# Disable all messages in the listed categories (IRCWEF).
+disable-msg-cat=I
+
+# Enable the message(s) with the given id(s).
+#enable-msg=
+
+# Disable the message(s) with the given id(s).
+disable-msg=W0704,W0311,C0301,C0103,C0321,R0902,R0903,W0105,C0322,C0324,R0904
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html
+output-format=html
+
+# Include message's id in output
+include-ids=yes
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells wether to display a full report or only the messages
+reports=yes
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectivly contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (R0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (R0004).
+comment=no
+
+# Enable the report(s) with the given id(s).
+#enable-report=
+
+# Disable the report(s) with the given id(s).
+#disable-report=
+
+
+# checks for :
+# * doc strings
+# * modules / classes / functions / methods / arguments / variables name
+# * number of arguments, local variables, branchs, returns and statements in
+# functions, methods
+# * required module attributes
+# * dangerous default values as arguments
+# * redefinition of function / method / class
+# * uses of the global statement
+#
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# Regular expression which should only match functions or classes name which do
+# not require a docstring
+no-docstring-rgx=__.*__
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+
+# try to find bugs in the code using type inference
+#
+[TYPECHECK]
+
+# Tells wether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamicaly set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+# checks for
+# * unused variables / imports
+# * undefined variables
+# * redefinition of variable from builtins or from an outer scope
+# * use of variable before assigment
+#
+[VARIABLES]
+
+# Tells wether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching names used for dummy variables (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+# checks for :
+# * methods without self as first argument
+# * overridden methods signature
+# * access only to existant members via self
+# * attributes not defined in the __init__ method
+# * supported interfaces implementation
+# * unreachable code
+#
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+
+# checks for sign of poor/misdesign:
+# * number of methods, attributes, local variables...
+# * size, complexity of functions, methods
+#
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branchs=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+# checks for
+# * external modules dependencies
+# * relative / wildcard imports
+# * cyclic imports
+# * uses of deprecated modules
+#
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report R0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report R0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report R0402 must
+# not be disabled)
+int-import-graph=
+
+
+# checks for :
+# * unauthorized constructions
+# * strict indentation
+# * line length
+# * use of <> instead of !=
+#
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+
+# checks for:
+# * warning notes in the code like FIXME, XXX
+# * PEP 263: source code with non ascii character but no encoding declaration
+#
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+# checks for similarities and duplicated code. This computation may be
+# memory / CPU intensive, so you should disable it if you experiments some
+# problems.
+#
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
diff --git a/run_pylint.bat b/run_pylint.bat
new file mode 100644
index 0000000..6de4b8f
--- /dev/null
+++ b/run_pylint.bat
@@ -0,0 +1,2 @@
+ at echo off
+pylint --rcfile=pylintrc.conf pyevolve >errors.html
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..cc091cb
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,18 @@
+from setuptools import setup, find_packages
+from pyevolve import __version__, __author__
+
+setup(
+ name = "Pyevolve",
+ version = __version__,
+ packages = ["pyevolve"],
+ scripts = ['pyevolve_graph.py'],
+ package_data = {
+ 'pyevolve': ['*.txt']
+ },
+ author = __author__,
+ author_email = "christian.perone at gmail.com",
+ description = "A complete, free and open-source evolutionary framework written in Python",
+ license = "PSF",
+ keywords = "genetic algorithm genetic programming algorithms framework library python ai evolutionary framework",
+ url = "http://pyevolve.sourceforge.net/"
+)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pyevolve.git
More information about the debian-science-commits
mailing list