diff --git a/README.md b/README.md index 94e0b7e..b71d8a9 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ First, you need to add the following repository, which is a repository that can ``` Than you can add the dependency on our `aitoa-code` repository into your `dependencies` section. -Here, `0.8.40` is the current version of `aitoa-code`. +Here, `0.8.41` is the current version of `aitoa-code`. Notice that you may have more dependencies in your `dependencies` section, say on `junit`, but here I just put the one for `aitoa-code` as example. ```xml @@ -52,7 +52,7 @@ Notice that you may have more dependencies in your `dependencies` section, say o com.github.thomasWeise aitoa-code - 0.8.40 + 0.8.41 ``` diff --git a/pom.xml b/pom.xml index d309cc5..c90c0ef 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ aitoa aitoa-code - 0.8.40 + 0.8.41 jar aitoa-code Example Source Codes from the Book "Introduction to Optimization Algorithms" @@ -203,7 +203,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.2 + 3.2.1 package diff --git a/src/main/java/aitoa/algorithms/EAWithPruning.java b/src/main/java/aitoa/algorithms/EAWithPruning.java index 2358fb9..74640a8 100644 --- a/src/main/java/aitoa/algorithms/EAWithPruning.java +++ b/src/main/java/aitoa/algorithms/EAWithPruning.java @@ -160,8 +160,8 @@ public final void solve(final IBlackBoxProcess process) { // we switch the two arrays here so the rest is the same as EA makeUnique: for (final Individual ind : P2) { ++done; - if ((unique <= 0) - || (ind.quality > P[unique - 1].quality)) { + if ((unique <= 0) || // + (ind.quality > P[unique - 1].quality)) { P[unique] = ind; if ((++unique) >= this.mu) { // we are done and can System.arraycopy(P2, done, P, unique, // copy the @@ -184,7 +184,8 @@ public final void solve(final IBlackBoxProcess process) { } final Individual dest = P[index]; - final Individual sel = P[(++p1) % unique]; + p1 = (p1 + 1) % unique; + final Individual sel = P[p1]; if ((unique >= 2) && (random.nextDouble() <= this.cr)) { int p2; // to hold index of second selected record do { // find a second, different record diff --git a/src/main/java/aitoa/algorithms/MA.java b/src/main/java/aitoa/algorithms/MA.java index 0db227e..46635f2 100644 --- a/src/main/java/aitoa/algorithms/MA.java +++ b/src/main/java/aitoa/algorithms/MA.java @@ -156,7 +156,7 @@ public final void solve(final IBlackBoxProcess process) { if (newQuality < ind.quality) { // better? ind.quality = newQuality; // store quality searchSpace.copy(point, ind.x); // store point - return (true); // exit to next loop + return true; // exit to next loop } // if we get here, point is not better return process.shouldTerminate(); }); // repeat this until no improvement or time is diff --git a/src/main/java/aitoa/algorithms/MAWithPruning.java b/src/main/java/aitoa/algorithms/MAWithPruning.java index 043fcc7..99301fd 100644 --- a/src/main/java/aitoa/algorithms/MAWithPruning.java +++ b/src/main/java/aitoa/algorithms/MAWithPruning.java @@ -176,11 +176,10 @@ public final void solve(final IBlackBoxProcess process) { if (newQuality < ind.quality) { // better? ind.quality = newQuality; // store quality searchSpace.copy(point, ind.x); // store - return (true); // exit to next loop + return true; // exit to next loop } // if we get here, point is not better return process.shouldTerminate(); - }); // repeat this until no improvement or time - // is up + }); // repeat until no improvement or time up if (process.shouldTerminate()) { // we return return; // best solution is stored in process } @@ -198,8 +197,8 @@ public final void solve(final IBlackBoxProcess process) { // we switch the two arrays here so the rest is the same as EA makeUnique: for (final Individual ind : P2) { ++done; - if ((unique <= 0) - || (ind.quality > P[unique - 1].quality)) { + if ((unique <= 0) || // + (ind.quality > P[unique - 1].quality)) { P[unique] = ind; if ((++unique) >= this.mu) { // we are done and can System.arraycopy(P2, done, P, unique, // copy the @@ -224,7 +223,8 @@ public final void solve(final IBlackBoxProcess process) { return; // best solution is stored in process } final Individual dest = P[index]; - final Individual sel = P[(++p1) % unique]; + p1 = (p1 + 1) % unique; + final Individual sel = P[p1]; // to hold index of second selected record do { // find a second, different record p2 = random.nextInt(unique); diff --git a/src/main/java/aitoa/examples/jssp/EJSSPExperimentStage.java b/src/main/java/aitoa/examples/jssp/EJSSPExperimentStage.java index a7186fb..3cf3f87 100644 --- a/src/main/java/aitoa/examples/jssp/EJSSPExperimentStage.java +++ b/src/main/java/aitoa/examples/jssp/EJSSPExperimentStage.java @@ -638,6 +638,20 @@ public void configureBuilderForProblem( () -> new MA<>(64, 64, 100), // () -> new MAWithPruning<>(64, 64, 100), // // + () -> new MA<>(256, 256, Integer.MAX_VALUE), // + () -> new MAWithPruning<>(256, 256, Integer.MAX_VALUE), // + () -> new MA<>(256, 256, 10), // + () -> new MAWithPruning<>(256, 256, 10), // + () -> new MA<>(256, 256, 100), // + () -> new MAWithPruning<>(64, 64, 100), // + // + () -> new MA<>(1024, 1024, Integer.MAX_VALUE), // + () -> new MAWithPruning<>(1024, 1024, Integer.MAX_VALUE), // + () -> new MA<>(1024, 1024, 10), // + () -> new MAWithPruning<>(1024, 1024, 10), // + () -> new MA<>(1024, 1024, 100), // + () -> new MAWithPruning<>(1024, 1024, 100), // + // () -> new MA<>(4096, 4096, Integer.MAX_VALUE), // () -> new MAWithPruning<>(4096, 4096, Integer.MAX_VALUE), // () -> new MA<>(4096, 4096, 10), // diff --git a/src/main/java/aitoa/examples/jssp/JSSPUnaryOperator1SwapU.java b/src/main/java/aitoa/examples/jssp/JSSPUnaryOperator1SwapU.java index d7b39c0..549065e 100644 --- a/src/main/java/aitoa/examples/jssp/JSSPUnaryOperator1SwapU.java +++ b/src/main/java/aitoa/examples/jssp/JSSPUnaryOperator1SwapU.java @@ -28,7 +28,7 @@ public final class JSSPUnaryOperator1SwapU implements IUnarySearchOperator { // end relevant /** the indexes */ - private final int[] m_indexes; + final int[] m_indexes; /** * create the representation @@ -127,13 +127,13 @@ public final boolean enumerate(final Random random, // start relevant System.arraycopy(x, 0, dest, 0, dest.length); // copy x - // We move along the index-pair array and shuffle the indices - // on the way +// We move along the index-pair array and shuffle the indices on +// the way for (int i = 0, start = -1; i < pairCount; i++) { - // Get "a" and "b": the next, randomly chosen index pair. - // What we do here is basically an iterative version of the - // Fisher-Yates shuffle. +// Get "a" and "b": the next, randomly chosen index pair. +// What we do here is basically an iterative version of the +// Fisher-Yates shuffle. int swapWith = (i + random.nextInt(pairCount - i)) << 1; final int a = indexes[swapWith]; indexes[swapWith] = indexes[++start]; @@ -146,8 +146,8 @@ public final boolean enumerate(final Random random, final int job_j = dest[b];// the job at second index if (job_i != job_j) { - dest[b] = job_j; // then we swap the values - dest[a] = job_i; // and will then call the visitor + dest[a] = job_j; // then we swap the values + dest[b] = job_i; // and will then call the visitor if (visitor.test(dest)) { return true; // visitor says: stop -> return true } // visitor did not say stop, so we need to diff --git a/src/test/java/aitoa/examples/jssp/TestJSSPUnaryOperator1SwapU.java b/src/test/java/aitoa/examples/jssp/TestJSSPUnaryOperator1SwapU.java new file mode 100644 index 0000000..ba3cdf2 --- /dev/null +++ b/src/test/java/aitoa/examples/jssp/TestJSSPUnaryOperator1SwapU.java @@ -0,0 +1,184 @@ +package aitoa.examples.jssp; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +import org.junit.Assert; +import org.junit.Test; + +import aitoa.structure.ISpace; +import aitoa.structure.IUnarySearchOperator; +import aitoa.structure.IUnarySearchOperatorTest; + +/** test the unary 1-swap search operator */ +public class TestJSSPUnaryOperator1SwapU + extends IUnarySearchOperatorTest { + + /** the space we use */ + private static final JSSPInstance PROBLEM = + new JSSPInstance("yn2"); //$NON-NLS-1$ + + /** the space we use */ + private static final JSSPSearchSpace SPACE = + new JSSPSearchSpace(TestJSSPUnaryOperator1SwapU.PROBLEM); + + /** the operator we use */ + private static final JSSPUnaryOperator1SwapU OP = + new JSSPUnaryOperator1SwapU( + TestJSSPUnaryOperator1SwapU.PROBLEM); + + /** {@inheritDoc} */ + @Override + protected ISpace getSpace() { + return TestJSSPUnaryOperator1SwapU.SPACE; + } + + /** {@inheritDoc} */ + @Override + protected IUnarySearchOperator + getOperator(final ISpace space) { + return TestJSSPUnaryOperator1SwapU.OP; + } + + /** {@inheritDoc} */ + @Override + protected boolean equals(final int[] a, final int[] b) { + return Arrays.equals(a, b); + } + + /** {@inheritDoc} */ + @Override + protected int[] createValid() { + return JSSPTestUtils + .createValidX(TestJSSPUnaryOperator1SwapU.PROBLEM); + } + + /** + * check that all index pairs are unique + * + * @param op + * the operator + * @param test + * the test set + */ + private static final void __checkUnique( + final JSSPUnaryOperator1SwapU op, + final HashSet test) { + test.clear(); + for (int k = 0; k < op.m_indexes.length;) { + final long v = op.m_indexes[k++]; + final long w = op.m_indexes[k++]; + final long key = + (v < w) ? ((v << 32L) | w) : ((w << 32L) | v); + Assert.assertTrue(test.add(Long.valueOf(key))); + } + } + + /** test the application to the canonical instance */ + @SuppressWarnings("static-method") + @Test(timeout = 3600000) + public final void testCanonical() { + final Random random = ThreadLocalRandom.current(); + new HashSet<>(); + for (final JSSPInstance inst : JSSPTestUtils.INSTANCS) { + final JSSPUnaryOperator1SwapU op = + new JSSPUnaryOperator1SwapU(inst); + TestJSSPUnaryOperator1SwapU.__checkUnique(op, + new HashSet<>()); + final int[] x = new int[inst.m * inst.n]; + final int[] c = new int[inst.m * inst.n]; + JSSPTestUtils.canonicalX(c, inst); + final int[] c2 = c.clone(); + JSSPTestUtils.assertX(c2, inst); + for (int i = 1000; (--i) >= 0;) { + op.apply(c, x, random); + JSSPTestUtils.assertX(x, inst); + Assert.assertArrayEquals(c, c2); + } + } + } + + /** test the application to random instances */ + @SuppressWarnings("static-method") + @Test(timeout = 3600000) + public final void testRandom() { + final Random random = ThreadLocalRandom.current(); + for (final JSSPInstance inst : JSSPTestUtils.INSTANCS) { + final int[] x = new int[inst.m * inst.n]; + final int[] c = new int[inst.m * inst.n]; + final JSSPUnaryOperator1SwapU op = + new JSSPUnaryOperator1SwapU(inst); + TestJSSPUnaryOperator1SwapU.__checkUnique(op, + new HashSet<>()); + + for (int i = 1000; (--i) >= 0;) { + JSSPTestUtils.randomX(c, inst); + JSSPTestUtils.assertX(c, inst); + op.apply(c, x, random); + JSSPTestUtils.assertX(x, inst); + } + } + } + + /** test the number of unique outcomes */ + @SuppressWarnings("static-method") + @Test(timeout = 3600000) + public void testNumberOfUniqueOutcomes() { + final Random random = ThreadLocalRandom.current(); + final JSSPInstance inst = new JSSPInstance("demo"); //$NON-NLS-1$ + final int[] in = new int[inst.n * inst.m]; + final int[] out = new int[in.length]; + final int[][] unique = new int[(inst.n * inst.m + * (inst.n - 1) * inst.m) >>> 1][out.length]; + + new JSSPNullaryOperator(inst).apply(in, random); + final JSSPUnaryOperator1SwapU op = + new JSSPUnaryOperator1SwapU(inst); + int count = 0; + outer: for (int i = (50 * unique.length * unique.length); + (--i) >= 0;) { + op.apply(in, out, random); + for (int j = count; (--j) >= 0;) { + if (Arrays.equals(unique[j], out)) { + continue outer; + } + } + System.arraycopy(out, 0, unique[count++], 0, out.length); + } + + Assert.assertEquals(unique.length, count); + } + + /** + * test that the + * {@link IUnarySearchOperator#enumerate(java.util.Random, Object, Object, java.util.function.Predicate)} + * method works correctly and respects the return values of the + * visitor + */ + @SuppressWarnings({ "static-method", "unchecked" }) + @Test(timeout = 3600000) + public void testEnumerate2() { + final JSSPSearchSpace space = + TestJSSPUnaryOperator1SwapU.SPACE; + + final JSSPUnaryOperator1SwapU op = + TestJSSPUnaryOperator1SwapU.OP; + final Random random = ThreadLocalRandom.current(); + + final int[] src = this.createValid(); + final int[] dest = space.create(); + + final int[] copy = space.create(); + space.copy(src, copy); + + for (int i = 10; (--i) >= 0;) { + Assert.assertFalse( + op.enumerate(random, src, dest, (x) -> false)); + final HashSet set = new HashSet<>(); + TestJSSPUnaryOperator1SwapU.__checkUnique(op, set); + Assert.assertTrue(this.equals(src, copy)); + } + } +}