public double tryRemoveFakeEdge(double temp, double currentEnergy) { if (fakeEdges.size() > 0) { PEdge<V, E> choice = fakeEdges.get(random.nextInt(fakeEdges.size())); ArrayList<PEdge<V, E>> toBeRemoved = new ArrayList<PEdge<V, E>>(); if (Math.random() < 0.5) { // remove single edge toBeRemoved.add(choice); } else { for (PEdge<V, E> parent : choice.to.getParents()) { if (parent.isFake && !parent.from.isRoot) { toBeRemoved.add(parent); } } } ArrayList<Integer> positions = new ArrayList<Integer>(toBeRemoved.size()); for (PEdge<V, E> fakeEdge : toBeRemoved) { int position = fakeEdge.from.getChildren().indexOf(fakeEdge); fakeEdge.from.getChildren().remove(position); positions.add(position); fakeEdge.to.removeParent(fakeEdge); } double newEnergy = getEnergy(); if (acceptChange(currentEnergy, newEnergy, temp)) { fakeEdges.removeAll(toBeRemoved); return newEnergy; } else { for (int i = positions.size() - 1; i >= 0; i--) { PEdge<V, E> fakeEdge = toBeRemoved.get(i); fakeEdge.from.getChildren().add(positions.get(i), fakeEdge); fakeEdge.to.addParent(fakeEdge); } return currentEnergy; } } return currentEnergy; }
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 double getEnergy() { fillTmpLGraph(); double energy = tmpLGraph.getNumberOfIntersections(); // energy += 1 - Math.exp(-Math.sqrt(lgraph.getNumberOfDummyNodes())); // removing // intersections has strict priority energy += 0.5 * tmpLGraph.getNumberOfDummyNodes() / (double) nodes.size(); energy += 0.2 * Math.sqrt(tmpLGraph.getDensityMeasure()); return energy; }
public boolean acceptChange(double oldEnergy, double newEnergy, double temp) { if (newEnergy < oldEnergy) return true; return Math.exp((oldEnergy - newEnergy) / temp) > Math.random(); }