Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Jenetics | 771 | 101 | 6 | a month ago | 20 | June 15, 2022 | 33 | apache-2.0 | Java | |
Jenetics - Genetic Algorithm, Genetic Programming, Grammatical Evolution, Evolutionary Algorithm, and Multi-objective Optimization | ||||||||||
Eaopt | 721 | 2 | 2 years ago | 3 | April 23, 2021 | 6 | mit | Go | ||
:four_leaf_clover: Evolutionary optimization library for Go (genetic algorithm, partical swarm optimization, differential evolution) | ||||||||||
Procedural Painting | 384 | a year ago | 1 | mit | C# | |||||
Procedural painting algorithms in Unity 3d with compute shaders based on genetic evolution algorithms | ||||||||||
Moeaframework | 289 | 18 | 2 | 2 months ago | 13 | December 09, 2022 | other | Java | ||
A Free and Open Source Java Framework for Multiobjective Optimization | ||||||||||
Piecewise_linear_fit_py | 218 | 1 | 3 | 6 months ago | 53 | May 01, 2022 | 33 | mit | Python | |
fit piecewise linear data for a specified number of line segments | ||||||||||
Autogoal | 190 | 6 months ago | 32 | mit | Python | |||||
A Python framework for program synthesis with a focus on Automated Machine Learning. | ||||||||||
Yabox | 127 | 6 months ago | 6 | June 01, 2020 | 7 | apache-2.0 | Jupyter Notebook | |||
Yet another black-box optimization library for Python | ||||||||||
Evokit | 57 | 2 years ago | other | Rust | ||||||
Modest Py | 42 | a year ago | 11 | June 12, 2022 | 3 | bsd-2-clause | Python | |||
FMI-compliant Model Estimation in Python | ||||||||||
Evolve | 38 | 8 years ago | 2 | mit | PHP | |||||
Image evolution |
Jenetics is a Genetic Algorithm, Evolutionary Algorithm, Grammatical Evolution, Genetic Programming, and Multi-objective Optimization library, written in modern day Java. It is designed with a clear separation of the several concepts of the algorithm, e.g. Gene
, Chromosome
, Genotype
, Phenotype
, Population
and fitness Function
. Jenetics allows you to minimize and maximize the given fitness function without tweaking it. In contrast to other GA implementations, the library uses the concept of an evolution stream (EvolutionStream
) for executing the evolution steps. Since the EvolutionStream
implements the Java Stream interface, it works smoothly with the rest of the Java Stream API.
Other languages
The library is fully documented (javadoc) and comes with an user manual (pdf).
Jenetics requires at least Java 17 to compile and run. It also compiles and runs with Java 20.
Check out the master branch from GitHub.
$ git clone https://github.com/jenetics/jenetics.git <builddir>
Jenetics uses Gradle as build system and organizes the source into sub-projects (modules). Each subproject is located in its own subdirectory:
Published projects
The following projects/modules are also published to Maven.
EvolutionStream
and evolution Engine
.Non-published projects
For building the library change into the <builddir>
directory (or one of the module directory) and call one of the available tasks:
<builddir>/<module-dir>/build/classes/main
directory.<builddir>/<module-dir>/build/libs
directory.<builddir>/<module-dir>/build/docs
directory<builddir>/<module-dir>
directory.<builddir>/build/*
directories and removes all generated artifacts.For building the library jar from the source call
$ cd <build-dir>
$ ./gradlew jar
The minimum evolution Engine setup needs a genotype factory, Factory<Genotype<?>>
, and a fitness Function
. The Genotype
implements the Factory
interface and can therefore be used as prototype for creating the initial Population
and for creating new random Genotypes
.
import io.jenetics.BitChromosome;
import io.jenetics.BitGene;
import io.jenetics.Genotype;
import io.jenetics.engine.Engine;
import io.jenetics.engine.EvolutionResult;
import io.jenetics.util.Factory;
public class HelloWorld {
// 2.) Definition of the fitness function.
private static Integer eval(Genotype<BitGene> gt) {
return gt.chromosome()
.as(BitChromosome.class)
.bitCount();
}
public static void main(String[] args) {
// 1.) Define the genotype (factory) suitable
// for the problem.
Factory<Genotype<BitGene>> gtf =
Genotype.of(BitChromosome.of(10, 0.5));
// 3.) Create the execution environment.
Engine<BitGene, Integer> engine = Engine
.builder(HelloWorld::eval, gtf)
.build();
// 4.) Start the execution (evolution) and
// collect the result.
Genotype<BitGene> result = engine.stream()
.limit(100)
.collect(EvolutionResult.toBestGenotype());
System.out.println("Hello World:\n" + result);
}
}
In contrast to other GA implementations, the library uses the concept of an evolution stream (EvolutionStream
) for executing the evolution steps. Since the EvolutionStream
implements the Java Stream interface, it works smoothly with the rest of the Java streaming API. Now let's have a closer look at listing above and discuss this simple program step by step:
The probably most challenging part, when setting up a new evolution Engine
, is to transform the problem domain into a appropriate Genotype
(factory) representation. In our example we want to count the number of ones of a BitChromosome
. Since we are counting only the ones of one chromosome, we are adding only one BitChromosome
to our Genotype
. In general, the Genotype
can be created with 1 to n chromosomes.
Once this is done, the fitness function which should be maximized, can be defined. Utilizing the new language features introduced in Java 8, we simply write a private static method, which takes the genotype we defined and calculate it's fitness value. If we want to use the optimized bit-counting method, bitCount()
, we have to cast the Chromosome<BitGene>
class to the actual used BitChromosome
class. Since we know for sure that we created the Genotype with a BitChromosome
, this can be done safely. A reference to the eval method is then used as fitness function and passed to the Engine.build
method.
In the third step we are creating the evolution Engine
, which is responsible for changing, respectively evolving, a given population. The Engine
is highly configurable and takes parameters for controlling the evolutionary and the computational environment. For changing the evolutionary behavior, you can set different alterers and selectors. By changing the used Executor
service, you control the number of threads, the Engine is allowed to use. An new Engine
instance can only be created via its builder, which is created by calling the Engine.builder
method.
In the last step, we can create a new EvolutionStream
from our Engine
. The EvolutionStream
is the model or view of the evolutionary process. It serves as a »process handle« and also allows you, among other things, to control the termination of the evolution. In our example, we simply truncate the stream after 100 generations. If you don't limit the stream, the EvolutionStream
will not terminate and run forever. Since the EvolutionStream
extends the java.util.stream.Stream
interface, it integrates smoothly with the rest of the Java Stream API. The final result, the best Genotype
in our example, is then collected with one of the predefined collectors of the EvolutionResult
class.
This example tries to approximate a given image by semitransparent polygons. It comes with an Swing UI, where you can immediately start your own experiments. After compiling the sources with
$ ./gradlew compileTestJava
you can start the example by calling
$ ./jrun io.jenetics.example.image.EvolvingImages
The previous image shows the GUI after evolving the default image for about 4,000 generations. With the »Open« button it is possible to load other images for polygonization. The »Save« button allows storing polygonized images in PNG format to disk. At the button of the UI, you can change some GA parameters of the example.
...
Codecs::ofSubSet::encode
method.BitChromosone::bitCount
returns wrong results for chromosome lengths <= 8.MathExpr
class. Replace ad-hoc parsing implementation.BitChromosome
methods: and
, or
, xor
, not
, shiftRight
, shiftLeft
.Tree::reduce
function. Allows to write code as follows:final Tree<String, ?> formula = TreeNode.parse(
"add(sub(6, div(230, 10)), mul(5, 6))",
String::trim
);
final double result = formula.reduce(new Double[0], (op, args) ->
switch (op) {
case "add" -> args[0] + args[1];
case "sub" -> args[0] - args[1];
case "mul" -> args[0] * args[1];
case "div" -> args[0] / args[1];
default -> Double.parseDouble(op);
}
);
The library is licensed under the Apache License, Version 2.0.
Copyright 2007-2023 Franz Wilhelmstötter
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.