public double runSimulatedAnnealing(int iterations) { if (!locked) lock(); double temp = 1; double coolingFactor = Math.pow(0.001, 1d / iterations); double currentEnergy = getEnergy(); if (nodes.isEmpty()) return currentEnergy; Collections.shuffle(nodesWithSeveralChildrenScaled, random); Collections.shuffle(sourceFakeEdges, random); while (temp > 0.001) { double action = random.nextDouble(); if (action < 0.19) { // add fake edge currentEnergy = tryAddFakeEdge(temp, currentEnergy); assert currentEnergy == getEnergy(); } else if (action < 0.36) { // remove fake edge (slightly higher probability - we don't want too many fake // edges) - update: apparently, that hypothesis is wrong currentEnergy = tryRemoveFakeEdge(temp, currentEnergy); assert currentEnergy == getEnergy(); } else if (action < 0.7) { // swap two children of some node currentEnergy = trySwapChildren(temp, currentEnergy); assert currentEnergy == getEnergy(); } else { // change where one of the sources is attached to currentEnergy = tryChangeSource(temp, currentEnergy); assert currentEnergy == getEnergy(); } temp *= coolingFactor; } return currentEnergy; }
public double tryChangeSource(double temp, double currentEnergy) { PEdge<V, E> fakeEdge = sourceFakeEdges.get(random.nextInt(sourceFakeEdges.size())); PNode<V, E> child = fakeEdge.to; int oldIndex = fakeEdge.from.getChildren().indexOf(fakeEdge); child.removeParent(fakeEdge); fakeEdge.from.removeChild(fakeEdge); PEdge<V, E> fakeEdge2; int fakeEdge2Swap = -1; if (fakeEdge.from.isRoot || random.nextDouble() < 0.4) { // try attaching it somewhere else PNode<V, E> parent; if (Math.random() < 0.5 || nodesWithSeveralChildrenScaled.size() == 0) { // try some completely random node parent = nodes.get(random.nextInt(nodes.size())); } else { parent = nodesWithSeveralChildrenScaled.get( random.nextInt(nodesWithSeveralChildrenScaled.size())); } fakeEdge2 = new PEdge<V, E>(parent, child); parent.addChild(fakeEdge2); if (parent.getChildren().size() > 1) { fakeEdge2Swap = random.nextInt(parent.getChildren().size() - 1); parent.swapChildren(parent.getChildren().size() - 1, fakeEdge2Swap); } child.addParent(fakeEdge2); } else { // try attaching it back to root. fakeEdge2 = new PEdge<V, E>(root, child); root.addChild(fakeEdge2); if (root.getChildren().size() > 1) { fakeEdge2Swap = random.nextInt(root.getChildren().size() - 1); root.swapChildren(root.getChildren().size() - 1, fakeEdge2Swap); } child.addParent(fakeEdge2); } if (!graphHasCycle(fakeEdge2.to)) { double newEnergy = getEnergy(); if (acceptChange(currentEnergy, newEnergy, temp)) { sourceFakeEdges.remove(fakeEdge); sourceFakeEdges.add(fakeEdge2); return newEnergy; } } fakeEdge2.from.removeChild(fakeEdge2); child.removeParent(fakeEdge2); if (fakeEdge2Swap != -1) { PEdge<V, E> e = fakeEdge2.from.getChildren().get(fakeEdge2.from.getChildren().size() - 1); fakeEdge2.from.getChildren().remove(fakeEdge2.from.getChildren().size() - 1); fakeEdge2.from.getChildren().add(fakeEdge2Swap, e); } // fakeEdge.from.addChild(fakeEdge); fakeEdge.from.getChildren().add(oldIndex, fakeEdge); child.addParent(fakeEdge); return currentEnergy; }
public static int quadraticRandint(int limit) { // return (int)(random.nextDouble() * limit); return (int) (random.nextDouble() * random.nextDouble() * limit); // return 0; }