SingleNodeCrossover.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.1.0).
003  * Copyright (c) 2007-2019 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.ext;
021 
022 import static java.lang.String.format;
023 
024 import java.util.Random;
025 
026 import io.jenetics.util.ISeq;
027 import io.jenetics.util.RandomRegistry;
028 
029 import io.jenetics.ext.util.TreeNode;
030 
031 /**
032  * Swaps two, randomly chosen, nodes (sub-trees) from two given trees.
033  <pre> {@code
034  *     Tree A                 Tree B
035  *   0                      a
036  *   ├── 1                  ├── b
037  *   │   ├── 4              │   ├── e
038  *   │   └── 5              │   └── f
039  *   ├── 2                  ├── c
040  *   │   └── 6              │   └── g
041  *   └── 3                  └── d
042  *       ├── 7                  ├── h
043  *       │   ├── 10             │   ├── k
044  *       │   └── 11             │   └── l
045  *       ├── 8                  ├── i
046  *       └── 9                  └── j
047  *
048  *     Swap node "3" of A with node "c" of B
049  *
050  *   0                      a
051  *   ├── 1                  ├── b
052  *   │   ├── 4              │   ├── e
053  *   │   └── 5              │   └── f
054  *   ├── 2                  ├── 3
055  *   │   └── 6              │   ├── 7
056  *   └── c                  │   │   ├── 10
057  *       └── g              │   │   └── 11
058  *                          │   ├── 8
059  *                          │   └── 9
060  *                          └── d
061  *                              ├── h
062  *                              │   ├── k
063  *                              │   └── l
064  *                              ├── i
065  *                              └── j
066  * }</pre>
067  *
068  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
069  @version 5.0
070  @since 3.9
071  */
072 public class SingleNodeCrossover<
073     extends TreeGene<?, G>,
074     extends Comparable<? super C>
075 >
076     extends TreeCrossover<G, C>
077 {
078 
079     public SingleNodeCrossover(double probability) {
080         super(probability);
081     }
082 
083     public SingleNodeCrossover() {
084         this(DEFAULT_ALTER_PROBABILITY);
085     }
086 
087     @Override
088     protected <A> int crossover(final TreeNode<A> that, final TreeNode<A> other) {
089         return swap(that, other);
090     }
091 
092     // The static method makes it easier to test.
093     static <A> int swap(final TreeNode<A> that, final TreeNode<A> other) {
094         assert that != null;
095         assert other != null;
096 
097         final Random random = RandomRegistry.getRandom();
098 
099         final ISeq<TreeNode<A>> seq1 = that.breadthFirstStream()
100             .collect(ISeq.toISeq());
101 
102         final ISeq<TreeNode<A>> seq2 = other.breadthFirstStream()
103             .collect(ISeq.toISeq());
104 
105         final int changed;
106         if (seq1.length() && seq2.length() 1) {
107             final TreeNode<A> n1 = seq1.get(random.nextInt(seq1.length() 11);
108             final TreeNode<A> p1 = n1.getParent().orElseThrow(AssertionError::new);
109 
110             final TreeNode<A> n2 = seq2.get(random.nextInt(seq2.length() 11);
111             final TreeNode<A> p2 = n2.getParent().orElseThrow(AssertionError::new);
112 
113             final int i1 = p1.indexOf(n1);
114             final int i2 = p2.indexOf(n2);
115 
116             p1.insert(i1, n2.detach());
117             p2.insert(i2, n1.detach());
118 
119             changed = 2;
120         else {
121             changed = 0;
122         }
123 
124         return changed;
125     }
126 
127     @Override
128     public String toString() {
129         return format("SingleNodeCrossover[%f]", _probability);
130     }
131 
132 }