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 tryAddFakeEdge(double temp, double currentEnergy) { // it's sufficient to only add fake edges from leaves to nodes with multiple parents if (nodesWithoutChildren.size() > 0 && nodesWithSeveralParents.size() > 0) { PNode<V, E> from = nodesWithoutChildren.get(random.nextInt(nodesWithoutChildren.size())); PNode<V, E> to = nodesWithSeveralParents.get(random.nextInt(nodesWithSeveralParents.size())); PEdge<V, E> fakeEdge = new PEdge<V, E>(from, to); from.addChild(fakeEdge); to.addParent(fakeEdge); if (!graphHasCycle(to)) { double newEnergy = getEnergy(); if (acceptChange(currentEnergy, newEnergy, temp)) { fakeEdges.add(fakeEdge); return newEnergy; } } // otherwise undo changes from.removeChild(fakeEdge); to.removeParent(fakeEdge); return currentEnergy; } return currentEnergy; }
public double trySwapChildren(double temp, double currentEnergy) { if (nodesWithSeveralChildrenScaled.size() > 0) { PNode<V, E> parent = nodesWithSeveralChildrenScaled.get( quadraticRandint(nodesWithSeveralChildrenScaled.size())); nodesWithSeveralChildrenScaled.remove(parent); nodesWithSeveralChildrenScaled.add( parent); // move it to the end - less likely to be picked again in near future int numberOfChildren = parent.getChildren().size(); int i1 = random.nextInt(numberOfChildren); int i2 = random.nextInt(numberOfChildren - 1); i2 = i2 >= i1 ? i2 + 1 : i2; parent.swapChildren(i1, i2); double newEnergy = getEnergy(); if (acceptChange(currentEnergy, newEnergy, temp)) { return newEnergy; } else { parent.swapChildren(i1, i2); // swap back return currentEnergy; } } 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; }