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

org.neo4j.gds.labelpropagation.ComputeStepConsumer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.gds.labelpropagation;

import com.carrotsearch.hppc.LongDoubleScatterMap;
import com.carrotsearch.hppc.cursors.LongDoubleCursor;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.api.properties.relationships.RelationshipWithPropertyConsumer;
import org.neo4j.gds.collections.ha.HugeLongArray;

final class ComputeStepConsumer implements RelationshipWithPropertyConsumer {

    private final NodePropertyValues nodeWeights;
    private final HugeLongArray existingLabels;
    private final LongDoubleScatterMap votes;

    ComputeStepConsumer(
            NodePropertyValues nodeWeights,
            HugeLongArray existingLabels) {
        this.existingLabels = existingLabels;
        this.nodeWeights = nodeWeights;
        // use scatter map to get consistent (deterministic) hash order
        this.votes = new LongDoubleScatterMap();
    }

    @Override
    public boolean accept(final long sourceNodeId, final long targetNodeId, final double property) {
        castVote(targetNodeId, property);
        return true;
    }

    private void castVote(long candidate, double weight) {
        weight = weightOf(candidate, weight);
        long label = existingLabels.get(candidate);
        votes.addTo(label, weight);
    }

    private double weightOf(final long candidate, final double relationshipWeight) {
        double nodeWeight = nodeWeights.doubleValue(candidate);
        return relationshipWeight * nodeWeight;
    }

    void clearVotes() {
        votes.clear();
    }

    long tallyVotes(long label) {
        double weight = Double.NEGATIVE_INFINITY;
        for (LongDoubleCursor vote : votes) {
            if (weight < vote.value) {
                weight = vote.value;
                label = vote.key;
            } else if (weight == vote.value) {
                if (vote.key < label) {
                    label = vote.key;
                }
            }
        }
        return label;
    }

    private static final long[] EMPTY_LONGS = new long[0];

    void release() {
        // the HPPC release() method allocates new arrays
        // the clear() method overwrite the existing keys with the default value
        // we want to throw away all data to allow for GC collection instead.

        if (votes.keys != null) {
            votes.keys = EMPTY_LONGS;
            votes.clear();
            votes.keys = null;
            votes.values = null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy