All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.teavm.common.GraphIndexer Maven / Gradle / Ivy

There is a newer version: 0.10.2
Show newest version
/*
 *  Copyright 2011 Alexey Andreev.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.teavm.common;

import com.carrotsearch.hppc.IntArrayList;
import com.carrotsearch.hppc.IntHashSet;
import com.carrotsearch.hppc.IntSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class GraphIndexer {
    static final byte NONE = 0;
    static final byte VISITING = 1;
    static final byte VISITED = 2;
    private int[] indexToNode;
    private int[] nodeToIndex;
    private Graph graph;
    private DominatorTree domTree;
    private int lastIndex;
    private int[] weights;
    private int[] priorities;

    public GraphIndexer(Graph graph, int[] weights, int[] priorities) {
        int sz = graph.size();
        this.weights = weights.clone();
        propagateWeights(graph, this.weights);
        this.priorities = priorities.clone();
        propagatePriorities(graph, this.priorities);
        indexToNode = new int[sz + 1];
        nodeToIndex = new int[sz + 1];
        Arrays.fill(nodeToIndex, -1);
        Arrays.fill(indexToNode, -1);
        this.graph = graph;
        domTree = GraphUtils.buildDominatorTree(graph);
        sort(graph);
        --lastIndex;
        for (int node = 0; node < sz; ++node) {
            int index = nodeToIndex[node];
            if (index < 0) {
                continue;
            }
            index = lastIndex - index;
            nodeToIndex[node] = index;
            indexToNode[index] = node;
        }
        indexToNode[sz] = sz;
        nodeToIndex[sz] = sz;
        GraphBuilder sorted = new GraphBuilder(lastIndex + 2);
        for (int i = 0; i <= lastIndex; ++i) {
            for (int next : graph.outgoingEdges(indexToNode[i])) {
                sorted.addEdge(i, nodeToIndex[next]);
            }
        }
        this.graph = sorted.build();
    }

    private void propagateWeights(Graph graph, int[] weights) {
        int sz = graph.size();
        byte[] state = new byte[sz];
        IntegerStack stack = new IntegerStack(sz * 2);
        stack.push(0);
        while (!stack.isEmpty()) {
            int node = stack.pop();
            switch (state[node]) {
                case VISITING:
                    state[node] = VISITED;
                    for (int succ : graph.outgoingEdges(node)) {
                        if (state[succ] == VISITED) {
                            weights[node] += weights[succ];
                        }
                    }
                    break;
                case NONE:
                    state[node] = VISITING;
                    stack.push(node);
                    for (int succ : graph.outgoingEdges(node)) {
                        if (state[succ] == NONE) {
                            stack.push(succ);
                        }
                    }
                    break;
            }
        }
    }

    private void propagatePriorities(Graph graph, int[] priorities) {
        boolean allZero = true;
        for (int i = 0; i < priorities.length; ++i) {
            if (priorities[i] != 0) {
                allZero = false;
                break;
            }
        }
        if (allZero) {
            return;
        }

        DominatorTree domTree = GraphUtils.buildDominatorTree(graph);
        Graph domGraph = GraphUtils.buildDominatorGraph(domTree, graph.size());
        IntegerStack stack = new IntegerStack(graph.size() * 2);
        for (int i = 0; i < domGraph.size(); ++i) {
            if (domGraph.outgoingEdgesCount(i) == 0) {
                stack.push(i);
            }
        }
        while (!stack.isEmpty()) {
            int node = stack.pop();
            int parent = domTree.immediateDominatorOf(node);
            if (parent < 0) {
                continue;
            }
            if (priorities[parent] < priorities[node]) {
                priorities[parent] = priorities[node];
                stack.push(parent);
            }
        }
    }

    private void sort(Graph graph) {
        int sz = graph.size();
        byte[] state = new byte[sz];
        IntegerStack stack = new IntegerStack(sz * 2);
        stack.push(0);
        while (!stack.isEmpty()) {
            int node = stack.pop();
            switch (state[node]) {
                case VISITING: {
                    state[node] = VISITED;
                    nodeToIndex[node] = lastIndex++;
                    break;
                }
                case NONE: {
                    state[node] = VISITING;
                    stack.push(node);
                    IntegerArray terminalNodes = new IntegerArray(1);
                    for (int pred : graph.incomingEdges(node)) {
                        if (domTree.dominates(node, pred)) {
                            terminalNodes.add(pred);
                        }
                    }
                    int[] successors = graph.outgoingEdges(node);
                    List succList = new ArrayList<>(successors.length);
                    IntegerArray orderedSuccessors = new IntegerArray(successors.length);
                    if (terminalNodes.size() > 0) {
                        int[] loopNodeList = findNaturalLoop(node, terminalNodes.getAll());
                        IntSet loopNodes = IntHashSet.from(loopNodeList);
                        for (int succ : successors) {
                            if (loopNodes.contains(succ)) {
                                succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
                            }
                        }
                        Collections.sort(succList);
                        for (WeightedNode wnode : succList) {
                            orderedSuccessors.add(wnode.index);
                        }

                        IntSet outerSuccessors = new IntHashSet(successors.length);
                        succList.clear();
                        for (int loopNode : loopNodeList) {
                            for (int succ : graph.outgoingEdges(loopNode)) {
                                if (!loopNodes.contains(succ)) {
                                    if (outerSuccessors.add(succ)) {
                                        succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
                                    }
                                }
                            }
                        }
                        Collections.sort(succList);
                        for (WeightedNode wnode : succList) {
                            orderedSuccessors.add(wnode.index);
                        }
                    } else {
                        for (int succ : successors) {
                            succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
                        }
                        Collections.sort(succList);
                        for (WeightedNode wnode : succList) {
                            orderedSuccessors.add(wnode.index);
                        }
                    }
                    successors = orderedSuccessors.getAll();
                    for (int succ : successors) {
                        if (state[succ] == NONE) {
                            stack.push(succ);
                        }
                    }
                    break;
                }
            }
        }
    }

    private int[] findNaturalLoop(int head, int[] terminals) {
        IntSet loop = new IntHashSet();
        IntArrayList loopList = new IntArrayList();
        loop.add(head);
        loopList.add(head);
        IntegerStack stack = new IntegerStack(1);
        for (int pred : terminals) {
            stack.push(pred);
        }
        while (!stack.isEmpty()) {
            int node = stack.pop();
            if (!loop.add(node)) {
                continue;
            }
            loopList.add(node);
            for (int pred : graph.incomingEdges(node)) {
                stack.push(pred);
            }
        }
        return loopList.toArray();
    }

    public int nodeAt(int index) {
        return indexToNode[index];
    }

    public int indexOf(int node) {
        return nodeToIndex[node];
    }

    public int size() {
        return indexToNode.length - 1;
    }

    public Graph getGraph() {
        return graph;
    }

    static class WeightedNode implements Comparable {
        int index;
        int priority;
        int weight;

        public WeightedNode(int index, int priority, int weight) {
            this.index = index;
            this.priority = priority;
            this.weight = weight;
        }

        @Override
        public int compareTo(WeightedNode o) {
            int r = Integer.compare(priority, o.priority);
            if (r != 0) {
                return r;
            }
            return Integer.compare(weight, o.weight);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy