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

main.io.github.moonlightsuite.moonlight.space.IntManhattanDistanceStructure Maven / Gradle / Ivy

Go to download

MoonLight is a light-weight Java-tool for monitoring temporal, spatial and spatio-temporal properties of distributed complex systems, such as Cyber-Physical Systems and Collective Adaptive Systems.

The newest version!
package io.github.moonlightsuite.moonlight.space;

import io.github.moonlightsuite.moonlight.core.space.DistanceDomain;
import io.github.moonlightsuite.moonlight.core.space.DistanceStructure;
import io.github.moonlightsuite.moonlight.core.space.SpatialModel;
import io.github.moonlightsuite.moonlight.domain.IntegerDomain;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.IntStream;

public class IntManhattanDistanceStructure
        implements DistanceStructure {
    private final int lowerBound;

    private final boolean parallel;
    private final int upperBound;
    private final RegularGridModel model;
    private final int cappedUpperBound;
    private int[][] distanceMatrix;
    private int[][] oneStepDistanceMatrix;

    /**
     * @param lowerBound lower bound of the distance
     * @param upperBound upper bound of the distance, inclusive
     * @param model      the spatial model
     */
    public IntManhattanDistanceStructure(int lowerBound, int upperBound,
                                         @NotNull RegularGridModel model) {
        this(false, lowerBound, upperBound, model);
    }

    /**
     * @param parallel   if true, the distance matrix is computed in parallel
     * @param lowerBound lower bound of the distance
     * @param upperBound upper bound of the distance, inclusive
     * @param model      the spatial model
     */
    public IntManhattanDistanceStructure(
            boolean parallel,
            int lowerBound,
            int upperBound,
            @NotNull RegularGridModel model) {
        this.lowerBound = lowerBound;
        this.upperBound = upperBound;
        this.model = model;
        this.parallel = parallel;
        cappedUpperBound = Math.min(model.size(), upperBound + 1);
        computeDistanceMatrix();
    }

    private void computeDistanceMatrix() {
        distanceMatrix = new int[model.size()][0];
        prepareOneStepDistanceMatrix();
        computeReachableSets();
    }

    private void prepareOneStepDistanceMatrix() {
        oneStepDistanceMatrix = new int[model.size()][4];
        IntStream.range(0, model.size())
                .forEach(i -> oneStepDistanceMatrix[i] =
                        model.getNeighboursArray(i));

    }

    private void computeReachableSets() {
        if (parallel)
            IntStream.range(0, model.size()).parallel()
                    .forEach(this::computeLocationReachableSet);
        else
            IntStream.range(0, model.size())
                    .forEach(this::computeLocationReachableSet);
    }

    private void computeLocationReachableSet(int location) {
        IntStream.range(lowerBound, cappedUpperBound)
                .forEach(distance -> addAll(location, distance));
    }

    private void addAll(int location, int distance) {
        switch (distance) {
            case 0 -> addDistanceSet(new int[]{location}, location);
            case 1 -> addDistanceSet(oneStepDistanceMatrix[location], location);
            default -> addDistanceSet(computeDistanceSet(location), location);
        }
    }

    private int[] computeDistanceSet(int location) {
        int[] previous = distanceMatrix[location];
        IntFunction next = i ->
                Arrays.stream(oneStepDistanceMatrix[i]);

        return Arrays.stream(previous).flatMap(next).toArray();
    }

    private void addDistanceSet(int[] set, int target) {
        int[] oldNeighbours = distanceMatrix[target];
        int[] result = Arrays.copyOf(oldNeighbours,
                oldNeighbours.length + set.length);
        System.arraycopy(set, 0, result,
                oldNeighbours.length, set.length);
        result = Arrays.stream(result).distinct().toArray();
        distanceMatrix[target] = result;
    }

    @Override
    public int[] getNeighbourhood(int location) {
        return distanceMatrix[location];
    }

    @Override
    public boolean areWithinBounds(int from, int to) {
        return Arrays.stream(distanceMatrix[from]).anyMatch(x -> x == to);
    }

    @Override
    public Integer getDistance(int from, int to) {
        return getIntDistance(from, to);
    }

    public int getIntDistance(int from, int to) {
        int[] fPair = model.unsafeToCoordinates(from);
        int[] tPair = model.unsafeToCoordinates(to);
        return computeManhattanDistance(fPair, tPair);
    }

    private int computeManhattanDistance(int[] from,
                                         int[] to) {
        int distX = Math.abs(from[0] - to[0]);
        int distY = Math.abs(from[1] - to[1]);
        return distX + distY;
    }

    @Override
    public boolean isWithinBounds(Integer d) {
        return isWithinBounds(d.intValue());
    }

    public boolean isWithinBounds(int d) {
        return lowerBound <= d && d <= upperBound;
    }

    @Override
    public SpatialModel getModel() {
        return model;
    }

    @Override
    public Function getDistanceFunction() {
        return x -> x;
    }

    @Override
    public DistanceDomain getDistanceDomain() {
        return new IntegerDomain();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy