Search in sources :

Example 1 with Node

use of au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node in project constellation by constellation-app.

the class InfomapGreedy method moveNodesToPredefinedModules.

@Override
protected void moveNodesToPredefinedModules() {
    if (DEBUG) {
        LOGGER.log(Level.INFO, "{0}.moveNodesToPredefinedModules", getClass().getSimpleName());
    }
    // Size of active network and cluster array should match.
    assert moveTo.size() == activeNetwork.size();
    final int numNodes = activeNetwork.size();
    if (DEBUG) {
        final String log = String.format("Begin moving %d nodes to predefined modules, starting with codelength %f...\n", numNodes, codelength);
        LOGGER.log(Level.INFO, log);
    }
    int numMoved = 0;
    for (int k = 0; k < numNodes; k++) {
        final Node current = getNode(activeNetwork.get(k));
        // == k
        final int oldM = current.getIndex();
        assert oldM == k;
        final int newM = moveTo.get(k);
        if (newM != oldM) {
            final DeltaFlow oldModuleDelta = new DeltaFlow(oldM, 0, 0);
            final DeltaFlow newModuleDelta = new DeltaFlow(newM, 0, 0);
            addTeleportationDeltaFlowOnOldModuleIfMove(current, oldModuleDelta);
            addTeleportationDeltaFlowOnNewModuleIfMove(current, newModuleDelta);
            // For all outlinks.
            for (final Edge<NodeBase> edge : current.getOutEdges()) {
                if (edge.isSelfPointing()) {
                    continue;
                }
                final int otherModule = edge.getTarget().getIndex();
                if (otherModule == oldM) {
                    oldModuleDelta.setDeltaExit(oldModuleDelta.getDeltaExit() + edge.getData().flow);
                } else if (otherModule == newM) {
                    newModuleDelta.setDeltaExit(newModuleDelta.getDeltaExit() + edge.getData().flow);
                } else {
                // Do nothing
                }
            }
            // For all inlinks.
            for (final Edge<NodeBase> edge : current.getInEdges()) {
                if (edge.isSelfPointing()) {
                    continue;
                }
                final int otherModule = edge.getSource().getIndex();
                if (otherModule == oldM) {
                    oldModuleDelta.setDeltaEnter(oldModuleDelta.getDeltaEnter() + edge.getData().flow);
                } else if (otherModule == newM) {
                    newModuleDelta.setDeltaEnter(newModuleDelta.getDeltaEnter() + edge.getData().flow);
                } else {
                // Do nothing
                }
            }
            // Update empty module vector.
            if (moduleMembers[newM] == 0) {
                // Remove last element.
                emptyModules.remove(emptyModules.size() - 1);
            }
            if (moduleMembers[oldM] == 1) {
                emptyModules.add(oldM);
            }
            updateCodelength(current, oldModuleDelta, newModuleDelta);
            moduleMembers[oldM] -= 1;
            moduleMembers[newM] += 1;
            current.setIndex(newM);
            numMoved++;
        }
    }
    if (DEBUG) {
        final String log = String.format("Done! Moved %d nodes into %d modules to codelength: %.5f\n", numMoved, getNumActiveModules(), codelength);
        LOGGER.log(Level.INFO, log);
    }
}
Also used : NodeBase(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.NodeBase) Node(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node)

Example 2 with Node

use of au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node in project constellation by constellation-app.

the class InfomapGreedy method initModuleOptimization.

@Override
protected void initModuleOptimization() {
    final int numNodes = activeNetwork.size();
    moduleFlowData = Resizer.resizeFlowBase(moduleFlowData, numNodes, treeData.getNodeFactory());
    moduleMembers = new int[numNodes];
    Arrays.fill(moduleMembers, 1);
    emptyModules = new ArrayList<>(numNodes);
    int i = 0;
    for (final NodeBase nodeBase : activeNetwork) {
        final Node node = getNode(nodeBase);
        // Unique module index for each node
        node.setIndex(i);
        moduleFlowData[i] = node.getData().copy();
        i++;
    }
    // Initiate codelength terms for the initial state of one module per node.
    calculateCodelengthFromActiveNetwork(hasDetailedBalance());
}
Also used : NodeBase(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.NodeBase) Node(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node)

Example 3 with Node

use of au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node in project constellation by constellation-app.

the class InfomapGreedy method tryMoveEachNodeIntoBestModule.

/**
 * Try to minimize the codelength by trying to move nodes into the same
 * modules as neighbouring nodes.
 *
 * For each node: 1. Calculate the change in codelength for a move to each
 * of its neighbouring modules or to an empty module 2. Move to the one that
 * reduces the codelength the most, if any.
 *
 * The first step would require O(d^2), where d is the degree, if
 * calculating the full change at each neighbour, but a special data
 * structure is used to accumulate the marginal effect of each link on its
 * target, giving O(d).
 *
 * @return The number of nodes moved.
 */
int tryMoveEachNodeIntoBestModule() {
    if (DEBUG) {
        LOGGER.log(Level.INFO, "{0}.tryMoveEachNodeIntoBestModule", getClass().getSimpleName());
    }
    final int numNodes = activeNetwork.size();
    dumpActiveNetwork("in");
    // Get random enumeration of nodes.
    final int[] randomOrder = new int[numNodes];
    InfoMath.getRandomizedIndexVector(randomOrder, rand);
    final DeltaFlow[] moduleDeltaEnterExit = new DeltaFlow[numNodes];
    Arrays.fill(moduleDeltaEnterExit, new DeltaFlow());
    final int[] redirect = new int[numNodes];
    Arrays.fill(redirect, 0);
    int offset = 1;
    final int maxOffset = Integer.MAX_VALUE - 1 - numNodes;
    int numMoved = 0;
    for (int i = 0; i < numNodes; i++) {
        // Reset offset before overflow.
        if (offset > maxOffset) {
            Arrays.fill(redirect, 0);
            offset = 1;
        }
        // Pick nodes in random order.
        final int flip = randomOrder[i];
        final Node current = getNode(activeNetwork.get(flip));
        // and others won't move into this. TODO: always best leave it alone?
        if (current.getDegree() == 0 || (config.isIncludeSelfLinks() && (current.getOutDegree() == 1 && current.getInDegree() == 1) && current.getOutEdges().get(0).getTarget().equals(current))) {
            LOGGER.log(Level.INFO, "SKIPPING isolated node {0}", current);
            // TODO: if not skipping self-links, this yields different results from moveNodesToPredefinedModules!!
            assert !config.isIncludeSelfLinks();
            continue;
        }
        // Create vector with module links.
        int numModuleLinks = 0;
        if (current.isDangling()) {
            redirect[current.getIndex()] = offset + numModuleLinks;
            moduleDeltaEnterExit[numModuleLinks].setModule(current.getIndex());
            moduleDeltaEnterExit[numModuleLinks].setDeltaExit(0);
            moduleDeltaEnterExit[numModuleLinks].setDeltaEnter(0);
            numModuleLinks++;
        } else {
            // For all outlinks.
            for (final Edge<NodeBase> edge : current.getOutEdges()) {
                if (edge.isSelfPointing()) {
                    continue;
                }
                final NodeBase neighbour = edge.getTarget();
                if (redirect[neighbour.getIndex()] >= offset) {
                    moduleDeltaEnterExit[redirect[neighbour.getIndex()] - offset].setDeltaExit(moduleDeltaEnterExit[redirect[neighbour.getIndex()] - offset].getDeltaExit() + edge.getData().flow);
                } else {
                    redirect[neighbour.getIndex()] = offset + numModuleLinks;
                    moduleDeltaEnterExit[numModuleLinks].setModule(neighbour.getIndex());
                    moduleDeltaEnterExit[numModuleLinks].setDeltaExit(edge.getData().flow);
                    moduleDeltaEnterExit[numModuleLinks].setDeltaEnter(0);
                    numModuleLinks++;
                }
            }
        }
        // For all inlinks.
        for (final Edge<NodeBase> edge : current.getInEdges()) {
            if (edge.isSelfPointing()) {
                continue;
            }
            final Node neighbour = getNode(edge.getSource());
            if (redirect[neighbour.getIndex()] >= offset) {
                moduleDeltaEnterExit[redirect[neighbour.getIndex()] - offset].setDeltaEnter(moduleDeltaEnterExit[redirect[neighbour.getIndex()] - offset].getDeltaEnter() + edge.getData().flow);
            } else {
                redirect[neighbour.getIndex()] = offset + numModuleLinks;
                moduleDeltaEnterExit[numModuleLinks].setModule(neighbour.getIndex());
                moduleDeltaEnterExit[numModuleLinks].setDeltaExit(0);
                moduleDeltaEnterExit[numModuleLinks].setDeltaEnter(edge.getData().flow);
                numModuleLinks++;
            }
        }
        // If alone in the module, add virtual link to the module (used when adding teleportation).
        if (redirect[current.getIndex()] < offset) {
            redirect[current.getIndex()] = offset + numModuleLinks;
            moduleDeltaEnterExit[numModuleLinks].setModule(current.getIndex());
            moduleDeltaEnterExit[numModuleLinks].setDeltaExit(0);
            moduleDeltaEnterExit[numModuleLinks].setDeltaEnter(0);
            numModuleLinks++;
        }
        // Empty function if no teleportation coding model.
        addTeleportationDeltaFlowIfMove(current, moduleDeltaEnterExit, numModuleLinks);
        // Option to move to empty module (if node not already alone).
        if (moduleMembers[current.getIndex()] > 1 && !emptyModules.isEmpty()) {
            moduleDeltaEnterExit[numModuleLinks].setModule(emptyModules.get(emptyModules.size() - 1));
            moduleDeltaEnterExit[numModuleLinks].setDeltaExit(0);
            moduleDeltaEnterExit[numModuleLinks].setDeltaEnter(0);
            numModuleLinks++;
        }
        // Store the DeltaFlow of the current module.
        final DeltaFlow oldModuleDelta = new DeltaFlow(moduleDeltaEnterExit[redirect[current.getIndex()] - offset]);
        if (DEBUG) {
            for (int j = 0; j < numModuleLinks - 1; ++j) {
                LOGGER.log(Level.INFO, "{0}", moduleDeltaEnterExit[j].getModule());
            }
        }
        // Randomize link order for optimized search.
        for (int j = 0; j < numModuleLinks - 1; ++j) {
            final int randPos = j + rand.randInt(numModuleLinks - j - 1);
            final DeltaFlow t = moduleDeltaEnterExit[j];
            moduleDeltaEnterExit[j] = moduleDeltaEnterExit[randPos];
            moduleDeltaEnterExit[randPos] = t;
        }
        DeltaFlow bestDeltaModule = new DeltaFlow(oldModuleDelta);
        double bestDeltaCodelength = 0;
        // Find the move that minimizes the description length.
        for (int j = 0; j < numModuleLinks; ++j) {
            final int otherModule = moduleDeltaEnterExit[j].getModule();
            if (otherModule != current.getIndex()) {
                double deltaCodelength = getDeltaCodelength(current, oldModuleDelta, moduleDeltaEnterExit[j]);
                if (deltaCodelength < bestDeltaCodelength) {
                    bestDeltaModule = new DeltaFlow(moduleDeltaEnterExit[j]);
                    bestDeltaCodelength = deltaCodelength;
                }
            }
        }
        // Make best possible move.
        if (bestDeltaModule.getModule() != current.getIndex()) {
            final int bestModuleIndex = bestDeltaModule.getModule();
            // Update empty module vector.
            if (moduleMembers[bestModuleIndex] == 0) {
                emptyModules.remove(emptyModules.size() - 1);
            }
            if (moduleMembers[current.getIndex()] == 1) {
                emptyModules.add(current.getIndex());
            }
            updateCodelength(current, oldModuleDelta, bestDeltaModule);
            moduleMembers[current.getIndex()] -= 1;
            moduleMembers[bestModuleIndex] += 1;
            current.setIndex(bestModuleIndex);
            numMoved++;
        }
        offset += numNodes;
    }
    dumpActiveNetwork("");
    return numMoved;
}
Also used : NodeBase(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.NodeBase) Node(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node)

Example 4 with Node

use of au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node in project constellation by constellation-app.

the class InfomapGreedy method calculateCodelengthFromActiveNetwork.

protected void calculateCodelengthFromActiveNetwork(final boolean detailedBalance) {
    if (DEBUG) {
        final String log = String.format("%s.calculateCodelengthFromActiveNetwork(%s)%n", getClass().getSimpleName(), detailedBalance);
        LOGGER.log(Level.INFO, log);
    }
    flowLogFlow = 0;
    exitLogExit = 0;
    enterFlow = 0;
    if (detailedBalance) {
        // For each module...
        for (final NodeBase nodeBase : activeNetwork) {
            final Node node = getNode(nodeBase);
            // Own node/module codebook.
            flowLogFlow += plogp(node.getData().getFlow() + node.getData().getExitFlow());
            // Use of index codebook.
            enterFlow += node.getData().getExitFlow();
            exitLogExit += plogp(node.getData().getExitFlow());
        }
        enterFlow += exitNetworkFlow;
        enterFlowLogEnterFlow = plogp(enterFlow);
        indexCodelength = enterFlowLogEnterFlow - exitLogExit - exitNetworkFlowLogExitNetworkFlow;
        moduleCodelength = -exitLogExit + flowLogFlow - nodeFlowLogNodeFlow;
        codelength = indexCodelength + moduleCodelength;
    } else {
        enterLogEnter = 0;
        // For each module...
        for (final NodeBase nodeBase : activeNetwork) {
            final Node node = getNode(nodeBase);
            // Own node/module codebook.
            flowLogFlow += plogp(node.getData().getFlow() + node.getData().getExitFlow());
            // Use of index codebook.
            enterLogEnter += plogp(node.getData().getEnterFlow());
            exitLogExit += plogp(node.getData().getExitFlow());
            enterFlow += node.getData().getEnterFlow();
        }
        enterFlow += exitNetworkFlow;
        enterFlowLogEnterFlow = plogp(enterFlow);
        indexCodelength = enterFlowLogEnterFlow - enterLogEnter - exitNetworkFlowLogExitNetworkFlow;
        moduleCodelength = -exitLogExit + flowLogFlow - nodeFlowLogNodeFlow;
        codelength = indexCodelength + moduleCodelength;
    }
}
Also used : NodeBase(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.NodeBase) Node(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node)

Example 5 with Node

use of au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node in project constellation by constellation-app.

the class InfomapGreedy method initConstantInfomapTerms.

@Override
protected void initConstantInfomapTerms() {
    nodeFlowLogNodeFlow = 0;
    // For each module...
    for (final NodeBase nodeBase : activeNetwork) {
        final Node node = getNode(nodeBase);
        nodeFlowLogNodeFlow += plogp(node.getData().getFlow());
    }
}
Also used : NodeBase(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.NodeBase) Node(au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node)

Aggregations

Node (au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.Node)6 NodeBase (au.gov.asd.tac.constellation.plugins.algorithms.clustering.infomap.NodeBase)6