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

it.unibo.alchemist.model.sapere.conditions.LsaNeighborhoodCondition Maven / Gradle / Ivy

There is a newer version: 35.0.1
Show newest version
/*
 * Copyright (C) 2010-2023, Danilo Pianini and contributors
 * listed, for each module, in the respective subproject's build.gradle.kts file.
 *
 * This file is part of Alchemist, and is distributed under the terms of the
 * GNU General Public License, with a linking exception,
 * as described in the file LICENSE in the Alchemist distribution's top directory.
 */
package it.unibo.alchemist.model.sapere.conditions;

import it.unibo.alchemist.model.sapere.dsl.impl.NumTreeNode;
import it.unibo.alchemist.model.sapere.dsl.IExpression;
import it.unibo.alchemist.model.sapere.dsl.ITreeNode;
import it.unibo.alchemist.model.sapere.molecules.LsaMolecule;
import it.unibo.alchemist.model.Context;
import it.unibo.alchemist.model.Environment;
import it.unibo.alchemist.model.sapere.ILsaMolecule;
import it.unibo.alchemist.model.sapere.ILsaNode;
import it.unibo.alchemist.model.Node;

import it.unibo.alchemist.model.Reaction;
import org.danilopianini.lang.HashString;

import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;


/**
 */
public final class LsaNeighborhoodCondition extends LsaStandardCondition {

    private static final long serialVersionUID = 5472803597473997104L;
    private final Environment, ?> environment;

    /**
     * @param node the node
     * @param molecule the molecule
     * @param environment the environment
     */
    public LsaNeighborhoodCondition(
            final ILsaNode node,
            final ILsaMolecule molecule,
            final Environment, ?> environment
    ) {
        super(molecule, node);
        this.environment = environment;
    }

    @Override
    public LsaNeighborhoodCondition cloneCondition(final Node> node, final Reaction> r) {
        return new LsaNeighborhoodCondition((ILsaNode) node, getMolecule(), environment);
    }

    @Override
    public boolean filter(
            final List>> matchesList,
            final List validNodes,
            final List>> retrieved
    ) {
        if (validNodes.isEmpty()) {
            return false;
        }
        if (matchesList.isEmpty()) {
            /*
             * This is the first condition. It must create all the matches.
             * 
             * To create them, it must check every neighbor, and create the
             * matches for each of them.
             */
            int lastSize = 0;
            for (int i = 0; i < validNodes.size();) {
                final ILsaNode neigh = validNodes.get(i);
                createMatches(getMolecule(), neigh, matchesList, retrieved);
                if (matchesList.size() > lastSize) {
                    /*
                     * This neighbor has the LSA we are checking for, so new
                     * matches have been created. For each of them, we must add
                     * the selected node special property, in order for the
                     * actions on single neighbor to be correctly bound.
                     */
                    final NumTreeNode nodeId = new NumTreeNode(neigh.getId());
                    for (; lastSize < matchesList.size(); lastSize++) {
                        matchesList.get(lastSize).put(LsaMolecule.SYN_SELECTED, nodeId);
                    }
                    i++;
                } else {
                    /*
                     * This neighbor is not valid, and thus should be removed
                     * from the validNodes list.
                     */
                    validNodes.remove(i);
                }
            }
            /*
             * True if at least a valid match has been created.
             */
            return makeValid(!matchesList.isEmpty());
        }
        /*
         * At least a condition has been run before. This condition must check
         * the existing matches, removing all those which are no longer valid.
         */
        boolean matchesfound = false;
        final AbstractSet newValidNodes = new LinkedHashSet<>(validNodes.size());
        for (int i = matchesList.size() - 1; i >= 0; i--) {
            final Map> alreadyRemovedMap = retrieved.get(i);
            final Map> matches = matchesList.get(i);
            final List partialInstance = getMolecule().allocateVar(matches);
            final boolean dups = getMolecule().hasDuplicateVariables();
            /*
             * There is a chance that other Neighborhood conditions have been
             * run before. Thus, it is mandatory to check if the selected node
             * match has been instanced, and in case just run on that node.
             */
            final ITreeNode node = matches.get(LsaMolecule.SYN_SELECTED);
            if (node != null) {
                final int id = ((Double) node.getData()).intValue();
                for (int j = validNodes.size() - 1; j >= 0; j--) {
                    final ILsaNode n = validNodes.get(j);
                    if (n.getId() == id) {
                        List alreadyRemoved = alreadyRemovedMap.get(n);
                        if (alreadyRemoved == null) {
                            alreadyRemoved = new ArrayList<>();
                            alreadyRemovedMap.put(n, alreadyRemoved);
                        }
                        final List otherMatches =
                                calculateMatches(partialInstance, dups, n.getLsaSpace(), alreadyRemoved);
                        if (otherMatches.isEmpty()) {
                            /*
                             * This match should be removed, but there might be
                             * other matches in which this node is still valid,
                             * so the node validity check must be performed
                             * after.
                             */
                            retrieved.remove(i);
                            matchesList.remove(i);
                        } else {
                            incorporateNewMatches(
                                    n,
                                    otherMatches,
                                    matches,
                                    getMolecule(),
                                    matchesList,
                                    alreadyRemovedMap,
                                    retrieved
                            );
                            matchesfound = true;
                            newValidNodes.add(n);
                        }
                        break;
                    }
                }
            } else {
                /*
                 * No node has been selected for this match yet
                 */
                final Map> matchesPerNode = new HashMap<>();
                for (int j = validNodes.size() - 1; j >= 0; j--) {
                    final ILsaNode n = validNodes.get(j);
                    List alreadyRemoved = alreadyRemovedMap.get(n);
                    if (alreadyRemoved == null) {
                        alreadyRemoved = new ArrayList<>();
                        alreadyRemovedMap.put(n, alreadyRemoved);
                    }
                    final List otherMatches =
                            calculateMatches(partialInstance, dups, n.getLsaSpace(), alreadyRemoved);
                    if (!otherMatches.isEmpty()) {
                        matchesPerNode.put(n, otherMatches);
                        newValidNodes.add(n);
                    }
                }
                if (matchesPerNode.isEmpty()) {
                    /*
                     * I've checked all the neighbors which are still valid. If
                     * this condition is not valid for the current match, it
                     * should be removed.
                     */
                    matchesList.remove(i);
                } else {
                    incorporateNewMatches(matchesPerNode, matches, getMolecule(), matchesList, alreadyRemovedMap, retrieved);
                    matchesfound = true;
                }
            }
        }
        /*
         * Valid nodes redefinition.
         */
        for (int i = 0; i < validNodes.size(); i++) {
            if (!newValidNodes.contains(validNodes.get(i))) {
                validNodes.remove(i);
                i--;
            }
        }
        return makeValid(matchesfound);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * alice.alchemist.model.implementations.conditions.LsaStandardCondition
     * #getContext()
     */
    @Override
    public Context getContext() {
        return Context.NEIGHBORHOOD;
    }

    /**
     * @return the current environment
     */
    protected Environment, ?> getEnvironment() {
        return environment;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * alice.alchemist.model.implementations.conditions.LsaStandardCondition
     * #toString()
     */
    @Override
    public String toString() {
        return "+" + super.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy