msi.gama.metamodel.population.GamaPopulation.java Source code

Java tutorial

Introduction

Here is the source code for msi.gama.metamodel.population.GamaPopulation.java

Source

/*******************************************************************************************************
 *
 * msi.gama.metamodel.population.GamaPopulation.java, in plugin msi.gama.core,
 * is part of the source code of the GAMA modeling and simulation platform (v. 1.8)
 * 
 * (c) 2007-2018 UMI 209 UMMISCO IRD/SU & Partners
 *
 * Visit https://github.com/gama-platform/gama for license information and contacts.
 * 
 ********************************************************************************************************/
package msi.gama.metamodel.population;

import static java.util.Collections.EMPTY_LIST;
import static java.util.Collections.EMPTY_MAP;
import static msi.gama.common.interfaces.IKeyword.CELL_HEIGHT;
import static msi.gama.common.interfaces.IKeyword.CELL_WIDTH;
import static msi.gama.common.interfaces.IKeyword.EDGE_SPECIES;
import static msi.gama.common.interfaces.IKeyword.EXPERIMENT;
import static msi.gama.common.interfaces.IKeyword.FILE;
import static msi.gama.common.interfaces.IKeyword.FILES;
import static msi.gama.common.interfaces.IKeyword.LOCATION;
import static msi.gama.common.interfaces.IKeyword.MIRRORS;
import static msi.gama.common.interfaces.IKeyword.NEIGHBORS;
import static msi.gama.common.interfaces.IKeyword.NEIGHBOURS;
import static msi.gama.common.interfaces.IKeyword.SHAPE;
import static msi.gama.common.interfaces.IKeyword.TARGET;
import static msi.gama.common.interfaces.IKeyword.WIDTH;
import static msi.gaml.descriptions.VariableDescription.INIT_DEPENDENCIES_FACETS;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;

import com.google.common.collect.Iterables;

import gnu.trove.map.hash.THashMap;
import gnu.trove.set.hash.THashSet;
import msi.gama.common.geometry.Envelope3D;
import msi.gama.common.interfaces.IKeyword;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.agent.IMacroAgent;
import msi.gama.metamodel.shape.GamaPoint;
import msi.gama.metamodel.shape.GamaShape;
import msi.gama.metamodel.shape.ILocation;
import msi.gama.metamodel.shape.IShape;
import msi.gama.metamodel.topology.ITopology;
import msi.gama.metamodel.topology.continuous.ContinuousTopology;
import msi.gama.metamodel.topology.filter.IAgentFilter;
import msi.gama.metamodel.topology.filter.In;
import msi.gama.metamodel.topology.graph.GamaSpatialGraph;
import msi.gama.metamodel.topology.graph.GraphTopology;
import msi.gama.metamodel.topology.grid.GamaSpatialMatrix;
import msi.gama.metamodel.topology.grid.GridTopology;
import msi.gama.runtime.GAMA;
import msi.gama.runtime.IScope;
import msi.gama.runtime.benchmark.StopWatch;
import msi.gama.runtime.concurrent.GamaExecutorService;
import msi.gama.runtime.exceptions.GamaRuntimeException;
import msi.gama.util.GamaList;
import msi.gama.util.GamaListFactory;
import msi.gama.util.IContainer;
import msi.gama.util.IList;
import msi.gama.util.file.GamaGridFile;
import msi.gama.util.graph.AbstractGraphNodeAgent;
import msi.gaml.architecture.IArchitecture;
import msi.gaml.compilation.IAgentConstructor;
import msi.gaml.descriptions.TypeDescription;
import msi.gaml.expressions.IExpression;
import msi.gaml.operators.Cast;
import msi.gaml.species.ISpecies;
import msi.gaml.statements.IExecutable;
import msi.gaml.types.GamaTopologyType;
import msi.gaml.types.IType;
import msi.gaml.types.Types;
import msi.gaml.variables.IVariable;
import one.util.streamex.StreamEx;

/**
 * Written by drogoul Modified on 6 sept. 2010
 *
 * @todo Description
 *
 */
public class GamaPopulation<T extends IAgent> extends GamaList<T> implements IPopulation<T> {

    public static <E extends IAgent> GamaPopulation<E> createPopulation(final IScope scope, final IMacroAgent host,
            final ISpecies species) {
        if (species.isGrid()) {
            final ITopology t = buildGridTopology(scope, species, host);
            final GamaSpatialMatrix m = (GamaSpatialMatrix) t.getPlaces();
            return m.new GridPopulation<>(t, host, species);
        }
        return new GamaPopulation<>(host, species);
    }

    /**
     * The agent hosting this population which is considered as the direct macro-agent.
     */
    protected IMacroAgent host;

    /**
     * The object describing how the agents of this population are spatially organized
     */
    protected ITopology topology;
    protected final ISpecies species;
    protected final String[] orderedVarNames;
    protected final IVariable[] updatableVars;
    protected int currentAgentIndex;
    protected final IArchitecture architecture;
    private final int hashCode;

    /**
     * Listeners, created in a lazy way
     */
    private LinkedList<IPopulation.Listener> listeners = null;

    public static IPopulation.IsLiving isLiving = new IPopulation.IsLiving();

    class MirrorPopulationManagement implements IExecutable {

        final IExpression listOfTargetAgents;

        MirrorPopulationManagement(final IExpression exp) {
            listOfTargetAgents = exp;
        }

        @Override
        public Object executeOn(final IScope scope) throws GamaRuntimeException {
            final IPopulation<T> pop = GamaPopulation.this;
            final Set<IAgent> targets = new THashSet<IAgent>(Cast.asList(scope, listOfTargetAgents.value(scope)));
            final List<IAgent> toKill = new ArrayList<>();
            for (final IAgent agent : pop.iterable(scope)) {
                final IAgent target = Cast.asAgent(scope, agent.getAttribute(TARGET));
                if (targets.contains(target)) {
                    targets.remove(target);
                } else {
                    toKill.add(agent);
                }
            }
            for (final IAgent agent : toKill) {
                agent.dispose();
            }
            final List<Map<String, Object>> attributes = new ArrayList<>();
            for (final IAgent target : targets) {
                final Map<String, Object> att = new THashMap<>();
                att.put(TARGET, target);
                attributes.add(att);
            }
            return pop.createAgents(scope, targets.size(), attributes, false, true);
        }

    }

    public GamaPopulation(final IMacroAgent host, final ISpecies species) {
        super(0, host == null ? Types.get(EXPERIMENT)
                : host.getModel().getDescription().getTypeNamed(species.getName()));
        this.host = host;
        this.species = species;
        architecture = species.getArchitecture();
        final TypeDescription ecd = species.getDescription();
        orderedVarNames = ecd.getOrderedAttributeNames(INIT_DEPENDENCIES_FACETS).toArray(new String[0]);
        final List<String> updatableVarNames = ecd.getUpdatableAttributeNames();
        final int updatableVarsSize = updatableVarNames.size();
        updatableVars = new IVariable[updatableVarsSize];
        for (int i = 0; i < updatableVarsSize; i++) {
            final String s = updatableVarNames.get(i);
            updatableVars[i] = species.getVar(s);
        }
        if (species.isMirror() && host != null) {
            host.getScope().getSimulation()
                    .postEndAction(new MirrorPopulationManagement(species.getFacet(MIRRORS)));
        }
        hashCode = Objects.hash(getSpecies(), getHost());

    }

    @Override
    public boolean step(final IScope scope) throws GamaRuntimeException {
        final IExpression frequencyExp = species.getFrequency();
        if (frequencyExp != null) {
            final int frequency = Cast.asInt(scope, frequencyExp.value(scope));
            final int step = scope.getClock().getCycle();
            if (frequency == 0 || step % frequency != 0) {
                return true;
            }
        }
        getSpecies().getArchitecture().preStep(scope, this);
        return stepAgents(scope);

    }

    protected boolean stepAgents(final IScope scope) {
        return GamaExecutorService.step(scope, this, getSpecies());
    }

    @Override
    public StreamEx<T> stream(final IScope scope) {
        return super.stream(scope);
    }

    /**
     * Take copy into account and always creates a list (necessary for #2254)
     */
    @Override
    public IList<T> listValue(final IScope scope, final IType contentsType, final boolean copy) {
        if (copy) {
            return GamaListFactory.create(scope, contentsType, this);
        }
        return this;
    }

    /**
     * Explicity copy (necessary for #2254)
     */
    @Override
    public IList<T> copy(final IScope scope) {
        return listValue(scope, getGamlType().getContentType(), true);
    }

    @Override
    public void updateVariables(final IScope scope, final IAgent a) {
        for (final IVariable v : updatableVars) {
            try (StopWatch w = GAMA.benchmark(scope, v)) {
                scope.setCurrentSymbol(v);
                scope.setAgentVarValue(a, v.getName(), v.getUpdatedValue(scope));
            }
        }
    }

    @Override
    public boolean init(final IScope scope) {
        return true;
        // // Do whatever the population has to do at the first step ?
    }

    @Override
    public void createVariablesFor(final IScope scope, final T agent) throws GamaRuntimeException {
        for (final String s : orderedVarNames) {
            final IVariable var = species.getVar(s);
            var.initializeWith(scope, agent, null);
        }
    }

    @Override
    public T getAgent(final Integer index) {
        return Iterables.find(this, each -> each.getIndex() == index, null);
    }

    @Override
    public int compareTo(final IPopulation<T> o) {
        return getName().compareTo(o.getName());
    }

    @Override
    public ITopology getTopology() {
        return topology;
    }

    @Override
    public String getName() {
        return species.getName();
    }

    @Override
    public boolean isGrid() {
        return species.isGrid();
    }

    @Override
    public ISpecies getSpecies() {
        return species;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Iterable<T> iterable(final IScope scope) {
        return (Iterable<T>) getAgents(scope);
    }

    @Override
    public void dispose() {
        killMembers();
        clear();
        final IScope scope = getHost() == null ? GAMA.getRuntimeScope() : getHost().getScope();
        firePopulationCleared(scope);
        if (topology != null) {
            topology.dispose();
            topology = null;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public T[] toArray() {
        return (T[]) super.toArray(new IAgent[0]);
    }

    /**
     * Special case for creating agents directly from geometries
     * 
     * @param scope
     * @param number
     * @param initialValues
     * @param geometries
     * @return
     */
    @Override
    public IList<T> createAgents(final IScope scope, final IContainer<?, ? extends IShape> geometries) {
        final int number = geometries.length(scope);
        if (number == 0) {
            return GamaListFactory.create();
        }
        final IList<T> list = GamaListFactory.create(getGamlType().getContentType(), number);
        final IAgentConstructor<T> constr = species.getDescription().getAgentConstructor();
        for (final IShape geom : geometries.iterable(scope)) {
            // WARNING Should be redefined somehow
            final T a = constr.createOneAgent(this, currentAgentIndex++);
            // final int ind = currentAgentIndex++;
            // a.setIndex(ind);
            a.setGeometry(geom);
            list.add(a);
        }
        /* agents. */addAll(list);

        for (final IAgent a : list) {
            a.schedule(scope);
            // a.scheduleAndExecute(null);
        }
        createVariablesFor(scope, list, EMPTY_LIST);
        fireAgentsAdded(scope, list);
        return list;

    }

    @Override
    public T createAgentAt(final IScope scope, final int index, final Map<String, Object> initialValues,
            final boolean isRestored, final boolean toBeScheduled) throws GamaRuntimeException {

        final List<Map<String, Object>> mapInitialValues = new ArrayList<>();
        mapInitialValues.add(initialValues);

        // TODO : think to another solution... it is ugly
        final int tempIndexAgt = currentAgentIndex;

        currentAgentIndex = index;
        final IList<T> listAgt = createAgents(scope, 1, mapInitialValues, isRestored, toBeScheduled);
        currentAgentIndex = tempIndexAgt;

        return listAgt.firstValue(scope);
    }

    @Override
    public IList<T> createAgents(final IScope scope, final int number,
            final List<? extends Map<String, Object>> initialValues, final boolean isRestored,
            final boolean toBeScheduled) throws GamaRuntimeException {
        if (number == 0) {
            return GamaListFactory.create();
        }
        final IList<T> list = GamaListFactory.create(getGamlType().getContentType(), number);
        final IAgentConstructor<T> constr = species.getDescription().getAgentConstructor();
        for (int i = 0; i < number; i++) {
            @SuppressWarnings("unchecked")
            final T a = constr.createOneAgent(this, currentAgentIndex++);
            // final int ind = currentAgentIndex++;
            // a.setIndex(ind);
            // Try to grab the location earlier
            if (initialValues != null && !initialValues.isEmpty()) {
                final Map<String, Object> init = initialValues.get(i);
                if (init.containsKey(SHAPE)) {
                    final Object val = init.get(SHAPE);
                    if (val instanceof GamaPoint) {
                        a.setGeometry(new GamaShape((IShape) val));
                    } else {
                        a.setGeometry((IShape) val);
                    }
                    init.remove(SHAPE);
                } else if (init.containsKey(LOCATION)) {
                    a.setLocation((GamaPoint) init.get(LOCATION));
                    init.remove(LOCATION);
                }
            }
            list.add(a);
        }
        addAll(list);
        createVariablesFor(scope, list, initialValues);
        if (!isRestored) {
            for (final IAgent a : list) {
                // if agent is restored (on the capture or release); then don't
                // need to run the "init"
                // reflex
                a.schedule(scope);
                // a.scheduleAndExecute(sequence);
            }
        }
        fireAgentsAdded(scope, list);
        return list;
    }

    public void createVariablesFor(final IScope scope, final List<T> agents,
            final List<? extends Map<String, Object>> initialValues) throws GamaRuntimeException {
        createAndUpdateVariablesFor(scope, agents, initialValues, false);
    }

    @SuppressWarnings("null")
    public void createAndUpdateVariablesFor(final IScope scope, final List<T> agents,
            final List<? extends Map<String, Object>> initialValues, final boolean update)
            throws GamaRuntimeException {
        if (agents == null || agents.isEmpty()) {
            return;
        }
        final boolean empty = initialValues == null || initialValues.isEmpty();
        Map<String, Object> inits;
        for (int i = 0, n = agents.size(); i < n; i++) {
            final IAgent a = agents.get(i);
            if (empty) {
                inits = EMPTY_MAP;
            } else {
                inits = initialValues.get(i);
            }
            for (final String s : orderedVarNames) {
                final IVariable var = species.getVar(s);
                final Object initGet = empty || !allowVarInitToBeOverridenByExternalInit(var) ? null : inits.get(s);
                if (!update || initGet != null) {
                    var.initializeWith(scope, a, initGet);
                } // else if initGet == null : do not do anything, this will
                  // keep the previously defined value for the variable
            }
        }
    }

    protected boolean allowVarInitToBeOverridenByExternalInit(final IVariable var) {
        return true;
    }

    @Override
    public void initializeFor(final IScope scope) throws GamaRuntimeException {
        dispose();
        computeTopology(scope);
        if (topology != null) {
            topology.initialize(scope, this);
        }
    }

    @Override
    public boolean hasVar(final String n) {
        return species.getVar(n) != null;
    }

    @Override
    public boolean hasAspect(final String default1) {
        return species.hasAspect(default1);
    }

    @Override
    public IExecutable getAspect(final String default1) {
        return species.getAspect(default1);
    }

    @Override
    public Collection<String> getAspectNames() {
        return species.getAspectNames();
    }

    @Override
    public IVariable getVar(final String s) {
        return species.getVar(s);
    }

    @Override
    public boolean hasUpdatableVariables() {
        return updatableVars.length > 0;
    }

    @SuppressWarnings("unchecked")
    @Override
    public T getAgent(final IScope scope, final ILocation coord) {
        final IAgentFilter filter = In.list(scope, this);
        if (filter == null) {
            return null;
        }

        return topology == null ? null : (T) topology.getAgentClosestTo(scope, coord, filter);
    }

    /**
     * Initializes the appropriate topology.
     *
     * @param scope
     * @return
     * @throws GamaRuntimeException
     */
    protected void computeTopology(final IScope scope) throws GamaRuntimeException {
        final IExpression expr = species.getFacet(IKeyword.TOPOLOGY);
        final boolean fixed = species.isGraph() || species.isGrid();
        if (expr != null) {
            if (!fixed) {
                topology = GamaTopologyType.staticCast(scope, scope.evaluate(expr, host).getValue(), false);
                return;
            }
            throw GamaRuntimeException.warning(
                    "Impossible to assign a topology to " + species.getName() + " as it already defines one.",
                    scope);
        }
        if (species.isGrid()) {
            topology = buildGridTopology(scope, species, getHost());
        } else if (species.isGraph()) {
            final IExpression spec = species.getFacet(EDGE_SPECIES);
            final String edgeName = spec == null ? "base_edge" : spec.literalValue();
            final ISpecies edgeSpecies = scope.getModel().getSpecies(edgeName);
            final IType<?> edgeType = scope.getType(edgeName);
            final IType<?> nodeType = getGamlType().getContentType();
            // TODO Specifier directed quelque part dans l'espece
            final GamaSpatialGraph g = new GamaSpatialGraph(GamaListFactory.create(), false, false,
                    new AbstractGraphNodeAgent.NodeRelation(), edgeSpecies, scope, nodeType, edgeType);
            this.addListener(g);
            g.postRefreshManagementAction(scope);
            topology = new GraphTopology(scope, this.getHost(), g);
        } else {
            topology = new ContinuousTopology(scope, this.getHost());
        }

    }

    protected static ITopology buildGridTopology(final IScope scope, final ISpecies species, final IAgent host) {
        IExpression exp = species.getFacet(WIDTH);
        final Envelope3D env = scope.getSimulation().getGeometry().getEnvelope();
        final int rows = exp == null ? species.hasFacet(CELL_WIDTH)
                ? (int) (env.getWidth() / Cast.asFloat(scope, species.getFacet(CELL_WIDTH).value(scope)))
                : 100 : Cast.asInt(scope, exp.value(scope));
        exp = species.getFacet(IKeyword.HEIGHT);
        final int columns = exp == null ? species.hasFacet(CELL_HEIGHT)
                ? (int) (env.getHeight() / Cast.asFloat(scope, species.getFacet(CELL_HEIGHT).value(scope)))
                : 100 : Cast.asInt(scope, exp.value(scope));

        final boolean isTorus = host.getTopology().isTorus();
        exp = species.getFacet("use_individual_shapes");
        final boolean useIndividualShapes = exp == null || Cast.asBool(scope, exp.value(scope));
        exp = species.getFacet("use_neighbors_cache");
        final boolean useNeighborsCache = exp == null || Cast.asBool(scope, exp.value(scope));
        exp = species.getFacet("horizontal_orientation");
        final boolean horizontalOrientation = exp == null || Cast.asBool(scope, exp.value(scope));

        exp = species.getFacet("optimizer");
        final String optimizer = exp == null ? "" : Cast.asString(scope, exp.value(scope));

        exp = species.getFacet(NEIGHBORS);
        if (exp == null) {
            exp = species.getFacet(NEIGHBOURS);
        }
        final boolean usesVN = exp == null || Cast.asInt(scope, exp.value(scope)) == 4;
        final boolean isHexagon = exp != null && Cast.asInt(scope, exp.value(scope)) == 6;
        exp = species.getFacet(FILES);
        // AD WARNING: The following line is really UNSAFE !!!
        final IList<GamaGridFile> files = (IList<GamaGridFile>) (exp != null ? exp.value(scope) : null);
        GridTopology result;
        if (files != null && !files.isEmpty()) {
            result = new GridTopology(scope, host, files, isTorus, usesVN, useIndividualShapes, useNeighborsCache,
                    optimizer);
        } else {
            exp = species.getFacet(FILE);
            final GamaGridFile file = (GamaGridFile) (exp != null ? exp.value(scope) : null);
            if (file == null) {
                result = new GridTopology(scope, host, rows, columns, isTorus, usesVN, isHexagon,
                        horizontalOrientation, useIndividualShapes, useNeighborsCache, optimizer);
            } else {
                result = new GridTopology(scope, host, file, isTorus, usesVN, useIndividualShapes,
                        useNeighborsCache, optimizer);
            }

        }
        // Reverts the modification of the world envelope (see #1953 and #1939)
        //
        // final Envelope3D env =
        // result.getPlaces().getEnvironmentFrame().getEnvelope();
        // final Envelope3D world = host.getEnvelope();
        // final Envelope3D newEnvelope = new Envelope3D(0,
        // Math.max(env.getWidth(), world.getWidth()), 0,
        // Math.max(env.getHeight(), world.getHeight()), 0,
        // Math.max(env.getDepth(), world.getDepth()));
        // host.setGeometry(new GamaShape(newEnvelope));
        return result;
    }

    @Override
    public IMacroAgent getHost() {
        return host;
    }

    @Override
    public Iterator<T> iterator() {
        return super.iterator();
    }

    @Override
    public final boolean equals(final Object o) {
        return o == this;
    }

    @Override
    public final int hashCode() {
        return hashCode;
    }

    @Override
    public void killMembers() throws GamaRuntimeException {
        final T[] ag = toArray();
        for (final T a : ag) {
            if (a != null) {
                a.dispose();
            }
        }
        this.clear();
    }

    @Override
    public String toString() {
        return "Population of " + species.getName();
    }

    @Override
    public void addValue(final IScope scope, final T value) {
        fireAgentAdded(scope, value);
        add(value);
    }

    @Override
    public void addValueAtIndex(final IScope scope, final Object index, final T value) {
        fireAgentAdded(scope, value);
        super.addValueAtIndex(scope, index, value);
    }

    @Override
    public void addValues(final IScope scope, final IContainer values) {
        for (final T o : (java.lang.Iterable<T>) values.iterable(scope)) {
            addValue(scope, o);
        }
    }

    @Override
    public void removeValue(final IScope scope, final Object value) {
        if (value instanceof IAgent && super.remove(value)) {
            if (topology != null) {
                topology.removeAgent((IAgent) value);
            }
            fireAgentRemoved(scope, (IAgent) value);
        }
    }

    @Override
    public void removeValues(final IScope scope, final IContainer values) {
        for (final Object o : values.iterable(scope)) {
            removeValue(scope, o);
        }
    }

    @Override
    public void removeAllOccurrencesOfValue(final IScope scope, final Object value) {
        removeValue(scope, value);
    }

    @Override
    public boolean remove(final Object a) {
        removeValue(null, a);
        return true;
    }

    @Override
    public boolean contains(final IScope scope, final Object o) {
        if (!(o instanceof IAgent)) {
            return false;
        }
        return ((IAgent) o).getPopulation() == this;
    }

    private boolean hasListeners() {
        return listeners != null && !listeners.isEmpty();
    }

    @Override
    public void addListener(final IPopulation.Listener listener) {
        if (listeners == null) {
            listeners = new LinkedList<>();
        }
        if (!listeners.contains(listener)) {
            listeners.add(listener);
        }
    }

    @Override
    public void removeListener(final IPopulation.Listener listener) {
        if (listeners == null) {
            return;
        }
        listeners.remove(listener);
    }

    protected void fireAgentAdded(final IScope scope, final IAgent agent) {
        if (!hasListeners()) {
            return;
        }
        try {
            for (final IPopulation.Listener l : listeners) {
                l.notifyAgentAdded(scope, this, agent);
            }
        } catch (final RuntimeException e) {
            e.printStackTrace();
        }
    }

    protected <T extends IAgent> void fireAgentsAdded(final IScope scope, final IList<T> container) {
        if (!hasListeners()) {
            return;
        }
        // create list
        final Collection<T> agents = new LinkedList<>();
        final Iterator<T> it = container.iterator();
        while (it.hasNext()) {
            agents.add(it.next());
        }
        // send event
        try {
            for (final IPopulation.Listener l : listeners) {
                l.notifyAgentsAdded(scope, this, agents);
            }
        } catch (final RuntimeException e) {
            e.printStackTrace();
        }
    }

    protected void fireAgentRemoved(final IScope scope, final IAgent agent) {
        if (!hasListeners()) {
            return;
        }
        try {
            for (final IPopulation.Listener l : listeners) {
                l.notifyAgentRemoved(scope, this, agent);
            }
        } catch (final RuntimeException e) {
            e.printStackTrace();
        }
    }

    protected void firePopulationCleared(final IScope scope) {
        if (!hasListeners()) {
            return;
        }
        // send event
        try {
            for (final IPopulation.Listener l : listeners) {
                l.notifyPopulationCleared(scope, this);
            }
        } catch (final RuntimeException e) {
            e.printStackTrace();
        }
    }

    // Filter methods

    /**
     * Method getAgents()
     * 
     * @see msi.gama.metamodel.topology.filter.IAgentFilter#getAgents()
     */
    @Override
    public IContainer<?, ? extends IAgent> getAgents(final IScope scope) {
        return GamaListFactory.create(scope, getGamlType().getContentType(), GamaPopulation.allLivingAgents(this));
    }

    /**
     * Method accept()
     * 
     * @see msi.gama.metamodel.topology.filter.IAgentFilter#accept(msi.gama.runtime.IScope,
     *      msi.gama.metamodel.shape.IShape, msi.gama.metamodel.shape.IShape)
     */
    @Override
    public boolean accept(final IScope scope, final IShape source, final IShape a) {
        final IAgent agent = a.getAgent();
        if (agent == null) {
            return false;
        }
        if (agent.getPopulation() != this) {
            return false;
        }
        if (agent.dead()) {
            return false;
        }
        final IAgent as = source.getAgent();
        if (agent == as) {
            return false;
        }
        // }
        return true;
    }

    /**
     * Method filter()
     * 
     * @see msi.gama.metamodel.topology.filter.IAgentFilter#filter(msi.gama.runtime.IScope,
     *      msi.gama.metamodel.shape.IShape, java.util.Collection)
     */
    @Override
    public void filter(final IScope scope, final IShape source, final Collection<? extends IShape> results) {
        final IAgent sourceAgent = source == null ? null : source.getAgent();
        results.remove(sourceAgent);
        final Predicate<IShape> toRemove = (each) -> {
            final IAgent a = each.getAgent();
            return a == null || a.dead() || a.getPopulation() != this
                    && (a.getPopulation().getGamlType().getContentType() != this.getGamlType().getContentType()
                            || !this.contains(a));
        };
        results.removeIf(toRemove);
    }

    @Override
    public Collection<? extends IPopulation<? extends IAgent>> getPopulations(final IScope scope) {
        return Collections.singleton(this);
    }

    @Override
    public T getFromIndicesList(final IScope scope, final IList indices) throws GamaRuntimeException {
        if (indices == null) {
            return null;
        }
        final int size = indices.size();
        switch (size) {
        case 0:
            return null;
        case 1:
            return super.getFromIndicesList(scope, indices);
        case 2:
            return this.getAgent(scope,
                    new GamaPoint(Cast.asFloat(scope, indices.get(0)), Cast.asFloat(scope, indices.get(1))));
        default:
            throw GamaRuntimeException.error("Populations cannot be accessed with 3 or more indexes", scope);

        }

    }

    /**
     * @param actionScope
     * @param iterable
     * @return
     */
    public static <T extends IAgent> Iterable<T> allLivingAgents(final Iterable<T> iterable) {
        return Iterables.filter(iterable, isLiving);
    }
}