diff --git a/msi.gama.core/src/msi/gama/common/Activator.java b/msi.gama.core/src/msi/gama/common/Activator.java index a4cc54642b..584ae42117 100644 --- a/msi.gama.core/src/msi/gama/common/Activator.java +++ b/msi.gama.core/src/msi/gama/common/Activator.java @@ -3,6 +3,7 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import msi.gama.runtime.concurrent.GamaExecutorService; import msi.gaml.compilation.kernel.GamaBundleLoader; public class Activator implements BundleActivator { @@ -10,12 +11,9 @@ public class Activator implements BundleActivator { @Override public void start(final BundleContext context) throws Exception { /* Early build of the contributions made by plugins to GAMA */ - new Thread(new Runnable() { - - @Override - public void run() { - GamaBundleLoader.preBuildContributions(); - } + new Thread(() -> { + GamaBundleLoader.preBuildContributions(); + GamaExecutorService.startUp(); }).start(); } diff --git a/msi.gama.core/src/msi/gama/common/GamaPreferences.java b/msi.gama.core/src/msi/gama/common/GamaPreferences.java index 4341fe308f..cff96a5cab 100644 --- a/msi.gama.core/src/msi/gama/common/GamaPreferences.java +++ b/msi.gama.core/src/msi/gama/common/GamaPreferences.java @@ -70,6 +70,7 @@ public class GamaPreferences { public static final String UI = "Presentation"; public static final String EXPERIMENTS = "Experiments"; public static final String SIMULATIONS = "Simulations"; + public static final String CONCURRENCY = "Concurrency"; public static final String EXPERIMENTAL = "Performances"; public static final String DISPLAY = "Displays"; public static final String EDITOR = "Editors"; @@ -750,36 +751,7 @@ private static String getDefaultRPath() { false, IType.BOOL).in(EXPERIMENTAL).group(DISPLAY); public static final Entry CORE_OUTPUT_DELAY = create("core.output_delay", "Delay (in ms) between the opening of display views (increase if you experience freezes when opening displays, esp. Java2D displays)", - 200, IType.INT).between(0, 1000).in(EXPERIMENTAL).group(DISPLAY);; - public static final Entry MULTITHREADED_SIMULATIONS = create("core.multithreaded_simulations", - "Run multiple simulations in multiple threads", true, IType.BOOL).activates("core.threads_number") - .in(EXPERIMENTAL).group(SIMULATIONS); - public static final Entry NUMBERS_OF_THREADS = create("core.threads_number", - "Max. number of threads to use (available processors: " + Runtime.getRuntime().availableProcessors() + ")", - 4, IType.INT).between(1, null).in(EXPERIMENTAL).group(SIMULATIONS); - public static final Entry GRID_OPTIMIZATION = create("core.grid_optimization", - "Enable parallel grid operations", false, IType.BOOL).in(EXPERIMENTAL).group(SIMULATIONS) - .activates("core.grid_threads"); - public static final Entry NUMBERS_OF_GRID_THREADS = create("core.grid_threads", - "Max. number of threads to use", 4, IType.INT).between(1, null).in(EXPERIMENTAL).group(SIMULATIONS) - .addChangeListener(new IPreferenceChangeListener() { - - @Override - public boolean beforeValueChange(final Integer newValue) { - return true; - } - - @Override - public void afterValueChange(final Integer newValue) { - GAMA.setConcurrencyLevel(newValue); - System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", - String.valueOf(newValue)); - } - }); - public static final Entry SEQUENTIAL_THRESHOLD = create("core.sequential_threshold", - "Number under which agents will always be executed sequentially", 20, IType.INT).between(1, null) - .in(EXPERIMENTAL).group(SIMULATIONS); - + 200, IType.INT).between(0, 1000).in(EXPERIMENTAL).group(DISPLAY); public static final Entry CONSTANT_OPTIMIZATION = create("core.constant_optimization", "Automatically optimize constant expressions", false, IType.BOOL).in(EXPERIMENTAL).group("Compilation"); public static final Entry AGENT_OPTIMIZATION = create("core.agent_optimization", diff --git a/msi.gama.core/src/msi/gama/common/util/RandomUtils.java b/msi.gama.core/src/msi/gama/common/util/RandomUtils.java index 80ebeece32..9cb91ed2d6 100644 --- a/msi.gama.core/src/msi/gama/common/util/RandomUtils.java +++ b/msi.gama.core/src/msi/gama/common/util/RandomUtils.java @@ -181,7 +181,7 @@ public int createPoisson(final double mean) { int x = 0; double t = 0.0; while (true) { - t -= FastMath.log(next()) / mean; + t -= Math.log(next()) / mean; if (t > 1.0) { break; } @@ -191,6 +191,8 @@ public int createPoisson(final double mean) { } + public static boolean USE_BITWISE = true; + private byte[] createSeed(final Double s, final int length) { this.seed = s; Double realSeed = seed; @@ -200,10 +202,11 @@ private byte[] createSeed(final Double s, final int length) { if (realSeed < 1) { realSeed *= Long.MAX_VALUE; } - long l = realSeed.longValue(); - // System.out.println("Initial seed: " + seed + "; normalized seed: " + - // l); - + long l; + if (!USE_BITWISE) + l = realSeed.longValue(); + else + l = Double.doubleToRawLongBits(realSeed); final byte[] result = new byte[length]; switch (length) { case 4: @@ -230,11 +233,9 @@ private byte[] createSeed(final Double s, final int length) { public void dispose() { seed = null; generator = null; - // uniform = null; } public byte[] generateSeed(final int length) { - // byte[] result; return createSeed(seed, length); } @@ -341,6 +342,10 @@ public double next() { return generator.nextDouble(); } + public int nextInt() { + return generator.nextInt(); + } + /** * @param matrix * @return @@ -418,26 +423,6 @@ public static void testDrawRandomValues(final int min, final int max, final int System.out.println(); } - public static void main(final String[] args) { - final RandomUtils r1 = new RandomUtils(100.0, "mersenne"); - final RandomUtils r2 = new RandomUtils(100.0, "m{ersenne"); - for (int i = 0; i < 2000; i++) { - System.out.println("r1 " + r1.next() + " | r2 " + r2.next()); - } - // drawRandomValues(-0.2, 0.2, 0.1); - // drawRandomValues(4., 5., 0.2); - // drawRandomValues(0, 100, 3); - // drawRandomValues(-5, 5, 3); - // RandomUtils r = new RandomUtils(100.0, "mersenne"); - // for ( int i = 0; i < 10000000; i++ ) { - // double d = 0.0; - // if ( r.between(0.0, 0.1) == 0.0 ) { - // System.out.println("0.0 !"); - // } - // } - // System.out.println("Finished"); - } - private class BitString { private static final int WORD_LENGTH = 32; @@ -595,4 +580,21 @@ public int countSetBits() { } + public static void main(final String[] args) { + USE_BITWISE = false; + RandomUtils r1 = new RandomUtils(1.0, "mersenne1"); + RandomUtils r2 = new RandomUtils(1.0 * Math.pow(10, -50), "mersenne2"); + RandomUtils r3 = new RandomUtils(1.1 * Math.pow(10, -50), "mersenne3"); + for (int i = 0; i < 3; i++) { + System.out.println("r1 " + r1.nextInt() + " | r2 " + r2.nextInt() + " | r3 " + r3.nextInt()); + } + USE_BITWISE = true; + r1 = new RandomUtils(1.0, "mersenne1"); + r2 = new RandomUtils(1.0 * Math.pow(10, -50), "mersenne2"); + r3 = new RandomUtils(1.1 * Math.pow(10, -50), "mersenne3"); + for (int i = 0; i < 3; i++) { + System.out.println("r1 " + r1.nextInt() + " | r2 " + r2.nextInt() + " | r3 " + r3.nextInt()); + } + } + } diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/BatchAgent.java b/msi.gama.core/src/msi/gama/kernel/experiment/BatchAgent.java index 95592ce71b..3b6dee5c8d 100644 --- a/msi.gama.core/src/msi/gama/kernel/experiment/BatchAgent.java +++ b/msi.gama.core/src/msi/gama/kernel/experiment/BatchAgent.java @@ -167,6 +167,8 @@ public int getRunNumber() { public Double launchSimulationsWithSolution(final ParametersSet sol) throws GamaRuntimeException { // We first reset the currentSolution and the fitness values final SimulationPopulation pop = getSimulationPopulation(); + if (pop == null) // interrupted + return 0d; currentSolution = new ParametersSet(sol); fitnessValues.clear(); runNumber = runNumber + 1; @@ -180,7 +182,9 @@ public Double launchSimulationsWithSolution(final ParametersSet sol) throws Gama } // We then create a number of simulations with the same solution - final int numberOfCores = pop.getMaxNumberOfConcurrentSimulations(); + int numberOfCores = pop.getMaxNumberOfConcurrentSimulations(); + if (numberOfCores == 0) + numberOfCores = 1; int repeatIndex = 0; while (repeatIndex < getSeeds().length) { for (int coreIndex = 0; coreIndex < numberOfCores; coreIndex++) { @@ -202,7 +206,7 @@ public Double launchSimulationsWithSolution(final ParametersSet sol) throws Gama // cycles += " " + simulation.getClock().getCycle(); // test the condition first in case it is paused final boolean stopConditionMet = Cast.asBool(sim.getScope(), - sim.getScope().evaluate(stopCondition, sim)); + sim.getScope().evaluate(stopCondition, sim).getValue()); final boolean mustStop = stopConditionMet || agent.dead() || agent.getScope().isPaused(); if (mustStop) { pop.unscheduleSimulation(agent); diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentAgent.java b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentAgent.java index aaf6e24916..17d4d995e0 100644 --- a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentAgent.java +++ b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentAgent.java @@ -57,7 +57,6 @@ import msi.gama.util.Guava; import msi.gama.util.IList; import msi.gama.util.TOrderedHashMap; -import msi.gaml.descriptions.IDescription; import msi.gaml.species.ISpecies; import msi.gaml.statements.IExecutable; import msi.gaml.types.GamaGeometryType; @@ -526,25 +525,23 @@ public IPopulation getPopulationFor(final ISpecies species) { } @Override - public boolean step(final IScope scope) { + protected boolean preStep(final IScope scope) { clock.beginCycle(); - boolean result; - // An experiment always runs in its own scope - try { - executer.executeBeginActions(); - result = super.step(this.scope); - executer.executeEndActions(); - executer.executeOneShotActions(); - final IOutputManager outputs = getOutputManager(); - if (outputs != null) { - outputs.step(scope); - } - } finally { - clock.step(this.scope); + executer.executeBeginActions(); + return super.preStep(scope); + } - informStatus(); + @Override + protected void postStep(final IScope scope) { + super.postStep(scope); + executer.executeEndActions(); + executer.executeOneShotActions(); + final IOutputManager outputs = getOutputManager(); + if (outputs != null) { + outputs.step(scope); } - return result; + clock.step(this.scope); + informStatus(); } @Override @@ -622,16 +619,6 @@ public IExperimentAgent getExperiment() { return ExperimentAgent.this; } - @Override - public IDescription getExperimentContext() { - return ExperimentAgent.this.getSpecies().getDescription(); - } - - @Override - public IDescription getModelContext() { - return ExperimentAgent.this.getSpecies().getModel().getDescription(); - } - @Override public Object getGlobalVarValue(final String name) { if (ExperimentAgent.this.hasAttribute(name) || getSpecies().hasVar(name)) { diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPlan.java b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPlan.java index 4e01ae2ea4..161f6f6185 100644 --- a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPlan.java +++ b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPlan.java @@ -13,11 +13,12 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.Set; import com.google.common.collect.Iterables; -import msi.gama.common.GamaPreferences; import msi.gama.common.interfaces.IGamlIssue; import msi.gama.common.interfaces.IKeyword; import msi.gama.kernel.batch.BatchOutput; @@ -26,6 +27,11 @@ import msi.gama.kernel.experiment.ExperimentPlan.BatchValidator; import msi.gama.kernel.model.IModel; import msi.gama.kernel.simulation.SimulationAgent; +import msi.gama.metamodel.agent.IAgent; +import msi.gama.metamodel.agent.IMacroAgent; +import msi.gama.metamodel.population.GamaPopulation; +import msi.gama.metamodel.shape.ILocation; +import msi.gama.metamodel.topology.continuous.AmorphousTopology; import msi.gama.outputs.ExperimentOutputManager; import msi.gama.outputs.FileOutput; import msi.gama.outputs.IOutputManager; @@ -43,13 +49,16 @@ import msi.gama.runtime.IScope; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.Guava; +import msi.gama.util.IList; import msi.gama.util.TOrderedHashMap; import msi.gaml.compilation.IDescriptionValidator; import msi.gaml.compilation.ISymbol; +import msi.gaml.compilation.kernel.GamaMetaModel; import msi.gaml.descriptions.IDescription; import msi.gaml.expressions.IExpression; import msi.gaml.operators.Cast; import msi.gaml.species.GamlSpecies; +import msi.gaml.species.ISpecies; import msi.gaml.types.IType; import msi.gaml.variables.IVariable; @@ -78,7 +87,8 @@ @facet(name = IKeyword.KEEP_SIMULATIONS, type = IType.BOOL, optional = true, doc = @doc("In the case of a batch experiment, specifies whether or not the simulations should be kept in memory for further analysis or immediately discarded with only their fitness kept in memory")), @facet(name = IKeyword.REPEAT, type = IType.INT, optional = true, doc = @doc("In the case of a batch experiment, expresses hom many times the simulations must be repeated")), @facet(name = IKeyword.UNTIL, type = IType.BOOL, optional = true, doc = @doc("In the case of a batch experiment, an expression that will be evaluated to know when a simulation should be terminated")), - @facet(name = IKeyword.MULTICORE, type = IType.BOOL, optional = true, doc = @doc("Allows the experiment, when set to true, to use multiple threads to run its simulations")), + @facet(name = IKeyword.PARALLEL, type = { IType.BOOL, + IType.INT }, optional = true, doc = @doc("When set to true, use multiple threads to run its simulations. Setting it to n will set the numbers of threads to use")), @facet(name = IKeyword.TYPE, type = IType.LABEL, values = { IKeyword.BATCH, IKeyword.MEMORIZE, /* IKeyword.REMOTE, */IKeyword.GUI_, IKeyword.HEADLESS_UI }, optional = false, doc = @doc("the type of the experiment (either 'gui' or 'batch'")) }, omissible = IKeyword.NAME) @@ -126,12 +136,69 @@ public void validate(final IDescription desc) { protected IExploration exploration; private FileOutput log; private boolean isHeadless; - private final boolean isMulticore; private final boolean keepSeed; private final boolean keepSimulations; - private final String experimentType; + public class ExperimentPopulation extends GamaPopulation { + + public ExperimentPopulation(final ISpecies expr) { + super(null, expr); + } + + @Override + public IList createAgents(final IScope scope, final int number, + final List> initialValues, final boolean isRestored, + final boolean toBeScheduled) throws GamaRuntimeException { + for (int i = 0; i < number; i++) { + agent = GamaMetaModel.INSTANCE.createExperimentAgent(getExperimentType(), this); + agent.setIndex(currentAgentIndex++); + add(agent); + scope.push(agent); + createVariables(scope, agent, initialValues.isEmpty() ? Collections.EMPTY_MAP : initialValues.get(i)); + } + return this; + } + + public void createVariables(final IScope scope, final IAgent a, final Map inits) + throws GamaRuntimeException { + final Set names = inits.keySet(); + try { + for (final String s : orderedVarNames) { + final IVariable var = getVar(s); + var.initializeWith(scope, a, inits.get(s)); + names.remove(s); + } + for (final String s : names) { + a.getScope().setAgentVarValue(a, s, inits.get(s)); + } + } finally { + } + + } + + @Override + protected boolean stepAgents(final IScope scope) { + return scope.step(agent).passed(); + } + + @Override + public ExperimentAgent getAgent(final IScope scope, final ILocation value) { + return agent; + } + + @Override + public IMacroAgent getHost() { + return null; + } + + @Override + public void computeTopology(final IScope scope) throws GamaRuntimeException { + topology = new AmorphousTopology(); + } + + } + @Override public boolean isHeadless() { return GAMA.isInHeadLessMode() || isHeadless; @@ -157,9 +224,6 @@ public ExperimentPlan(final IDescription description) { } else if (experimentType.equals(IKeyword.HEADLESS_UI)) { setHeadless(true); } - final IExpression coreExpr = getFacet(IKeyword.MULTICORE); - isMulticore = (coreExpr == null ? GamaPreferences.MULTITHREADED_SIMULATIONS.getValue() - : coreExpr.literalValue().equals(IKeyword.TRUE)) && !isHeadless(); final IExpression expr = getFacet(IKeyword.KEEP_SEED); if (expr != null && expr.isConst()) keepSeed = Cast.asBool(scope, expr.value(scope)); @@ -173,11 +237,6 @@ public ExperimentPlan(final IDescription description) { } - @Override - public boolean isMulticore() { - return isMulticore; - } - @Override public boolean keepsSeed() { return keepSeed; diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPopulation.java b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPopulation.java deleted file mode 100644 index 1915dd9f7c..0000000000 --- a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentPopulation.java +++ /dev/null @@ -1,92 +0,0 @@ -/********************************************************************************************* - * - * - * 'ExperimentPopulation.java', in plugin 'msi.gama.core', is part of the source code of the - * GAMA modeling and simulation platform. - * (c) 2007-2014 UMI 209 UMMISCO IRD/UPMC & Partners - * - * Visit https://code.google.com/p/gama-platform/ for license information and developers contact. - * - * - **********************************************************************************************/ -package msi.gama.kernel.experiment; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import msi.gama.metamodel.agent.IAgent; -import msi.gama.metamodel.agent.IMacroAgent; -import msi.gama.metamodel.population.GamaPopulation; -import msi.gama.metamodel.shape.ILocation; -import msi.gama.metamodel.topology.continuous.AmorphousTopology; -import msi.gama.runtime.IScope; -import msi.gama.runtime.exceptions.GamaRuntimeException; -import msi.gama.util.GamaListFactory; -import msi.gama.util.IList; -import msi.gaml.compilation.kernel.GamaMetaModel; -import msi.gaml.species.ISpecies; -import msi.gaml.types.Types; -import msi.gaml.variables.IVariable; - -public class ExperimentPopulation extends GamaPopulation { - - public ExperimentPopulation(final ISpecies expr) { - super(null, expr); - } - - @Override - public IList createAgents(final IScope scope, final int number, - final List> initialValues, final boolean isRestored, - final boolean toBeScheduled) throws GamaRuntimeException { - for (int i = 0; i < number; i++) { - final ExperimentAgent exp = GamaMetaModel.INSTANCE - .createExperimentAgent(((ExperimentPlan) getSpecies()).getExperimentType(), this); - exp.setIndex(currentAgentIndex++); - add(exp); - scope.push(exp); - createVariables(scope, exp, initialValues.isEmpty() ? Collections.EMPTY_MAP : initialValues.get(i)); - } - return this; - } - - public void createVariables(final IScope scope, final IAgent a, final Map inits) - throws GamaRuntimeException { - final Set names = inits.keySet(); - try { - for (final String s : orderedVarNames) { - final IVariable var = species.getVar(s); - var.initializeWith(scope, a, inits.get(s)); - names.remove(s); - } - for (final String s : names) { - a.getScope().setAgentVarValue(a, s, inits.get(s)); - } - } finally { - } - - } - - @Override - public IList computeAgentsToSchedule(final IScope scope) { - return GamaListFactory.create(scope, Types.AGENT, /* agents. */Arrays.asList(get(0))); - } - - @Override - public ExperimentAgent getAgent(final IScope scope, final ILocation value) { - return get(null, 0); - } - - @Override - public IMacroAgent getHost() { - return null; - } - - @Override - public void computeTopology(final IScope scope) throws GamaRuntimeException { - topology = new AmorphousTopology(); - } - -} \ No newline at end of file diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentScheduler.java b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentScheduler.java index 2edb60c160..eea2fa4537 100644 --- a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentScheduler.java +++ b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentScheduler.java @@ -83,17 +83,12 @@ public void step() { } } - // GAMA.getGui().debug("ExperimentScheduler.step"); stepables = toStep.keySet().toArray(new IStepable[toStep.size()]); scopes = toStep.values().toArray(new IScope[toStep.size()]); for (int i = 0; i < stepables.length; i++) { final IScope scope = scopes[i]; try { - // GAMA.getGui().debug("ExperimentScheduler.step : stepping " + - // stepables[i]); - if (!scope.step(stepables[i])) { - // GAMA.getGui().debug("ExperimentScheduler.step : removal - // of " + stepables[i]); + if (!scope.step(stepables[i]).passed()) { toStop.add(stepables[i]); } } catch (final Exception e) { @@ -164,7 +159,7 @@ public void schedule(final IStepable stepable, final IScope scope) { // We first init the stepable before it is scheduled // GAMA.getGui().debug("ExperimentScheduler.schedule " + stepable); try { - if (!scope.init(stepable)) { + if (!scope.init(stepable).passed()) { toStop.add(stepable); } } catch (final Throwable e) { diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/IExperimentPlan.java b/msi.gama.core/src/msi/gama/kernel/experiment/IExperimentPlan.java index 752bcbb279..5b2fe39f44 100644 --- a/msi.gama.core/src/msi/gama/kernel/experiment/IExperimentPlan.java +++ b/msi.gama.core/src/msi/gama/kernel/experiment/IExperimentPlan.java @@ -47,8 +47,6 @@ public interface IExperimentPlan extends ISpecies { public abstract boolean isGui(); - public boolean isMulticore(); - public abstract boolean hasParameter(String name); public ExperimentAgent getAgent(); diff --git a/msi.gama.core/src/msi/gama/kernel/simulation/SimulationAgent.java b/msi.gama.core/src/msi/gama/kernel/simulation/SimulationAgent.java index 1e416b09f3..0db968cd9a 100644 --- a/msi.gama.core/src/msi/gama/kernel/simulation/SimulationAgent.java +++ b/msi.gama.core/src/msi/gama/kernel/simulation/SimulationAgent.java @@ -121,6 +121,7 @@ public class SimulationAgent extends GamlAgent implements ITopLevelAgent { private final RandomUtils random; private final ActionExecuter executer; private RootTopology topology; + // Added here to be sure to public SimulationAgent(final IPopulation pop) { this((SimulationPopulation) pop); @@ -199,47 +200,30 @@ public void setColor(final GamaColor color) { @Override public void schedule(final IScope scope) { - - // this.prepareGuiForSimulation(scope); super.schedule(this.getScope()); } @Override - // TODO A redefinition of this method in GAML will lose all information - // regarding the clock and the advance of time, - // which will have to be done manually (i.e. cycle <- cycle + 1; time <- - // time + step;). The outputs will not be stepped neither - public Object _step_(final IScope scope) { - - // hqnghi check the on_user_hold in case that micro-model use an - // user_panel - // AD: removing the fix by Nghi temporarily. But it needs to be checked - // more - // carefully - // if (!scope.isOnUserHold()) { + protected boolean preStep(final IScope scope) { clock.beginCycle(); - // A simulation always runs in its own scope - try { - executer.executeBeginActions(); - super._step_(this.getScope()); - executer.executeEndActions(); - executer.executeOneShotActions(); - - if (outputs != null) { - outputs.step(this.getScope()); - } - } finally { - clock.step(this.getScope()); + executer.executeBeginActions(); + return super.preStep(scope); + } + + @Override + protected void postStep(final IScope scope) { + super.postStep(scope); + executer.executeEndActions(); + executer.executeOneShotActions(); + if (outputs != null) { + outputs.step(this.getScope()); } - // } - return this; + clock.step(this.getScope()); } @Override public Object _init_(final IScope scope) { - // A simulation always runs in its own scope super._init_(this.getScope()); - if (outputs != null) { outputs.init(this.getScope()); } @@ -273,10 +257,9 @@ public void dispose() { executer.executeDisposeActions(); // hqnghi if simulation come from popultion extern, dispose pop first // and then their outputs - for (final IPopulation pop : getExternMicroPopulations().values()) { - pop.dispose(); - } - this.getExternMicroPopulations().clear(); + + if (externMicroPopulations != null) + externMicroPopulations.clear(); if (outputs != null) { outputs.dispose(); diff --git a/msi.gama.core/src/msi/gama/kernel/simulation/SimulationPopulation.java b/msi.gama.core/src/msi/gama/kernel/simulation/SimulationPopulation.java index b7041d879d..3f1b13e953 100644 --- a/msi.gama.core/src/msi/gama/kernel/simulation/SimulationPopulation.java +++ b/msi.gama.core/src/msi/gama/kernel/simulation/SimulationPopulation.java @@ -11,24 +11,10 @@ **********************************************************************************************/ package msi.gama.kernel.simulation; -import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; -import java.util.concurrent.TimeUnit; - -import com.google.common.util.concurrent.MoreExecutors; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -import msi.gama.common.GamaPreferences; + import msi.gama.common.interfaces.IKeyword; import msi.gama.kernel.experiment.ExperimentAgent; import msi.gama.kernel.experiment.ExperimentPlan; @@ -37,6 +23,9 @@ import msi.gama.metamodel.shape.ILocation; import msi.gama.metamodel.topology.continuous.AmorphousTopology; import msi.gama.runtime.IScope; +import msi.gama.runtime.concurrent.GamaExecutorService; +import msi.gama.runtime.concurrent.GamaExecutorService.Caller; +import msi.gama.runtime.concurrent.SimulationRunner; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.IList; import msi.gaml.species.ISpecies; @@ -46,36 +35,18 @@ public class SimulationPopulation extends GamaPopulation { private SimulationAgent currentSimulation; - - final ThreadFactory factory = new ThreadFactoryBuilder().setThreadFactory(Executors.defaultThreadFactory()) - .setNameFormat("Simulation thread #%d of experiment " + getSpecies().getName()).build(); - ExecutorService executor; - Map runnables = new LinkedHashMap(); - private int activeThreads; + private final SimulationRunner runner; public SimulationPopulation(final ExperimentAgent agent, final ISpecies species) { super(agent, species); - - } - - protected ExecutorService getExecutorService() { - if (executor == null) { - final boolean isMultiThreaded = getHost().getSpecies().isMulticore(); - final int numberOfThreads = GamaPreferences.NUMBERS_OF_THREADS.getValue(); - executor = isMultiThreaded ? new ThreadPoolExecutor(1, numberOfThreads, 100L, TimeUnit.MILLISECONDS, - new SynchronousQueue()) : MoreExecutors.sameThreadExecutor(); - if (executor instanceof ThreadPoolExecutor) { - final ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor; - tpe.setRejectedExecutionHandler(new CallerRunsPolicy()); - tpe.allowCoreThreadTimeOut(true); - } - } - return executor; + runner = new SimulationRunner(this); } public int getMaxNumberOfConcurrentSimulations() { - final boolean isMultiThreaded = getHost().getSpecies().isMulticore(); - return isMultiThreaded ? GamaPreferences.NUMBERS_OF_THREADS.getValue() : 1; + if (getHost().getSpecies().isHeadless()) + return 1; + return GamaExecutorService.getParallelism(getHost().getScope(), getSpecies().getConcurrency(), + Caller.SIMULATION); } /** @@ -86,7 +57,7 @@ public int getMaxNumberOfConcurrentSimulations() { @Override protected void fireAgentRemoved(final IAgent agent) { super.fireAgentRemoved(agent); - runnables.remove(agent); + runner.remove((SimulationAgent) agent); } @Override @@ -97,15 +68,7 @@ public void initializeFor(final IScope scope) { @Override public void dispose() { - if (executor != null) { - executor.shutdown(); - try { - executor.awaitTermination(1, TimeUnit.SECONDS); - } catch (final InterruptedException e) { - e.printStackTrace(); - } - executor = null; - } + runner.dispose(); currentSimulation = null; super.dispose(); } @@ -132,11 +95,7 @@ public IList createAgents(final IScope scope, final int number, } initSimulation(scope, currentSimulation, initialValues, isRestored, toBeScheduled); if (toBeScheduled) { - - // Necessary to put it in a final variable here, so that the - // runnable does not point on the instance variable (see #1836) - final SimulationAgent simulation = currentSimulation; - runnables.put(currentSimulation, () -> simulation.step(simulation.getScope())); + runner.add(currentSimulation); } } return this; @@ -147,14 +106,6 @@ private void initSimulation(final IScope scope, final SimulationAgent sim, final boolean toBeScheduled) { scope.getGui().getStatus().waitStatus("Instantiating agents"); if (toBeScheduled) { - // Necessary to put it here as the output manager is initialized - // *after* - // the agent, and variables may contain populations generating - // errors. - // Doing it after will remove - // everything in the errors/console view that is being written by - // the - // init of the simulation sim.prepareGuiForSimulation(scope); } createVariablesFor(sim.getScope(), Collections.singletonList(sim), initialValues); @@ -199,19 +150,8 @@ public void computeTopology(final IScope scope) throws GamaRuntimeException { } @Override - public boolean step(final IScope scope) throws GamaRuntimeException { - try { - getExecutorService().invokeAll(new ArrayList(runnables.values())); - if (getExecutorService() instanceof ThreadPoolExecutor) { - final ThreadPoolExecutor e = (ThreadPoolExecutor) executor; - activeThreads = e.getPoolSize(); - } else { - activeThreads = 1; - } - } catch (final InterruptedException e) { - e.printStackTrace(); - } - + protected boolean stepAgents(final IScope scope) { + runner.step(); return true; } @@ -222,18 +162,18 @@ public boolean step(final IScope scope) throws GamaRuntimeException { * @param sim */ public void unscheduleSimulation(final SimulationAgent sim) { - runnables.remove(sim); + runner.remove(sim); } public int getNumberOfActiveThreads() { - return activeThreads; + return runner.getActiveThreads(); } /** * @return */ public boolean hasScheduledSimulations() { - return runnables.size() > 0; + return runner.hasSimulations(); } public SimulationAgent lastSimulationCreated() { diff --git a/msi.gama.core/src/msi/gama/metamodel/agent/AbstractAgent.java b/msi.gama.core/src/msi/gama/metamodel/agent/AbstractAgent.java index 4a58c97875..559bddddd3 100644 --- a/msi.gama.core/src/msi/gama/metamodel/agent/AbstractAgent.java +++ b/msi.gama.core/src/msi/gama/metamodel/agent/AbstractAgent.java @@ -1,7 +1,7 @@ /********************************************************************************************* * * - * 'MinimalAgent.java', in plugin 'msi.gama.core', is part of the source code of the + * 'AbstractAgent.java', in plugin 'msi.gama.core', is part of the source code of the * GAMA modeling and simulation platform. * (c) 2007-2014 UMI 209 UMMISCO IRD/UPMC & Partners * @@ -42,7 +42,7 @@ /** * - * Class MinimalAgent. An abstract class that tries to minimize the number of + * Class AbstractAgent. An abstract class that tries to minimize the number of * attributes manipulated by agents. In particular, it declares no Geometry * (leaving the programmer the possibility to redeclare getGeometry(), for * example in a dynamic fashion), no Population (leaving the programmer the @@ -248,13 +248,61 @@ public boolean init(final IScope scope) throws GamaRuntimeException { return getSpecies().getArchitecture().init(scope); } + /** + * Method called repetitively by the simulation engine. Should not be + * redefined except in rare cases (like special forms of experiments, which + * need to define their own sequence) + */ @Override public boolean step(final IScope scope) throws GamaRuntimeException { - if (scope.update(this)) { - final Object[] result = new Object[1]; - return scope.execute(getSpecies().getArchitecture(), this, null, result); + boolean result = false; + try { + return result = preStep(scope) ? doStep(scope) : false; + } finally { + if (result) + postStep(scope); } - return false; + } + + /** + * This method contains everything to do *before* the actual step is done + * (runs of reflexes, etc.). The basis consists in updating the variables. + * + * @param scope + * the scope in which the agent is asked to do the preStep() + * @return r + */ + protected boolean preStep(final IScope scope) { + return scope.update(this).passed(); + } + + /** + * This method contains everything to do *during* during the step of an + * agent. The basis consists in asking the architecture to execute on this + * and, if successfull, to step its sub-populations (if any). Only called if + * the preStep() method has been sucessfull + * + * @param scope + * the scope in which the agent is asked to do the step + * @return whether or not the step has been successful (i.e. no errors, + * etc.) + */ + protected boolean doStep(final IScope scope) { + return scope.execute(getSpecies().getArchitecture(), this, null).passed() ? stepSubPopulations(scope) : false; + } + + protected boolean stepSubPopulations(final IScope scope) { + return true; + } + + /** + * This method contains everything to do *after* the actual step of the + * agent has been done. Only called if the doStep() method has been + * successful. + * + * @param scope + */ + protected void postStep(final IScope scope) { } @Override @@ -272,8 +320,8 @@ public IList getPeers() throws GamaRuntimeException { final IPopulation pop = getHost().getPopulationFor(this.getSpecies()); if (pop != null) { final IScope scope = getScope(); - final IList retVal = GamaListFactory. createWithoutCasting( - scope.getModelContext().getTypeNamed(getSpeciesName()), pop.toArray()); + final IList retVal = GamaListFactory. createWithoutCasting(scope.getType(getSpeciesName()), + pop.toArray()); retVal.remove(this); return retVal; } @@ -514,7 +562,7 @@ public Type getGeometricalType() { @Override public IType getType() { - return getScope().getModelContext().getTypeNamed(getSpeciesName()); + return getScope().getType(getSpeciesName()); } /** diff --git a/msi.gama.core/src/msi/gama/metamodel/agent/GamlAgent.java b/msi.gama.core/src/msi/gama/metamodel/agent/GamlAgent.java index 7a39ad9b17..c3b10a53a5 100644 --- a/msi.gama.core/src/msi/gama/metamodel/agent/GamlAgent.java +++ b/msi.gama.core/src/msi/gama/metamodel/agent/GamlAgent.java @@ -11,6 +11,7 @@ **********************************************************************************************/ package msi.gama.metamodel.agent; +import java.util.Arrays; import java.util.List; import com.google.common.collect.Iterables; @@ -41,11 +42,10 @@ public class GamlAgent extends MinimalAgent implements IMacroAgent { // hqnghi manipulate micro-models AD put it to null to have lazy // initialization (saves some bytes in each agent) protected GamaMap> externMicroPopulations; - - // FIXME Necessary to have this in all agents ? It seems that only - // simulations are concerned, and they can get this information directly - // from the meta-population returned by "agents". - protected int nbSubAgents = 0; + // Added to optimize the traversal of "non-minimal" agents that contain + // micropopulations + private IPopulation[] microPopulations; + static IPopulation[] NO_POP = new IPopulation[0]; // end-hqnghi @@ -66,16 +66,27 @@ public GamlAgent(final IPopulation gridPopulation, final IShap } @Override - protected Object stepSubPopulations(final IScope scope) { + public IPopulation[] getMicroPopulations() { if (getAttributes() == null) { - return this; + return NO_POP; } - for (final Object pop : getAttributes().values().toArray()) { - if (pop instanceof IPopulation) { - scope.step((IPopulation) pop); - } + if (microPopulations == null) { + microPopulations = Iterables.toArray(Iterables.filter(getAttributes().values(), IPopulation.class), + IPopulation.class); + if (microPopulations.length == 0) + microPopulations = NO_POP; + Arrays.parallelSort(microPopulations, (p1, p2) -> p1.isGrid() ? p2.isGrid() ? 0 : 1 : p2.isGrid() ? -1 : 0); } - return this; + return microPopulations; + } + + @Override + protected boolean stepSubPopulations(final IScope scope) { + for (final IPopulation pop : getMicroPopulations()) { + if (!scope.step(pop).passed()) + return false; + } + return true; } @Override @@ -218,18 +229,6 @@ public void dispose() { super.dispose(); } - static IPopulation[] NO_POP = new IPopulation[0]; - - @Override - public IPopulation[] getMicroPopulations() { - if (getAttributes() == null) { - return NO_POP; - } - final IPopulation[] pops = Iterables - .toArray(Iterables.filter(getAttributes().values(), IPopulation.class), IPopulation.class); - return pops; - } - @Override public synchronized IPopulation getMicroPopulation(final String microSpeciesName) { if (getAttributes() == null) { @@ -386,14 +385,15 @@ public IPopulation getExternMicroPopulationFor(final String ex } return null; } - - @Override - public GamaMap> getExternMicroPopulations() { - if (externMicroPopulations == null) { - return GamaMapFactory.create(); - } - return externMicroPopulations; - } + // + // @Override + // public GamaMap> + // getExternMicroPopulations() { + // if (externMicroPopulations == null) { + // return GamaMapFactory.create(); + // } + // return externMicroPopulations; + // } // @Override // public int getNbAgents() { diff --git a/msi.gama.core/src/msi/gama/metamodel/agent/IMacroAgent.java b/msi.gama.core/src/msi/gama/metamodel/agent/IMacroAgent.java index b98901fe82..32872fdb88 100644 --- a/msi.gama.core/src/msi/gama/metamodel/agent/IMacroAgent.java +++ b/msi.gama.core/src/msi/gama/metamodel/agent/IMacroAgent.java @@ -20,7 +20,6 @@ import msi.gama.precompiler.GamlAnnotations.vars; import msi.gama.runtime.IScope; import msi.gama.runtime.exceptions.GamaRuntimeException; -import msi.gama.util.GamaMap; import msi.gama.util.IContainer; import msi.gama.util.IList; import msi.gaml.species.ISpecies; @@ -179,7 +178,8 @@ public abstract IList releaseMicroAgents(IScope scope, final IList getExternMicroPopulationFor(final String expName); - public abstract GamaMap> getExternMicroPopulations(); + // public abstract GamaMap> + // getExternMicroPopulations(); // end-hqnghi } \ No newline at end of file diff --git a/msi.gama.core/src/msi/gama/metamodel/agent/MinimalAgent.java b/msi.gama.core/src/msi/gama/metamodel/agent/MinimalAgent.java index 666dc9a5f9..f5bd30f6b4 100644 --- a/msi.gama.core/src/msi/gama/metamodel/agent/MinimalAgent.java +++ b/msi.gama.core/src/msi/gama/metamodel/agent/MinimalAgent.java @@ -22,10 +22,16 @@ import msi.gama.util.graph.GamaGraph; import msi.gaml.species.GamlSpecies; import msi.gaml.species.ISpecies; -import msi.gaml.statements.IStatement; import msi.gaml.types.GamaGeometryType; @species(name = IKeyword.AGENT, doc = @doc("The species parent of all agent species")) +/** + * A concrete implementation of AbstractAgent that declares its own population, + * geometry and name. Base of most of the concrete subclasses of GAMA agents + * + * @author drogoul + * + */ public class MinimalAgent extends AbstractAgent { /** The population that this agent belongs to. */ @@ -132,14 +138,7 @@ public void setName(final String name) { return; } final Envelope previous = geometry.getEnvelope(); - // Envelope previousEnvelope = geometry.getEnvelope(); geometry.setLocation(newLocation); - // final Integer newHeading = - // topology.directionInDegreesTo(getScope(), previousPoint, - // newLocation); - // if ( newHeading != null && !getTopology().isTorus() ) { - // setHeading(newHeading); - // } topology.updateAgent(previous, this); // update micro-agents' locations accordingly @@ -189,7 +188,7 @@ public boolean isInstanceOf(final ISpecies s, final boolean direct) { /** * During the call to init, the agent will search for the action named * _init_ and execute it. Its default implementation is provided in this - * class as well. + * class as well (equivalent to a super.init()) * * @see GamlAgent#_init_() * @see msi.gama.common.interfaces.IStepable#step(msi.gama.runtime.IScope) @@ -202,15 +201,15 @@ public boolean init(final IScope scope) { if (!getSpecies().isInitOverriden()) { _init_(scope); } else { - executeCallbackAction(scope, getSpecies().getAction(ISpecies.initActionName)); + scope.execute(getSpecies().getAction(ISpecies.initActionName), this, null); } return !scope.interrupted(); } /** - * During the call to step, the agent will search for the action named + * During the call to doStep(), the agent will search for the action named * _step_ and execute it. Its default implementation is provided in this - * class as well. + * class as well (equivalent to a super.doStep()); * * @see GamlAgent#_step_() * @see msi.gama.common.interfaces.IStepable#step(msi.gama.runtime.IScope) @@ -219,54 +218,41 @@ public boolean init(final IScope scope) { * _step_(IScope) instead. */ @Override - public boolean step(final IScope scope) { + public boolean doStep(final IScope scope) { if (!getSpecies().isStepOverriden()) { _step_(scope); + return !scope.interrupted(); } else { - executeCallbackAction(scope, getSpecies().getAction(ISpecies.stepActionName)); + return scope.execute(getSpecies().getAction(ISpecies.stepActionName), this, null).passed(); } - return !scope.interrupted(); } /** - * Callback Actions - * + * The default init of agents consists in calling the super implementation + * of init() in order to realize the default init sequence + * + * @param scope + * @return */ - - protected Object executeCallbackAction(final IScope scope, final IStatement action) { - final Object[] callbackResult = new Object[1]; - scope.execute(action, this, null, callbackResult); - return callbackResult[0]; - } - @action(name = ISpecies.initActionName) public Object _init_(final IScope scope) { - getSpecies().getArchitecture().init(scope); - return this; - } - - @action(name = ISpecies.stepActionName) - public Object _step_(final IScope scope) { - scope.update(this); - // we ask the architecture to execute on this - final Object[] result = new Object[1]; - if (scope.execute(getSpecies().getArchitecture(), this, null, result)) { - // we ask the sub-populations to step their agents if any - return stepSubPopulations(scope); - } - return result[0]; + return super.init(scope); } /** + * The default step of agents consists in calling the super implementation + * of doStep() in order to realize the default step sequence + * * @param scope * @return */ - protected Object stepSubPopulations(final IScope scope) { - return this; + @action(name = ISpecies.stepActionName) + public Object _step_(final IScope scope) { + return super.doStep(scope); } /** - * Method getArea() + * Method getArea(). Simply delegates to the geometry * * @see msi.gama.metamodel.shape.IGeometricalShape#getArea() */ @@ -276,7 +262,7 @@ public Double getArea() { } /** - * Method getVolume() + * Method getVolume(). Simply delegates to the geometry * * @see msi.gama.metamodel.shape.IGeometricalShape#getVolume() */ @@ -388,7 +374,6 @@ public void updateWith(final IScope scope, final SavedAgent sa) { this.setDirectVarValue(scope, attr.getKey(), attr.getValue()); } - // Update microPop } } diff --git a/msi.gama.core/src/msi/gama/metamodel/population/GamaPopulation.java b/msi.gama.core/src/msi/gama/metamodel/population/GamaPopulation.java index 7035765760..1fa02a87de 100644 --- a/msi.gama.core/src/msi/gama/metamodel/population/GamaPopulation.java +++ b/msi.gama.core/src/msi/gama/metamodel/population/GamaPopulation.java @@ -20,7 +20,6 @@ import java.util.Map; import java.util.Set; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import gnu.trove.map.hash.THashMap; @@ -41,6 +40,7 @@ import msi.gama.metamodel.topology.grid.GamaSpatialMatrix; import msi.gama.metamodel.topology.grid.GridTopology; import msi.gama.runtime.IScope; +import msi.gama.runtime.concurrent.GamaExecutorService; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.GamaList; import msi.gama.util.GamaListFactory; @@ -95,7 +95,6 @@ public static GamaPopulation createPopulation(final IScope protected final IVariable[] updatableVars; protected int currentAgentIndex; protected final IArchitecture architecture; - protected final IExpression scheduleFrequency; /** * Listeners, created in a lazy way @@ -159,18 +158,24 @@ protected GamaPopulation(final IMacroAgent host, final ISpecies species) { .postEndAction(new MirrorPopulationManagement(species.getFacet(IKeyword.MIRRORS))); } - // Add an attribute to the agents (dans SpeciesDescription) - scheduleFrequency = species.getFrequency(); } @Override public boolean step(final IScope scope) throws GamaRuntimeException { - for (final T agent : ImmutableList.copyOf(computeAgentsToSchedule(scope))) { - if (!scope.step(agent)) { - continue; + 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; } } - return true; + return stepAgents(scope); + + } + + protected boolean stepAgents(final IScope scope) { + return GamaExecutorService.step(scope, this, getSpecies()); } @Override @@ -185,8 +190,6 @@ public void updateVariables(final IScope scope, final IAgent a) { public boolean init(final IScope scope) { return true; // // Do whatever the population has to do at the first step ? - // Ideally, the list of agents to init should be there rather than in - // the scheduler } @Override @@ -197,23 +200,6 @@ public void createVariablesFor(final IScope scope, final T agent) throws GamaRun } } - /** - * - * @see msi.gama.interfaces.IPopulation#computeAgentsToSchedule(msi.gama.interfaces.IScope, - * msi.gama.util.GamaList) - */ - // @Override - public Iterable computeAgentsToSchedule(final IScope scope) { - final int frequency = scheduleFrequency == null ? 1 : Cast.asInt(scope, scheduleFrequency.value(scope)); - final int step = scope.getClock().getCycle(); - if (frequency == 0 || step % frequency != 0) { - return Collections.EMPTY_LIST; - } - final IExpression ags = getSpecies().getSchedule(); - final IList agents = ags == null ? this : Cast.asList(scope, ags.value(scope)); - return agents; - } - @Override public T getAgent(final Integer index) { return Iterables.find(this, each -> each.getIndex() == index, null); @@ -466,7 +452,7 @@ protected void computeTopology(final IScope scope) throws GamaRuntimeException { final boolean fixed = species.isGraph() || species.isGrid(); if (expr != null) { if (!fixed) { - topology = GamaTopologyType.staticCast(scope, scope.evaluate(expr, host), false); + topology = GamaTopologyType.staticCast(scope, scope.evaluate(expr, host).getValue(), false); return; } throw GamaRuntimeException.warning( @@ -478,7 +464,7 @@ protected void computeTopology(final IScope scope) throws GamaRuntimeException { final IExpression spec = species.getFacet(IKeyword.EDGE_SPECIES); final String edgeName = spec == null ? "base_edge" : spec.literalValue(); final ISpecies edgeSpecies = scope.getSimulation().getModel().getSpecies(edgeName); - final IType edgeType = scope.getModelContext().getTypeNamed(edgeName); + final IType edgeType = scope.getType(edgeName); final IType nodeType = getType().getContentType(); // TODO Specifier directed quelque part dans l'esp�ce final GamaSpatialGraph g = new GamaSpatialGraph(GamaListFactory.create(), false, false, @@ -746,7 +732,6 @@ public boolean accept(final IScope scope, final IShape source, final IShape a) { return false; } final IAgent as = source.getAgent(); - // if ( as != null && as.getPopulation() != pop ) { if (agent == as) { return false; } diff --git a/msi.gama.core/src/msi/gama/metamodel/topology/GamaQuadTree.java b/msi.gama.core/src/msi/gama/metamodel/topology/GamaQuadTree.java index 830cef590b..7c5c4cf489 100644 --- a/msi.gama.core/src/msi/gama/metamodel/topology/GamaQuadTree.java +++ b/msi.gama.core/src/msi/gama/metamodel/topology/GamaQuadTree.java @@ -12,10 +12,10 @@ package msi.gama.metamodel.topology; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.concurrent.ConcurrentLinkedQueue; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; @@ -171,10 +171,10 @@ private class QuadNode { private final Envelope bounds; private final double halfx, halfy; - private QuadNode[] nodes = null; + private volatile QuadNode[] nodes = null; // ** Addresses part of Issue 722 -- Need to keep the objects ordered // (by insertion order) ** - private Collection objects = null; + private volatile ConcurrentLinkedQueue objects = null; private final boolean canSplit; public QuadNode(final Envelope bounds) { @@ -200,11 +200,8 @@ public void dispose() { public IShape remove(final Coordinate p, final IShape a) { if (objects != null) { - final boolean removed = false; - synchronized (objects) { - if (objects.remove(a)) - return a; - } + if (objects.remove(a)) + return a; } else if (nodes != null) { return nodes[quadrant(p)].remove(p, a); } @@ -221,11 +218,9 @@ public boolean add(final Coordinate p, final IAgent a) { } if (nodes == null) { if (objects == null) { - objects = new ArrayList(maxCapacity + 5); - } - synchronized (objects) { - return objects.add(a); + objects = new ConcurrentLinkedQueue(); } + return objects.add(a); } else return nodes[quadrant(p)].add(p, a); } @@ -239,9 +234,7 @@ int quadrant(final Coordinate p) { public boolean remove(final Envelope bounds, final IShape a) { if (nodes == null) { if (objects != null) { - synchronized (objects) { - return objects.remove(a); - } + return objects.remove(a); } else return false; } @@ -260,12 +253,9 @@ public boolean add(final Envelope env, final IAgent o) { } if (nodes == null) { if (objects == null) { - objects = new ArrayList(maxCapacity + 5); - } - synchronized (objects) { - return objects.add(o); + objects = new ConcurrentLinkedQueue(); } - + return objects.add(o); } boolean retVal = false; for (final QuadNode node : nodes) @@ -284,31 +274,28 @@ public void split() { new QuadNode(new Envelope(halfx, maxx, miny, halfy)), new QuadNode(new Envelope(minx, halfx, halfy, maxy)), new QuadNode(new Envelope(halfx, maxx, halfy, maxy)) }; - IAgent[] tempList; - synchronized (objects) { - tempList = objects.toArray(new IAgent[objects.size()]); - } - objects = null; - for (final IAgent entry : tempList) { - if (!entry.dead()) { - final IShape g = entry.getGeometry(); - if (g.isPoint()) { - add((Coordinate) g.getLocation(), entry); - } else { - add(g.getEnvelope(), entry); + + if (objects != null) {// Can happen in concurrent executions + for (final IAgent entry : objects) { + if (entry != null && !entry.dead()) { + final IShape g = entry.getGeometry(); + if (g.isPoint()) { + add((Coordinate) g.getLocation(), entry); + } else { + add(g.getEnvelope(), entry); + } } } + objects = null; } } public void findIntersects(final Envelope r, final Collection result) { if (bounds.intersects(r)) { if (objects != null) { - synchronized (objects) { - for (final IShape entry : objects) { - if (entry.getEnvelope().intersects(r)) { - result.add(entry.getAgent()); - } + for (final IShape entry : objects) { + if (entry.getEnvelope().intersects(r)) { + result.add(entry.getAgent()); } } } diff --git a/msi.gama.core/src/msi/gama/metamodel/topology/grid/GamaSpatialMatrix.java b/msi.gama.core/src/msi/gama/metamodel/topology/grid/GamaSpatialMatrix.java index d2f51ae066..66e49ce2de 100644 --- a/msi.gama.core/src/msi/gama/metamodel/topology/grid/GamaSpatialMatrix.java +++ b/msi.gama.core/src/msi/gama/metamodel/topology/grid/GamaSpatialMatrix.java @@ -30,11 +30,9 @@ import gnu.trove.iterator.TIntIterator; import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.TIntHashSet; -import msi.gama.common.GamaPreferences; import msi.gama.common.interfaces.IKeyword; import msi.gama.common.util.JavaUtils; import msi.gama.common.util.RandomUtils; -import msi.gama.kernel.experiment.ITopLevelAgent; import msi.gama.metamodel.agent.AbstractAgent; import msi.gama.metamodel.agent.GamlAgent; import msi.gama.metamodel.agent.IAgent; @@ -49,9 +47,8 @@ import msi.gama.metamodel.shape.IShape; import msi.gama.metamodel.topology.ITopology; import msi.gama.metamodel.topology.filter.IAgentFilter; -import msi.gama.runtime.ParallelAgentRunner; -import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; +import msi.gama.runtime.concurrent.GamaExecutorService; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.GamaColor; import msi.gama.util.GamaListFactory; @@ -85,14 +82,6 @@ @SuppressWarnings({ "unchecked", "rawtypes" }) public class GamaSpatialMatrix extends GamaMatrix implements IGrid { - static { - // Explicitly sets the number of threads for parallel operations on the - // grid - if (GamaPreferences.GRID_OPTIMIZATION.getValue()) - System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", - String.valueOf(GamaPreferences.NUMBERS_OF_GRID_THREADS.getValue())); - } - /** The geometry of host. */ public final boolean useIndividualShapes; @@ -141,7 +130,7 @@ public IContainerType getPreciseType(final IScope scope) { if (cellSpecies == null) { return super.getType(); } else { - return Types.MATRIX.of(scope.getModelContext().getTypeNamed(cellSpecies.getName())); + return Types.MATRIX.of(scope.getType(cellSpecies.getName())); } } @@ -374,7 +363,7 @@ public double[] getGridValueOf(final IScope scope, final IExpression exp) { if (s != null) { final IAgent a = s.getAgent(); if (a != null) { - result[i] = Cast.asFloat(scope, scope.evaluate(exp, a)); + result[i] = Cast.asFloat(scope, scope.evaluate(exp, a).getValue()); } } @@ -1212,33 +1201,8 @@ public String serialize(final boolean includingBuiltIn) { } @Override - public boolean step(final IScope scope) throws GamaRuntimeException { - final IExpression ags = getSpecies().getSchedule(); - if (ags != null) { - // In case there is a schedule specified, we do the "normal" - // step - return super.step(scope); - } - final int frequency = scheduleFrequency == null ? 1 : Cast.asInt(scope, scheduleFrequency.value(scope)); - final int step = scope.getClock().getCycle(); - if (frequency == 0 || step % frequency != 0) { - return true; - } - - if (GamaPreferences.GRID_OPTIMIZATION.getValue()) { - // Important for each agent to be executed in its own scope - final ITopLevelAgent agent = scope.getRoot(); - GAMA.executeThreaded(ParallelAgentRunner.step(scope, matrix)); - } else { - // We can keep the same scope for sequential steps - for (final IShape s : matrix) { - if (!scope.step((IAgent) s)) { - return false; - } - } - } - - return true; + protected boolean stepAgents(final IScope scope) { + return GamaExecutorService.step(scope, matrix, getSpecies()); } public int getNbCols() { @@ -1714,43 +1678,10 @@ public IList getBands() { return bands.get(getIndex()); } - // // hqnghi must-implement methods from GamlAgent - // @Override - // public void addExternMicroPopulation(final String expName, final - // IPopulation pop) { - // // TODO Auto-generated method stub - // - // } - // - // @Override - // public IPopulation getExternMicroPopulationFor(final String - // expName) { - // // TODO Auto-generated method stub - // return null; - // } - // - // @Override - // public Map getExternMicroPopulations() { - // // TODO Auto-generated method stub - // return null; - // } - // // end-hqnghi - } } - // private class IntToAgents implements Function { - // - // @Override - // public IAgent apply(final Integer input) { - // return matrix[input].getAgent(); - // } - // - // } - // - // private final Function intToAgents = new IntToAgents(); - /** * Method usesNeighborsCache() * @@ -1772,16 +1703,6 @@ protected IShape getNthElement(final Integer index) { return matrix[index]; } - /** - * Method getGridValueOfColorAttribute() - * - * @see msi.gama.metamodel.topology.grid.IGrid#getGridValueOfColorAttribute() - */ - @Override - public double[] getGridValueOfColorAttribute() { - return null; - } - @Override public Collection allAgents() { return this.getAgents(); diff --git a/msi.gama.core/src/msi/gama/metamodel/topology/grid/IGrid.java b/msi.gama.core/src/msi/gama/metamodel/topology/grid/IGrid.java index 21c0711c5c..33da2f373d 100644 --- a/msi.gama.core/src/msi/gama/metamodel/topology/grid/IGrid.java +++ b/msi.gama.core/src/msi/gama/metamodel/topology/grid/IGrid.java @@ -111,9 +111,4 @@ public abstract Set getNeighborsOf(final IScope scope, final IShape shap */ public abstract ISpecies getCellSpecies(); - /** - * @return - */ - public abstract double[] getGridValueOfColorAttribute(); - } diff --git a/msi.gama.core/src/msi/gama/outputs/AbstractOutputManager.java b/msi.gama.core/src/msi/gama/outputs/AbstractOutputManager.java index d86b9c4118..48f2603c97 100644 --- a/msi.gama.core/src/msi/gama/outputs/AbstractOutputManager.java +++ b/msi.gama.core/src/msi/gama/outputs/AbstractOutputManager.java @@ -144,7 +144,7 @@ private Iterable getDisplayOutputs() { public boolean init(final IScope scope) { for (final IOutput output : ImmutableList.copyOf(this)) { - if (scope.init(output)) { + if (scope.init(output).passed()) { output.setPaused(false); if (initialStep(scope, output)) { try { @@ -162,13 +162,13 @@ public boolean init(final IScope scope) { } protected boolean initialStep(final IScope scope, final IOutput output) { - return scope.step(output); + return scope.step(output).passed(); } @Override public boolean step(final IScope scope) { final ImmutableList stepable = ImmutableList - .copyOf(Iterables.filter(this, each -> each.isRefreshable() && each.getScope().step(each))); + .copyOf(Iterables.filter(this, each -> each.isRefreshable() && each.getScope().step(each).passed())); for (final IOutput o : stepable) { o.update(); } diff --git a/msi.gama.core/src/msi/gama/outputs/FileOutput.java b/msi.gama.core/src/msi/gama/outputs/FileOutput.java index 15d53c73bd..356a85372f 100644 --- a/msi.gama.core/src/msi/gama/outputs/FileOutput.java +++ b/msi.gama.core/src/msi/gama/outputs/FileOutput.java @@ -294,7 +294,7 @@ public void update() throws GamaRuntimeException { public void doRefreshWriteAndClose(final ParametersSet sol, final Object fitness) throws GamaRuntimeException { setSolution(sol); if (fitness == null) { - if (!getScope().step(this)) { + if (!getScope().step(this).passed()) { return; } } else { diff --git a/msi.gama.core/src/msi/gama/outputs/InspectDisplayOutput.java b/msi.gama.core/src/msi/gama/outputs/InspectDisplayOutput.java index 5b8d44c049..2d88c49caf 100644 --- a/msi.gama.core/src/msi/gama/outputs/InspectDisplayOutput.java +++ b/msi.gama.core/src/msi/gama/outputs/InspectDisplayOutput.java @@ -237,7 +237,7 @@ private InspectDisplayOutput(final IMacroAgent agent, final IExpression agents) } public void launch(final IScope scope) throws GamaRuntimeException { - if (!scope.init(InspectDisplayOutput.this)) { + if (!scope.init(InspectDisplayOutput.this).passed()) { return; } // What to do in case of multi-simulations ??? @@ -262,7 +262,7 @@ public boolean step(final IScope scope) { return false; } getScope().setCurrentSymbol(this); - lastValue = getScope().evaluate(getValue(), rootAgent); + lastValue = getScope().evaluate(getValue(), rootAgent).getValue(); } return true; } diff --git a/msi.gama.core/src/msi/gama/outputs/LayeredDisplayOutput.java b/msi.gama.core/src/msi/gama/outputs/LayeredDisplayOutput.java index 058f04f3da..f088e1a923 100644 --- a/msi.gama.core/src/msi/gama/outputs/LayeredDisplayOutput.java +++ b/msi.gama.core/src/msi/gama/outputs/LayeredDisplayOutput.java @@ -259,7 +259,7 @@ public boolean init(final IScope scope) throws GamaRuntimeException { for (final ILayerStatement layer : getLayers()) { // try { layer.setDisplayOutput(this); - if (!getScope().init(layer)) { + if (!getScope().init(layer).passed()) { return false; } // } catch (final GamaRuntimeException e) { diff --git a/msi.gama.core/src/msi/gama/outputs/MonitorOutput.java b/msi.gama.core/src/msi/gama/outputs/MonitorOutput.java index 64d0a9fad2..f5260d5168 100644 --- a/msi.gama.core/src/msi/gama/outputs/MonitorOutput.java +++ b/msi.gama.core/src/msi/gama/outputs/MonitorOutput.java @@ -80,7 +80,7 @@ public MonitorOutput(final IScope scope, final String name, final String expr) { name == null ? expr : name)); setScope(scope.copy("in monitor '" + expr + "'")); setNewExpressionText(expr); - if (getScope().init(this)) { + if (getScope().init(this).passed()) { getScope().getSimulation().addOutput(this); setPaused(false); open(); @@ -152,7 +152,7 @@ public boolean isUnique() { public boolean setNewExpressionText(final String string) { expressionText = string; setValue(GAML.compileExpression(string, getScope().getSimulation(), true)); - return getScope().step(this); + return getScope().step(this).passed(); } public void setNewExpression(final IExpression expr) throws GamaRuntimeException { diff --git a/msi.gama.core/src/msi/gama/outputs/layers/AgentLayer.java b/msi.gama.core/src/msi/gama/outputs/layers/AgentLayer.java index 1e04f65d42..ecce494f34 100644 --- a/msi.gama.core/src/msi/gama/outputs/layers/AgentLayer.java +++ b/msi.gama.core/src/msi/gama/outputs/layers/AgentLayer.java @@ -25,6 +25,7 @@ import msi.gama.metamodel.agent.IAgent; import msi.gama.metamodel.shape.IShape; import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.ExecutionResult; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gaml.statements.AspectStatement; import msi.gaml.statements.IExecutable; @@ -79,9 +80,8 @@ public void privateDrawDisplay(final IScope scope, final IGraphics g) throws Gam aspect = AspectStatement.DEFAULT_ASPECT; } - final Object[] result = new Object[1]; - scope.execute(aspect, a, null, result); - final Rectangle2D r = (Rectangle2D) result[0]; + final ExecutionResult result = scope.execute(aspect, a, null); + final Rectangle2D r = (Rectangle2D) result.getValue(); // final Rectangle2D r = aspect.draw(scope, a); if (r != null) { shapes.put(a, r); @@ -94,9 +94,8 @@ public void privateDrawDisplay(final IScope scope, final IGraphics g) throws Gam if (a != null/* && !scope.interrupted() */ ) { final IExecutable aspect = AspectStatement.DEFAULT_ASPECT; - final Object[] result = new Object[1]; - scope.execute(aspect, a, null, result); - final Rectangle2D r = (Rectangle2D) result[0]; + final ExecutionResult result = scope.execute(aspect, a, null); + final Rectangle2D r = (Rectangle2D) result.getValue(); // final Rectangle2D r = aspect.draw(scope, a); if (r != null) { shapes.put(a, r); diff --git a/msi.gama.core/src/msi/gama/outputs/layers/EventLayer.java b/msi.gama.core/src/msi/gama/outputs/layers/EventLayer.java index cb2dc439d0..64c03f979c 100644 --- a/msi.gama.core/src/msi/gama/outputs/layers/EventLayer.java +++ b/msi.gama.core/src/msi/gama/outputs/layers/EventLayer.java @@ -200,15 +200,7 @@ private void executeEvent(final int x, final int y) { return; } } - GAMA.runAndUpdateAll(new Runnable() { - - final Object[] result = new Object[1]; - - @Override - public void run() { - executionScope.execute(executer, agent, null, result); - } - }); + GAMA.runAndUpdateAll(() -> executionScope.execute(executer, agent, null)); } diff --git a/msi.gama.core/src/msi/gama/outputs/layers/GraphicLayer.java b/msi.gama.core/src/msi/gama/outputs/layers/GraphicLayer.java index df5df58c63..8b20444729 100644 --- a/msi.gama.core/src/msi/gama/outputs/layers/GraphicLayer.java +++ b/msi.gama.core/src/msi/gama/outputs/layers/GraphicLayer.java @@ -11,7 +11,8 @@ **********************************************************************************************/ package msi.gama.outputs.layers; -import msi.gama.common.interfaces.*; +import msi.gama.common.interfaces.IGraphics; +import msi.gama.common.interfaces.IKeyword; import msi.gama.metamodel.agent.IAgent; import msi.gama.runtime.IScope; import msi.gama.runtime.exceptions.GamaRuntimeException; @@ -24,9 +25,8 @@ protected GraphicLayer(final ILayerStatement layer) { @Override protected void privateDrawDisplay(final IScope scope, final IGraphics g) throws GamaRuntimeException { - Object[] result = new Object[1]; - IAgent agent = scope.getAgent(); - scope.execute(((GraphicLayerStatement) definition).getAspect(), agent, null, result); + final IAgent agent = scope.getAgent(); + scope.execute(((GraphicLayerStatement) definition).getAspect(), agent, null); } @Override @@ -34,5 +34,4 @@ public String getType() { return IKeyword.GRAPHICS; } - } diff --git a/msi.gama.core/src/msi/gama/outputs/layers/OverlayLayer.java b/msi.gama.core/src/msi/gama/outputs/layers/OverlayLayer.java index d4c14c0a5a..5c05b0cd67 100644 --- a/msi.gama.core/src/msi/gama/outputs/layers/OverlayLayer.java +++ b/msi.gama.core/src/msi/gama/outputs/layers/OverlayLayer.java @@ -46,9 +46,8 @@ public String getType() { @Override protected void privateDrawDisplay(final IScope scope, final IGraphics g) throws GamaRuntimeException { g.setOpacity(1); - final Object[] result = new Object[1]; final IAgent agent = scope.getAgent(); - scope.execute(((OverlayStatement) definition).getAspect(), agent, null, result); + scope.execute(((OverlayStatement) definition).getAspect(), agent, null); } @Override diff --git a/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayer.java b/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayer.java index 90e2ffdd73..5fe2ad96a1 100644 --- a/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayer.java +++ b/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayer.java @@ -22,6 +22,7 @@ import msi.gama.metamodel.agent.IMacroAgent; import msi.gama.metamodel.population.IPopulation; import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.ExecutionResult; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gaml.species.ISpecies; import msi.gaml.statements.AspectStatement; @@ -78,18 +79,18 @@ private void drawPopulation(final IScope scope, final IGraphics g, final Species if (a == null || a.dead()) { continue; } - final Object[] result = new Object[1]; + ExecutionResult result; if (a == scope.getGui().getHighlightedAgent()) { IExecutable hAspect = population.getSpecies().getAspect("highlighted"); if (hAspect == null) { hAspect = aspect; // hAspect = AspectStatement.HIGHLIGHTED_ASPECT; } - scope.execute(hAspect, a, null, result); + result = scope.execute(hAspect, a, null); } else { - scope.execute(aspect, a, null, result); + result = scope.execute(aspect, a, null); } - final Rectangle2D r = (Rectangle2D) result[0]; + final Rectangle2D r = (Rectangle2D) result.getValue(); if (r != null) { shapes.put(a, r); } diff --git a/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayerStatement.java b/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayerStatement.java index 1667d8fa94..f1042bb530 100644 --- a/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayerStatement.java +++ b/msi.gama.core/src/msi/gama/outputs/layers/SpeciesLayerStatement.java @@ -131,7 +131,7 @@ public boolean _init(final IScope scope) throws GamaRuntimeException { if (super._init(scope)) { for (final SpeciesLayerStatement microLayer : microSpeciesLayers) { microLayer.setHostSpecies(species); - if (!scope.init(microLayer)) { + if (!scope.init(microLayer).passed()) { return false; } } diff --git a/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java b/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java index 3a46a39128..48f2907990 100644 --- a/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java +++ b/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java @@ -1,94 +1,100 @@ package msi.gama.runtime; +import java.util.Collections; import java.util.Map; import gnu.trove.map.hash.THashMap; -public class ExecutionContext extends THashMap implements IExecutionContext.Statement { +public class ExecutionContext implements IExecutionContext { - IExecutionContext outer; + Map local; + final IExecutionContext outer; public ExecutionContext() { this(null); } - private ExecutionContext(final IExecutionContext previous) { - super(5); - this.outer = previous; + ExecutionContext(final IExecutionContext outer) { + this.outer = outer; } @Override - public void setVar(final String name, final Object value) { - final int i = index(name); - if (i == -1) { - if (outer != null) - outer.setVar(name, value); - } else { - _values[i] = value; - } + public final IExecutionContext getOuterContext() { + return outer; } @Override - public Object getVar(final String name) { - final int i = index(name); - if (i < 0) { - if (outer == null) - return null; - return outer.getVar(name); + public void setTempVar(final String name, final Object value) { + if (local == null || !local.containsKey(name)) { + if (outer != null) + outer.setTempVar(name, value); + } else { + local.put(name, value); } - return _values[i]; + } @Override - public boolean hasVar(final String name) { - return index(name) >= 0 || outer != null && outer.hasVar(name); + public Object getTempVar(final String name) { + if (local == null || !local.containsKey(name)) + return outer == null ? null : outer.getTempVar(name); + // if (name == ExecutionScope.EACH) + // System.out.println("EACH value found in context " + this); + return local.get(name); } @Override - public ExecutionContext copy() { + public ExecutionContext createCopyContext() { final ExecutionContext r = new ExecutionContext(outer); - r.putAll(this); + if (local != null) + r.local = new THashMap(local); return r; } @Override - public IExecutionContext.Statement getOuter() { - return (Statement) outer; - } - - @Override - public Map getAllOwnVars() { - return this; + public Map getLocalVars() { + return local == null ? Collections.EMPTY_MAP : local; } @Override - public void clearOwnVars() { - clear(); + public void clearLocalVars() { + local = null; } @Override - public void putOwnVar(final String varName, final Object val) { - put(varName, val); + public void putLocalVar(final String varName, final Object val) { + if (local == null) + local = new THashMap<>(); + // if (varName == ExecutionScope.EACH) + // System.out.println("EACH value set to " + val + " in context " + + // this); + local.put(varName, val); } @Override - public Object getOwnVar(final String string) { - return get(string); + public Object getLocalVar(final String string) { + if (local == null) + return null; + return local.get(string); } @Override - public boolean hasOwnVar(final String name) { - return contains(name); + public boolean hasLocalVar(final String name) { + if (local == null) + return false; + return local.containsKey(name); } @Override - public Statement createChild() { - return new ExecutionContext(this); + public void removeLocalVar(final String name) { + if (local == null) + return; + local.remove(name); } @Override - public void removeOwnVar(final String name) { - remove(name); + public String toString() { + return "execution context " + local; } } \ No newline at end of file diff --git a/msi.gama.core/src/msi/gama/runtime/ExecutionScope.java b/msi.gama.core/src/msi/gama/runtime/ExecutionScope.java index fc1d8613e5..631972df7f 100644 --- a/msi.gama.core/src/msi/gama/runtime/ExecutionScope.java +++ b/msi.gama.core/src/msi/gama/runtime/ExecutionScope.java @@ -12,7 +12,9 @@ package msi.gama.runtime; import java.util.Map; +import java.util.Set; +import gnu.trove.set.hash.TLinkedHashSet; import msi.gama.common.interfaces.IGraphics; import msi.gama.common.interfaces.IGui; import msi.gama.common.interfaces.IStepable; @@ -27,7 +29,7 @@ import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.IList; import msi.gaml.compilation.ISymbol; -import msi.gaml.descriptions.IDescription; +import msi.gaml.descriptions.ModelDescription; import msi.gaml.expressions.IExpression; import msi.gaml.operators.Strings; import msi.gaml.statements.Arguments; @@ -35,6 +37,7 @@ import msi.gaml.statements.IStatement; import msi.gaml.statements.RemoteSequence; import msi.gaml.types.IType; +import msi.gaml.types.ITypesManager; import msi.gaml.types.Types; /** @@ -47,69 +50,69 @@ @SuppressWarnings({ "unchecked", "rawtypes" }) public class ExecutionScope implements IScope { - private static final String TOPOLOGY = "%_topology_%"; - private static final String GRAPHICS = "%_graphics_%"; - private static final String EACH = "%_each_%"; + // private static final String TOPOLOGY = "%_topology_%"; + // private static final String GRAPHICS = "%_graphics_%"; + // static final String EACH = "%_each_%"; private static final String ATTRIBUTES = "%_attributes_%"; private static int SCOPE_NUMBER = 0; private final String name; - private ITopLevelAgent rootAgent; - protected IExecutionContext.Agent currentAgentContext; - protected IExecutionContext.Statement currentExecutionContext; + + protected IExecutionContext executionContext; + protected AgentExecutionContext agentContext; + protected final SpecialContext additionalContext = new SpecialContext(); private volatile boolean _action_halted, _loop_halted, _agent_halted, _trace, _interrupted, _errors_disabled; private ISymbol currentSymbol; - class AgentExecutionContext implements IExecutionContext.Agent { - - final IAgent agent; - final IExecutionContext.Agent outer; - - public AgentExecutionContext(final IAgent agent) { - this(agent, null); - } + class SpecialContext { + Object each; + IGraphics graphics; + public ITopology topology; + private ITopLevelAgent rootAgent; + private IGui gui; + private ITypesManager types; - private AgentExecutionContext(final IAgent agent, final IExecutionContext.Agent outer) { - this.agent = agent; - this.outer = outer; + void clear() { + each = null; + graphics = null; + topology = null; + rootAgent = null; + gui = null; + types = null; } - @Override - public void setVar(final String name, final Object value) { - agent.setDirectVarValue(ExecutionScope.this, name, value); - + public void copyFrom(final SpecialContext specialContext) { + each = specialContext.each; + graphics = specialContext.graphics; + topology = specialContext.topology; + rootAgent = specialContext.rootAgent; + gui = specialContext.gui; + types = specialContext.types; } - @Override - public Object getVar(final String name) { - return agent.getDirectVarValue(ExecutionScope.this, name); - } + } - @Override - public boolean hasVar(final String name) { - return agent.getSpecies().hasVar(name); - } + class AgentExecutionContext { - @Override - public IExecutionContext.Agent copy() { - return this; - } + final IAgent agent; + final AgentExecutionContext outer; - @Override - public IExecutionContext.Agent getOuter() { - return outer; + public AgentExecutionContext(final IAgent agent, final AgentExecutionContext outer) { + this.outer = outer; + this.agent = agent; } - @Override public IAgent getAgent() { return agent; } @Override - public Agent createChild(final IAgent agent) { - if (this.agent == agent) - return this; - return new AgentExecutionContext(agent, this); + public String toString() { + return "context of " + agent; + } + + public AgentExecutionContext getOuterContext() { + return outer; } } @@ -122,15 +125,35 @@ public ExecutionScope(final ITopLevelAgent root, final String otherName) { String name = "Scope #" + ++SCOPE_NUMBER; setRoot(root); - currentAgentContext = new AgentExecutionContext(root); + agentContext = new AgentExecutionContext(root, null); if (root != null) { name += " of " + root; } name += otherName == null || otherName.isEmpty() ? "" : "(" + otherName + ")"; this.name = name; - currentExecutionContext = new ExecutionContext(); + // System.out.println("Scope created " + this); + + // Necessary to create a blank execution context + push((ISymbol) null); + } + public ExecutionScope(final ITopLevelAgent root, final String otherName, final ExecutionContext context, + final AgentExecutionContext agentContext, final SpecialContext specialContext) { + this(root, otherName); + this.executionContext = context.createCopyContext(); + this.agentContext = agentContext; + this.additionalContext.copyFrom(specialContext); + } + + public AgentExecutionContext createChildContext(final IAgent agent) { + return new AgentExecutionContext(agent, agentContext); + }; + + public IExecutionContext createChildContext() { + return new ExecutionContext(executionContext); + }; + /** * Method clear() * @@ -138,8 +161,9 @@ public ExecutionScope(final ITopLevelAgent root, final String otherName) { */ @Override public void clear() { - currentAgentContext = null; - currentExecutionContext = null; + executionContext = null; + agentContext = null; + additionalContext.clear(); currentSymbol = null; } @@ -228,23 +252,26 @@ public final void interruptAgent() { // @Override @Override public synchronized boolean push(final IAgent agent) { - final IAgent a = currentAgentContext.getAgent(); - if (a != null && a.equals(agent)) { - return false; - } - // Previous context didnt have a root. + final IAgent a = agentContext.getAgent(); if (a == null) { if (agent instanceof ITopLevelAgent) { + // Previous context didnt have a root. setRoot((ITopLevelAgent) agent); } - currentAgentContext = new AgentExecutionContext(agent); - } else - currentAgentContext = currentAgentContext.createChild(agent); + // get rid of the previous context **important** + agentContext = null; + } else if (a == agent) { + return false; + } + + // System.out.println("PUSHING " + agent + " IN " + this + " (Previous + // context:" + context); + agentContext = createChildContext(agent); return true; } protected void setRoot(final ITopLevelAgent agent) { - rootAgent = agent; + additionalContext.rootAgent = agent; } /** @@ -255,10 +282,10 @@ protected void setRoot(final ITopLevelAgent agent) { // @Override @Override public void pop(final IAgent agent) { - if (currentAgentContext == null) { + if (agentContext == null) { throw GamaRuntimeException.warning("Agents stack is empty", this); } - currentAgentContext = currentAgentContext.getOuter(); + agentContext = agentContext.getOuterContext(); _agent_halted = false; } @@ -270,7 +297,7 @@ public void pop(final IAgent agent) { @Override public void push(final ISymbol statement) { setCurrentSymbol(statement); - currentExecutionContext = currentExecutionContext.createChild(); + executionContext = createChildContext(); } @Override @@ -286,7 +313,7 @@ public void setCurrentSymbol(final ISymbol statement) { */ private void writeTrace() { final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < currentExecutionContext.depth(); i++) { + for (int i = 0; i < executionContext.depth(); i++) { sb.append(Strings.TAB); } sb.append(currentSymbol.getTrace(this)); @@ -310,7 +337,7 @@ public void popAction() { */ @Override public void pop(final ISymbol symbol) { - currentExecutionContext = currentExecutionContext.getOuter(); + executionContext = executionContext.getOuterContext(); } @Override @@ -328,11 +355,10 @@ public ISymbol getCurrentSymbol() { * msi.gama.metamodel.agent.IAgent) */ @Override - public boolean execute(final IExecutable statement, final IAgent agent, final Arguments args, - final Object[] result) { + public ExecutionResult execute(final IExecutable statement, final IAgent agent, final Arguments args) { final IAgent caller = this.getAgent(); if (statement == null || agent == null || interrupted() || agent.dead()) { - return false; + return FAILED; } // We then try to push the agent on the stack final boolean pushed = push(agent); @@ -345,15 +371,11 @@ public boolean execute(final IExecutable statement, final IAgent agent, final Ar } else if (statement instanceof RemoteSequence) { ((RemoteSequence) statement).setMyself(caller); // We delegate to the remote scope - result[0] = statement.executeOn(this); - return true; } - result[0] = statement.executeOn(this); + return new ExecutionResultWithValue(statement.executeOn(this)); } catch (final GamaRuntimeException g) { - // If an exception occurs, we throw it and return false (could be - // INTERRUPTED as well) - // g.addAgent(agent.getName()); GAMA.reportAndThrowIfNeeded(this, g, true); + return FAILED; } finally { // Whatever the outcome, we pop the agent from the stack if it has // been previously pushed @@ -361,7 +383,6 @@ public boolean execute(final IExecutable statement, final IAgent agent, final Ar pop(agent); } } - return true; } @@ -398,13 +419,13 @@ public void stackArguments(final Arguments actualArgs) { * msi.gama.metamodel.agent.IAgent) */ @Override - public Object evaluate(final IExpression expr, final IAgent agent) throws GamaRuntimeException { + public ExecutionResult evaluate(final IExpression expr, final IAgent agent) throws GamaRuntimeException { if (agent == null || interrupted() || agent.dead()) { - return null; + return FAILED; } final boolean pushed = push(agent); try { - return expr.value(this); + return new ExecutionResultWithValue(expr.value(this)); } catch (final GamaRuntimeException g) { // g.addAgent(agent.toString()); GAMA.reportAndThrowIfNeeded(this, g, true); @@ -417,44 +438,42 @@ public Object evaluate(final IExpression expr, final IAgent agent) throws GamaRu } @Override - public boolean step(final IStepable agent) { - boolean result = false; + public ExecutionResult step(final IStepable agent) { final boolean isAgent = agent instanceof IAgent; if (agent == null || interrupted() || isAgent && ((IAgent) agent).dead()) { - return false; + return FAILED; } final boolean pushed = isAgent && push((IAgent) agent); try { - result = agent.step(this); + return new ExecutionResultWithValue(agent.step(this)); } catch (final Throwable ex) { final GamaRuntimeException g = GamaRuntimeException.create(ex, this); GAMA.reportAndThrowIfNeeded(this, g, true); + return FAILED; } finally { if (pushed) { pop((IAgent) agent); } } - return result; } @Override - public boolean init(final IStepable agent) { - boolean result = false; + public ExecutionResult init(final IStepable agent) { final boolean isAgent = agent instanceof IAgent; if (agent == null || interrupted() || isAgent && ((IAgent) agent).dead()) { - return false; + return FAILED; } final boolean pushed = isAgent && push((IAgent) agent); try { - result = agent.init(this); + return new ExecutionResultWithValue(agent.init(this)); } catch (final GamaRuntimeException g) { GAMA.reportAndThrowIfNeeded(this, g, true); + return FAILED; } finally { if (pushed) { pop((IAgent) agent); } } - return result; } /** @@ -464,7 +483,7 @@ public boolean init(final IStepable agent) { */ @Override public Object getVarValue(final String varName) { - return currentExecutionContext.getVar(varName); + return executionContext.getTempVar(varName); } /** @@ -475,7 +494,7 @@ public Object getVarValue(final String varName) { */ @Override public void setVarValue(final String varName, final Object val) { - currentExecutionContext.setVar(varName, val); + executionContext.setTempVar(varName, val); } /** @@ -485,7 +504,7 @@ public void setVarValue(final String varName, final Object val) { */ @Override public void saveAllVarValuesIn(final Map varsToSave) { - varsToSave.putAll(currentExecutionContext.getAllOwnVars()); + varsToSave.putAll(executionContext.getLocalVars()); } /** @@ -495,7 +514,7 @@ public void saveAllVarValuesIn(final Map varsToSave) { */ @Override public void removeAllVars() { - currentExecutionContext.clearOwnVars(); + executionContext.clearLocalVars(); } /** @@ -506,7 +525,7 @@ public void removeAllVars() { */ @Override public void addVarWithValue(final String varName, final Object val) { - currentExecutionContext.putOwnVar(varName, val); + executionContext.putLocalVar(varName, val); } /** @@ -516,7 +535,8 @@ public void addVarWithValue(final String varName, final Object val) { */ @Override public void setEach(final Object value) { - this.addVarWithValue(EACH, value); + additionalContext.each = value; + } /** @@ -526,7 +546,7 @@ public void setEach(final Object value) { */ @Override public Object getEach() { - return getVarValue(EACH); + return additionalContext.each; } /** @@ -536,7 +556,7 @@ public Object getEach() { */ @Override public Object getArg(final String string, final int type) throws GamaRuntimeException { - return Types.get(type).cast(this, currentExecutionContext.getOwnVar(string), null, false); + return Types.get(type).cast(this, executionContext.getLocalVar(string), null, false); } @Override @@ -571,17 +591,7 @@ public final String getStringArg(final String name) throws GamaRuntimeException */ @Override public boolean hasArg(final String name) { - return currentExecutionContext.hasOwnVar(name); - } - - /** - * Method hasVar() - * - * @see msi.gama.runtime.IScope#hasVar(java.lang.String) - */ - @Override - public boolean hasVar(final String name) { - return currentExecutionContext.hasVar(name); + return executionContext.hasLocalVar(name); } /** @@ -595,16 +605,14 @@ public Object getAgentVarValue(final IAgent agent, final String name) throws Gam if (agent == null || agent.dead() || interrupted()) { return null; } - Object result = null; final boolean pushed = push(agent); try { - result = currentAgentContext.getVar(name); + return agent.getDirectVarValue(ExecutionScope.this, name); } finally { if (pushed) { pop(agent); } } - return result; } /** @@ -620,7 +628,7 @@ public void setAgentVarValue(final IAgent agent, final String name, final Object } final boolean pushed = push(agent); try { - currentAgentContext.setVar(name, v); + agent.setDirectVarValue(ExecutionScope.this, name, v); } finally { if (pushed) { pop(agent); @@ -629,22 +637,22 @@ public void setAgentVarValue(final IAgent agent, final String name, final Object } @Override - public boolean update(final IAgent a) { + public ExecutionResult update(final IAgent a) { if (a == null || a.dead() || interrupted()) { - return false; + return FAILED; } final boolean pushed = push(a); try { a.getPopulation().updateVariables(this, a); - + return PASSED; } catch (final GamaRuntimeException g) { GAMA.reportAndThrowIfNeeded(this, g, true); + return FAILED; } finally { if (pushed) { pop(a); } } - return true; } /** @@ -697,7 +705,7 @@ public String toString() { */ @Override public ITopology getTopology() { - final ITopology topology = (ITopology) this.getVarValue(TOPOLOGY); + final ITopology topology = additionalContext.topology; return topology != null ? topology : getAgent().getTopology(); } @@ -709,7 +717,7 @@ public ITopology getTopology() { @Override public ITopology setTopology(final ITopology topo) { final ITopology previous = getTopology(); - addVarWithValue(TOPOLOGY, topo); + additionalContext.topology = topo; return previous; } @@ -720,7 +728,7 @@ public ITopology setTopology(final ITopology topo) { */ @Override public void setGraphics(final IGraphics val) { - addVarWithValue(GRAPHICS, val); + additionalContext.graphics = val; } /** @@ -730,7 +738,7 @@ public void setGraphics(final IGraphics val) { */ @Override public IGraphics getGraphics() { - return (IGraphics) getVarValue(GRAPHICS); + return additionalContext.graphics; } /** @@ -740,7 +748,9 @@ public IGraphics getGraphics() { */ @Override public IAgent getAgent() { - return currentAgentContext.getAgent(); + if (agentContext == null) + return null; + return agentContext.getAgent(); } /** @@ -777,32 +787,12 @@ public IModel getModel() { return getRoot().getModel(); } - /** - * Method getExperimentContext() - * - * @see msi.gama.runtime.IScope#getExperimentContext() - */ - @Override - public IDescription getExperimentContext() { - final IExperimentAgent a = getExperiment(); - if (a == null) { - return null; - } - return a.getSpecies().getDescription(); - } - - /** - * Method getModelContext() - * - * @see msi.gama.runtime.IScope#getModelContext() - */ @Override - public IDescription getModelContext() { - final IModel model = getModel(); - if (model == null) { - return null; - } - return model.getDescription(); + public IType getType(final String name) { + if (additionalContext.types == null) + additionalContext.types = ((ModelDescription) getSimulation().getSpecies().getDescription()) + .getTypesManager(); + return additionalContext.types.get(name); } /** @@ -821,14 +811,17 @@ public SimulationClock getClock() { @Override public IAgent[] getAgentsStack() { - final IAgent[] result = new IAgent[currentAgentContext.depth() + 1]; - IExecutionContext.Agent current = currentAgentContext; - int i = 0; + final Set agents = new TLinkedHashSet<>(); + AgentExecutionContext current = agentContext; + if (current == null) { + return new IAgent[0]; + } + final int i = 0; while (current != null) { - result[i++] = current.getAgent(); - current = current.getOuter(); + agents.add(current.getAgent()); + current = current.getOuterContext(); } - return result; + return agents.stream().toArray(IAgent[]::new); } /** @@ -849,7 +842,7 @@ public void pushReadAttributes(final Map values) { @Override public Map popReadAttributes() { final Map value = (Map) this.getVarValue(ATTRIBUTES); - currentExecutionContext.removeOwnVar(ATTRIBUTES); + executionContext.removeLocalVar(ATTRIBUTES); return value; } @@ -861,19 +854,21 @@ public Map peekReadAttributes() { @Override public IGui getGui() { + if (additionalContext.gui != null) + return additionalContext.gui; final IExperimentAgent experiment = getExperiment(); if (experiment == null) { - return GAMA.getGui(); - } - if (experiment.getSpecies().isHeadless()) { - return GAMA.getHeadlessGui(); - } - return GAMA.getRegularGui(); + additionalContext.gui = GAMA.getGui(); + } else if (experiment.getSpecies().isHeadless()) { + additionalContext.gui = GAMA.getHeadlessGui(); + } else + additionalContext.gui = GAMA.getRegularGui(); + return additionalContext.gui; } @Override public ITopLevelAgent getRoot() { - return rootAgent; + return additionalContext.rootAgent; } @Override @@ -888,13 +883,18 @@ public boolean isPaused() { */ @Override public RandomUtils getRandom() { - return getRoot().getRandomGenerator(); + final ITopLevelAgent root = getRoot(); + if (root == null) + return new RandomUtils(); + return root.getRandomGenerator(); } @Override public IScope copy(final String additionalName) { final ExecutionScope scope = new ExecutionScope(getRoot(), additionalName); - scope.currentExecutionContext = currentExecutionContext.copy(); + scope.executionContext = executionContext.createCopyContext(); + scope.agentContext = agentContext; + scope.additionalContext.copyFrom(additionalContext); return scope; } diff --git a/msi.gama.core/src/msi/gama/runtime/GAMA.java b/msi.gama.core/src/msi/gama/runtime/GAMA.java index 0ed6bed682..6851783eb1 100644 --- a/msi.gama.core/src/msi/gama/runtime/GAMA.java +++ b/msi.gama.core/src/msi/gama/runtime/GAMA.java @@ -14,8 +14,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; import msi.gama.common.GamaPreferences; import msi.gama.common.interfaces.IGui; @@ -39,30 +37,9 @@ */ public class GAMA { - public static ForkJoinPool THREAD_POOL = new ForkJoinPool(GamaPreferences.NUMBERS_OF_GRID_THREADS.getValue()); - - public static void setConcurrencyLevel(final int nb) { - THREAD_POOL.shutdown(); - THREAD_POOL = new ForkJoinPool(nb); - } - - public static void executeThreaded(final Runnable r) { - THREAD_POOL.invoke(ForkJoinTask.adapt(r)); - } - - public static T executeThreaded(final ForkJoinTask task) { - if (task == null) - return null; - return THREAD_POOL.invoke(task); - } - public final static String VERSION = "GAMA 1.7"; - // public static final String _FATAL = "fatal"; public static final String _WARNINGS = "warnings"; - // private final static ExperimentController controller = new - // ExperimentController(new ExperimentScheduler()); - // hqnghi: add several controllers to have multi-thread experiments private final static List controllers = new ArrayList<>(); diff --git a/msi.gama.core/src/msi/gama/runtime/IExecutionContext.java b/msi.gama.core/src/msi/gama/runtime/IExecutionContext.java index c5fcb9cf9f..8fec065d33 100644 --- a/msi.gama.core/src/msi/gama/runtime/IExecutionContext.java +++ b/msi.gama.core/src/msi/gama/runtime/IExecutionContext.java @@ -2,59 +2,46 @@ import java.util.Map; -import msi.gama.metamodel.agent.IAgent; - public interface IExecutionContext { - public interface Agent extends IExecutionContext { - public abstract IAgent getAgent(); - - @Override - public abstract IExecutionContext.Agent copy(); - - @Override - public abstract IExecutionContext.Agent getOuter(); - - public abstract IExecutionContext.Agent createChild(IAgent agent); + public default int depth() { + if (getOuterContext() == null) + return 0; + return 1 + getOuterContext().depth(); } - public interface Statement extends IExecutionContext { - public abstract Map getAllOwnVars(); - - public abstract void clearOwnVars(); + /** + * Temporary variables, defined in execution contexts. Can be accessed in a + * recursive way + */ - public abstract void putOwnVar(String varName, Object val); + public abstract void setTempVar(String name, Object value); - public abstract Object getOwnVar(String string); + public abstract Object getTempVar(String name); - public abstract boolean hasOwnVar(String name); + /** + * Local variables, for example arguments, defined in execution contexts. + * Are only managed locally + */ - @Override - public abstract IExecutionContext.Statement getOuter(); + public abstract Map getLocalVars(); - @Override - public abstract IExecutionContext.Statement copy(); + public abstract void clearLocalVars(); - public abstract IExecutionContext.Statement createChild(); + public abstract void putLocalVar(String varName, Object val); - public abstract void removeOwnVar(String name); - - } - - public default int depth() { - if (getOuter() == null) - return 0; - return 1 + getOuter().depth(); - } + public abstract Object getLocalVar(String string); - public abstract void setVar(String name, Object value); + public abstract boolean hasLocalVar(String name); - public abstract Object getVar(String name); + public abstract void removeLocalVar(String name); - public abstract boolean hasVar(String name); + /** + * Other methods + */ - public abstract IExecutionContext copy(); + public abstract IExecutionContext getOuterContext(); - public abstract IExecutionContext getOuter(); + public abstract IExecutionContext createCopyContext(); } \ No newline at end of file diff --git a/msi.gama.core/src/msi/gama/runtime/IScope.java b/msi.gama.core/src/msi/gama/runtime/IScope.java index c901f8fef5..2b8248dead 100644 --- a/msi.gama.core/src/msi/gama/runtime/IScope.java +++ b/msi.gama.core/src/msi/gama/runtime/IScope.java @@ -27,10 +27,10 @@ import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.IList; import msi.gaml.compilation.ISymbol; -import msi.gaml.descriptions.IDescription; import msi.gaml.expressions.IExpression; import msi.gaml.statements.Arguments; import msi.gaml.statements.IExecutable; +import msi.gaml.types.IType; /** * Written by drogoul Modified on 18 janv. 2011 @@ -41,6 +41,96 @@ @SuppressWarnings({ "rawtypes" }) public interface IScope { + /** + * Use this class to accumulate a series of execution results. Only the last + * one marked as 'passed' will be returned + * + * @author drogoul + * + */ + public static class MutableResult extends ExecutionResultWithValue { + public MutableResult() { + super(true, null); + } + + public boolean accept(final ExecutionResult e) { + passed = passed && e.passed(); + if (passed) + this.value = e.getValue(); + return passed; + } + + @Override + public Object getValue() { + return value; + } + + } + + /** + * The result of executions. 'passed' represents the success or failure of + * the computation, value its result + * + * @author drogoul + * + */ + + public abstract static class ExecutionResult { + public abstract boolean passed(); + + public Object getValue() { + return passed(); + } + + } + + public static class FailedExecutionResult extends ExecutionResult { + + @Override + public boolean passed() { + return false; + } + + } + + public static class SuccessfulExecutionResult extends ExecutionResult { + + @Override + public boolean passed() { + return true; + } + + } + + public static class ExecutionResultWithValue extends ExecutionResult { + + protected Object value; + protected boolean passed; + + public ExecutionResultWithValue(final Object value) { + this(true, value); + } + + public ExecutionResultWithValue(final boolean passed, final Object value) { + this.passed = passed; + this.value = value; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public boolean passed() { + return passed; + } + + } + + public final static ExecutionResult PASSED = new SuccessfulExecutionResult(); + public final static ExecutionResult FAILED = new FailedExecutionResult(); + /** * Management of the scope state. * @@ -178,10 +268,9 @@ public interface IScope { * */ - public abstract boolean execute(final IExecutable executable, final IAgent agent, final Arguments args, - Object[] result); + public abstract ExecutionResult execute(final IExecutable executable, final IAgent agent, final Arguments args); - public abstract Object evaluate(IExpression expr, IAgent agent) throws GamaRuntimeException; + public abstract ExecutionResult evaluate(IExpression expr, IAgent agent) throws GamaRuntimeException; /** * Access to variables (agent and context) @@ -226,18 +315,7 @@ public abstract boolean execute(final IExecutable executable, final IAgent agent public abstract boolean hasArg(String string); - public abstract boolean hasVar(String string); - - /** - * Returns the current simulation in which this scope is defined. - * - * @return the current simulation or null if none is defined (unlikely as - * the scope is created by a simulation) - */ - - public abstract IDescription getExperimentContext(); - - public abstract IDescription getModelContext(); + public IType getType(final String name); public abstract IModel getModel(); @@ -268,9 +346,9 @@ public abstract boolean execute(final IExecutable executable, final IAgent agent */ public abstract void interruptLoop(); - public abstract boolean init(final IStepable agent); + public abstract ExecutionResult init(final IStepable agent); - public abstract boolean step(final IStepable agent); + public abstract ExecutionResult step(final IStepable agent); /** * @param actualArgs @@ -280,7 +358,7 @@ public abstract boolean execute(final IExecutable executable, final IAgent agent /** * @param gamlAgent */ - public abstract boolean update(IAgent agent); + public abstract ExecutionResult update(IAgent agent); /** * @return the current statement or null if none diff --git a/msi.gama.core/src/msi/gama/runtime/ParallelAgentRunner.java b/msi.gama.core/src/msi/gama/runtime/ParallelAgentRunner.java deleted file mode 100644 index b94eeae222..0000000000 --- a/msi.gama.core/src/msi/gama/runtime/ParallelAgentRunner.java +++ /dev/null @@ -1,148 +0,0 @@ -package msi.gama.runtime; - -import java.util.List; -import java.util.concurrent.RecursiveTask; - -import msi.gama.common.GamaPreferences; -import msi.gama.metamodel.agent.IAgent; -import msi.gama.metamodel.population.IPopulation; -import msi.gama.metamodel.shape.IShape; -import msi.gama.runtime.exceptions.GamaRuntimeException; -import msi.gaml.statements.IExecutable; - -public abstract class ParallelAgentRunner extends RecursiveTask implements IExecutable { - - public static class ParallelAgentStepper extends ParallelAgentRunner { - - public ParallelAgentStepper(final IScope scope, final A[] agents, final int begin, - final int end) { - super(scope, agents, begin, end, GamaPreferences.SEQUENTIAL_THRESHOLD.getValue()); - } - - @Override - public Boolean executeOn(final IScope scope) throws GamaRuntimeException { - // Triggers the creation of a new scope if necessary in this thread - for (int i = begin; i < end; ++i) { - if (!scope.step((IAgent) agents[i])) - return false; - } - return true; - } - - @Override - ParallelAgentStepper subTask(final int begin, final int end) { - return new ParallelAgentStepper(originalScope, agents, begin, end); - } - - } - - public static class ParallelAgentExecuter extends ParallelAgentRunner { - - final IExecutable executable; - - public ParallelAgentExecuter(final IScope scope, final IExecutable executable, - final A[] agents, final int begin, final int end, final int threshold) { - super(scope, agents, begin, end, threshold); - this.executable = executable; - } - - @Override - public Object executeOn(final IScope scope) throws GamaRuntimeException { - // Triggers the creation of a new scope if necessary in this thread - final Object[] result = new Object[1]; - for (int i = begin; i < end; ++i) { - if (!scope.execute(executable, (IAgent) agents[i], null, result)) - return null; - } - return result[0]; - } - - @Override - ParallelAgentExecuter subTask(final int begin, final int end) { - return new ParallelAgentExecuter(originalScope, executable, agents, begin, end, sequentialThreshold); - } - - } - - final IShape[] agents; - final int begin, end; - final IScope originalScope; - final int sequentialThreshold; - - public static ParallelAgentRunner step(final IScope scope, final A[] array) { - if (array == null) - return null; - return new ParallelAgentStepper(scope, array, 0, array.length); - } - - public static ParallelAgentExecuter execute(final IScope scope, final IExecutable executable, - final A[] array, final int threshold) { - if (array == null || executable == null) - return null; - return new ParallelAgentExecuter(scope, executable, array, 0, array.length, threshold); - } - - public static ParallelAgentExecuter execute(final IExecutable executable, final IPopulation pop, - final int threshold) { - if (pop == null || pop.isEmpty()) - return null; - return new ParallelAgentExecuter(pop.getHost().getScope(), executable, pop.toArray(), 0, pop.size(), threshold); - } - - public static ParallelAgentExecuter execute(final IScope scope, final IExecutable executable, - final List list, final int threshold) { - if (list == null || list.isEmpty()) - return null; - return new ParallelAgentExecuter(scope, executable, list.toArray(new IAgent[list.size()]), 0, list.size(), - threshold); - } - - public static ParallelAgentRunner step(final IPopulation pop) { - if (pop == null || pop.isEmpty()) - return null; - return new ParallelAgentStepper(pop.getHost().getScope(), pop.toArray(), 0, pop.size()); - } - - public static ParallelAgentRunner step(final IScope scope, final List list) { - if (list == null || list.isEmpty()) - return null; - return new ParallelAgentStepper(scope, list.toArray(new IAgent[list.size()]), 0, list.size()); - } - - public ParallelAgentRunner(final IScope scope, final A[] agents, final int begin, final int end, - final int threshold) { - this.agents = agents; - this.begin = begin; - this.end = end; - this.originalScope = scope.copy(" - forked - "); - this.sequentialThreshold = threshold; - } - - abstract ParallelAgentRunner subTask(final int begin, final int end); - - @Override - protected T compute() throws GamaRuntimeException { - // We execute the agents if the size of the array is below the given - // threshold - if (end - begin <= sequentialThreshold) { - return executeOn(originalScope); - // Otherwise, we divide the array in two, compute the left part and - // fork the right part - } else { - final int mid = begin + (end - begin) / 2; - final ParallelAgentRunner left = subTask(begin, mid); - final ParallelAgentRunner right = subTask(mid, end); - left.fork(); - final T firstPart = right.compute(); - if (firstPart instanceof Boolean && ((Boolean) firstPart).equals(false)) - return null; - return left.join(); - } - } - - // Called for each subtask or can be called directly if no parallelism is - // allowed - @Override - public abstract T executeOn(IScope scope) throws GamaRuntimeException; - -} diff --git a/msi.gama.core/src/msi/gama/runtime/TemporaryScope.java b/msi.gama.core/src/msi/gama/runtime/TemporaryScope.java index 292ee9cd6b..add762aeb2 100644 --- a/msi.gama.core/src/msi/gama/runtime/TemporaryScope.java +++ b/msi.gama.core/src/msi/gama/runtime/TemporaryScope.java @@ -22,7 +22,6 @@ import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.IList; import msi.gaml.compilation.ISymbol; -import msi.gaml.descriptions.IDescription; import msi.gaml.expressions.IExpression; import msi.gaml.statements.Arguments; import msi.gaml.statements.IExecutable; @@ -107,9 +106,8 @@ public void pop(final ISymbol statement) { * java.lang.Object[]) Impossible to execute anything here */ @Override - public boolean execute(final IExecutable executable, final IAgent agent, final Arguments args, - final Object[] result) { - return false; + public ExecutionResult execute(final IExecutable executable, final IAgent agent, final Arguments args) { + return FAILED; } /** @@ -119,12 +117,12 @@ public boolean execute(final IExecutable executable, final IAgent agent, final A * msi.gama.metamodel.agent.IAgent) */ @Override - public Object evaluate(final IExpression expr, final IAgent agent) throws GamaRuntimeException { + public ExecutionResult evaluate(final IExpression expr, final IAgent agent) throws GamaRuntimeException { try { - return expr.value(this); + return new ExecutionResultWithValue(expr.value(this)); } catch (final GamaRuntimeException g) { GAMA.reportAndThrowIfNeeded(this, g, true); - return null; + return FAILED; } } @@ -271,16 +269,6 @@ public boolean hasArg(final String string) { return vars.containsKey(string); } - /** - * Method hasVar() - * - * @see msi.gama.runtime.IScope#hasVar(java.lang.String) - */ - @Override - public boolean hasVar(final String string) { - return vars.containsKey(string); - } - /** * Method getAgentVarValue() * @@ -423,24 +411,9 @@ public IExperimentAgent getExperiment() { return null; } - /** - * Method getExperimentContext() - * - * @see msi.gama.runtime.IScope#getExperimentContext() No Experiment - */ - @Override - public IDescription getExperimentContext() { - return null; - } - - /** - * Method getModelContext() - * - * @see msi.gama.runtime.IScope#getModelContext() No Model - */ @Override - public IDescription getModelContext() { - return null; + public IType getType(final String name) { + return Types.get(name); } /** @@ -525,8 +498,8 @@ public void interruptLoop() { * Nothing to do here */ @Override - public boolean init(final IStepable agent) { - return false; + public ExecutionResult init(final IStepable agent) { + return FAILED; } /** @@ -536,8 +509,8 @@ public boolean init(final IStepable agent) { * Nothing to do here */ @Override - public boolean step(final IStepable agent) { - return false; + public ExecutionResult step(final IStepable agent) { + return FAILED; } /** @@ -550,14 +523,11 @@ public void stackArguments(final Arguments actualArgs) { } /** - * Method update() - * - * @see msi.gama.runtime.IScope#update(msi.gama.metamodel.agent.IAgent) - * Nothing to do here + * Method update() Nothing to do here */ @Override - public boolean update(final IAgent agent) { - return false; + public ExecutionResult update(final IAgent agent) { + return FAILED; } /** diff --git a/msi.gama.core/src/msi/gama/runtime/concurrent/AgentSpliterator.java b/msi.gama.core/src/msi/gama/runtime/concurrent/AgentSpliterator.java new file mode 100644 index 0000000000..fba70d0142 --- /dev/null +++ b/msi.gama.core/src/msi/gama/runtime/concurrent/AgentSpliterator.java @@ -0,0 +1,68 @@ +package msi.gama.runtime.concurrent; + +import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; + +import msi.gama.metamodel.agent.IAgent; +import msi.gama.metamodel.shape.IShape; + +public class AgentSpliterator implements Spliterator { + + public static Spliterator of(final IShape[] agents, final int threshold) { + if (agents == null || agents.length == 0) + return Spliterators. emptySpliterator(); + return new AgentSpliterator(agents, 0, agents.length, threshold); + } + + public static Spliterator of(final List agents, final int threshold) { + return new AgentSpliterator(agents.toArray(new IAgent[0]), 0, agents.size(), threshold); + } + + int begin; + final int end, threshold; + final IShape[] agents; + + private AgentSpliterator(final IShape[] array, final int begin, final int end, final int threshold) { + this.begin = begin; + this.end = end; + this.threshold = threshold; + agents = array; + } + + @Override + public void forEachRemaining(final Consumer action) { + for (int i = begin; i < end; ++i) { + action.accept((IAgent) agents[i]); + } + } + + @Override + public boolean tryAdvance(final Consumer action) { + return true; + } + + @Override + public AgentSpliterator trySplit() { + final int size = end - begin; + if (size <= threshold) { + return null; + } + final int mid = begin + size / 2; + final AgentSpliterator split = new AgentSpliterator(agents, begin, mid, threshold); + begin = mid; + return split; + } + + @Override + public long estimateSize() { + return end - begin; + } + + @Override + public int characteristics() { + return Spliterator.CONCURRENT | Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.SIZED; + } + +} diff --git a/msi.gama.core/src/msi/gama/runtime/concurrent/GamaExecutorService.java b/msi.gama.core/src/msi/gama/runtime/concurrent/GamaExecutorService.java new file mode 100644 index 0000000000..ef15c6dea8 --- /dev/null +++ b/msi.gama.core/src/msi/gama/runtime/concurrent/GamaExecutorService.java @@ -0,0 +1,211 @@ +package msi.gama.runtime.concurrent; + +import static msi.gama.common.GamaPreferences.CONCURRENCY; +import static msi.gama.common.GamaPreferences.EXPERIMENTAL; +import static msi.gama.common.GamaPreferences.create; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; + +import com.google.common.util.concurrent.MoreExecutors; + +import msi.gama.common.GamaPreferences.Entry; +import msi.gama.common.GamaPreferences.IPreferenceChangeListener; +import msi.gama.metamodel.agent.IAgent; +import msi.gama.metamodel.shape.IShape; +import msi.gama.runtime.IScope; +import msi.gama.runtime.exceptions.GamaRuntimeException; +import msi.gaml.expressions.IExpression; +import msi.gaml.operators.Cast; +import msi.gaml.species.ISpecies; +import msi.gaml.statements.IExecutable; +import msi.gaml.types.IType;; + +public abstract class GamaExecutorService { + + public static ForkJoinPool AGENT_PARALLEL_EXECUTOR; + public static ExecutorService SIMULATION_PARALLEL_EXECUTOR; + public static final ExecutorService SAME_THREAD_EXECUTOR = MoreExecutors.sameThreadExecutor(); + + public static final Entry CONCURRENCY_SIMULATIONS = create("core.multithreaded_simulations", + "Allow experiments to run multiple simulations in parallel", true, IType.BOOL).in(EXPERIMENTAL) + .group(CONCURRENCY); + public static final Entry CONCURRENCY_GRID = create("core.grid_optimization", + "Make grids schedule their agents in parallel by default", false, IType.BOOL).in(EXPERIMENTAL) + .group(CONCURRENCY); + public static final Entry CONCURRENCY_SPECIES = create("core.species_optimization", + "Make regular species schedule their agents in parallel by default", false, IType.BOOL).in(EXPERIMENTAL) + .group(CONCURRENCY); + public static final Entry CONCURRENCY_THRESHOLD = create("core.sequential_threshold", + "Number under which agents will always be executed sequentially", 20, IType.INT).between(1, null) + .in(EXPERIMENTAL).group(CONCURRENCY); + public static final Entry CONCURRENCY_THREADS_NUMBER = create("core.threads_number", + "Max. number of threads to use for parallel operations (available processors: " + + Runtime.getRuntime().availableProcessors() + ")", + 4, IType.INT).between(1, null).in(EXPERIMENTAL).group(CONCURRENCY) + .addChangeListener(new IPreferenceChangeListener() { + + @Override + public boolean beforeValueChange(final Integer newValue) { + return true; + } + + @Override + public void afterValueChange(final Integer newValue) { + setConcurrencyLevel(newValue); + System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", + String.valueOf(newValue)); + } + }); + + public static void startUp() { + // Called by the activator to init the preferences and executor services + setConcurrencyLevel(CONCURRENCY_THREADS_NUMBER.getValue()); + } + + public static void setConcurrencyLevel(final int nb) { + if (AGENT_PARALLEL_EXECUTOR != null) + AGENT_PARALLEL_EXECUTOR.shutdown(); + AGENT_PARALLEL_EXECUTOR = new ForkJoinPool(nb); + if (SIMULATION_PARALLEL_EXECUTOR != null) + SIMULATION_PARALLEL_EXECUTOR.shutdown(); + SIMULATION_PARALLEL_EXECUTOR = Executors.newFixedThreadPool(nb); + } + + public static enum Caller { + SPECIES, GRID, NONE, SIMULATION + } + + /** + * Returns the level of parallelism from the expression passed and the + * preferences + * + * @param concurrency + * The facet passed to the statement or species + * @param forSpecies + * whether it is for species or not + * @return 0 for no parallelism, 1 for complete parallelism (i.e. each agent + * on its own), n for parallelism with a threshold of n + */ + public static int getParallelism(final IScope scope, final IExpression concurrency, final Caller caller) { + if (concurrency == null) { + switch (caller) { + case SIMULATION: + if (CONCURRENCY_SIMULATIONS.getValue()) + return CONCURRENCY_THREADS_NUMBER.getValue(); + else + return 0; + case SPECIES: + if (CONCURRENCY_SPECIES.getValue()) { + return CONCURRENCY_THRESHOLD.getValue(); + } else { + return 0; + } + case GRID: + if (CONCURRENCY_GRID.getValue()) { + return CONCURRENCY_THRESHOLD.getValue(); + } else { + return 0; + } + default: + return 0; + } + } else { + final Object o = concurrency.value(scope); + if (o instanceof Boolean) { + if (o.equals(Boolean.FALSE)) + return 0; + if (o.equals(Boolean.TRUE)) { + if (caller == Caller.SIMULATION) + return CONCURRENCY_THREADS_NUMBER.getValue(); + return CONCURRENCY_THRESHOLD.getValue(); + } + } else if (o instanceof Integer) { + final Integer i = Math.abs((Integer) o); + return i; + } else { + return getParallelism(scope, null, caller); + } + } + return 0; + } + + public static void executeThreaded(final Runnable r) { + AGENT_PARALLEL_EXECUTOR.invoke(ForkJoinTask.adapt(r)); + } + + public static Boolean step(final IScope scope, final List pop, final ISpecies species) + throws GamaRuntimeException { + final IExpression schedule = species.getSchedule(); + final List agents = schedule == null ? pop : Cast.asList(scope, schedule.value(scope)); + final int threshold = getParallelism(scope, species.getConcurrency(), + species.isGrid() ? Caller.GRID : Caller.SPECIES); + return doStep(scope, agents.toArray(new IAgent[0]), threshold); + } + + public static Boolean step(final IScope scope, final A[] array, final ISpecies species) + throws GamaRuntimeException { + final IExpression schedule = species.getSchedule(); + final IShape[] scheduledAgents; + if (schedule == null) { + scheduledAgents = array; + } else { + final List agents = Cast.asList(scope, schedule.value(scope)); + scheduledAgents = agents.toArray(new IShape[0]); + } + final int threshold = getParallelism(scope, species.getConcurrency(), + species.isGrid() ? Caller.GRID : Caller.SPECIES); + return doStep(scope, scheduledAgents, threshold); + } + + private static Boolean doStep(final IScope scope, final A[] array, final int threshold) { + int concurrency = threshold; + if (array.length <= threshold) + concurrency = 0; + switch (concurrency) { + case 0: + for (final A agent : array) { + if (!scope.step((IAgent) agent).passed()) + return false; + } + return true; + case 1: + for (final A agent : array) { + executeThreaded(() -> scope.step((IAgent) agent)); + } + return true; + default: + return ParallelAgentRunner.step(scope, array, threshold); + } + } + + public static void execute(final IScope scope, final IExecutable executable, final A[] array, + final IExpression parallel) throws GamaRuntimeException { + int threshold = getParallelism(scope, parallel, Caller.NONE); + if (array.length <= threshold) + threshold = 0; + switch (threshold) { + case 0: + for (final A agent : array) { + scope.execute(executable, (IAgent) agent, null); + } + return; + case 1: + for (final A agent : array) { + executeThreaded(() -> scope.execute(executable, (IAgent) agent, null)); + } + return; + default: + ParallelAgentRunner.execute(scope, executable, array, threshold); + } + } + + public static void execute(final IScope scope, final IExecutable executable, final List list, + final IExpression parallel) throws GamaRuntimeException { + execute(scope, executable, list.toArray(new IAgent[0]), parallel); + } + +} diff --git a/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentExecuter.java b/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentExecuter.java new file mode 100644 index 0000000000..c360e4b1eb --- /dev/null +++ b/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentExecuter.java @@ -0,0 +1,35 @@ +package msi.gama.runtime.concurrent; + +import java.util.Spliterator; + +import msi.gama.metamodel.agent.IAgent; +import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.MutableResult; +import msi.gama.runtime.exceptions.GamaRuntimeException; +import msi.gaml.statements.IExecutable; + +public class ParallelAgentExecuter extends ParallelAgentRunner { + + final IExecutable executable; + + public ParallelAgentExecuter(final IScope scope, final IExecutable executable, final Spliterator agents) { + super(scope, agents); + this.executable = executable; + } + + @Override + public Object executeOn(final IScope scope) throws GamaRuntimeException { + final MutableResult result = new MutableResult(); + agents.forEachRemaining(each -> { + if (result.passed()) + result.accept(scope.execute(executable, each, null)); + }); + return result.passed() ? result.getValue() : null; + } + + @Override + ParallelAgentExecuter subTask(final Spliterator sub) { + return new ParallelAgentExecuter(originalScope, executable, sub); + } + +} \ No newline at end of file diff --git a/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentRunner.java b/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentRunner.java new file mode 100644 index 0000000000..cbc0c8acbd --- /dev/null +++ b/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentRunner.java @@ -0,0 +1,98 @@ +package msi.gama.runtime.concurrent; + +import java.util.List; +import java.util.Spliterator; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveTask; + +import msi.gama.metamodel.agent.IAgent; +import msi.gama.metamodel.shape.IShape; +import msi.gama.runtime.IScope; +import msi.gama.runtime.exceptions.GamaRuntimeException; +import msi.gaml.statements.IExecutable; + +public abstract class ParallelAgentRunner extends RecursiveTask implements IExecutable { + + final Spliterator agents; + final IScope originalScope; + + public static T execute(final ForkJoinTask task) throws GamaRuntimeException { + if (task == null) + return null; + return GamaExecutorService.AGENT_PARALLEL_EXECUTOR.invoke(task); + } + + public static Boolean step(final IScope scope, final A[] array, final int threshold) + throws GamaRuntimeException { + final ParallelAgentRunner runner = from(scope, array, threshold); + if (array.length <= threshold) + return runner.executeOn(scope); + return execute(runner); + } + + public static void execute(final IScope scope, final IExecutable executable, final A[] array, + final int threshold) throws GamaRuntimeException { + final ParallelAgentRunner runner = from(scope, executable, array, threshold); + if (array.length <= threshold) + runner.executeOn(scope); + else + execute(runner); + } + + public static void execute(final IScope scope, final IExecutable executable, final List list, + final int threshold) throws GamaRuntimeException { + final ParallelAgentRunner runner = from(scope, executable, list, threshold); + if (list.size() <= threshold) + runner.executeOn(scope); + else + execute(runner); + } + + private static ParallelAgentRunner from(final IScope scope, final A[] array, + final int threshold) { + return new ParallelAgentStepper(scope, AgentSpliterator.of(array, threshold)); + } + + private static ParallelAgentRunner from(final IScope scope, final List list, + final int threshold) { + return new ParallelAgentStepper(scope, AgentSpliterator.of(list, threshold)); + } + + private static ParallelAgentExecuter from(final IScope scope, final IExecutable executable, + final A[] array, final int threshold) { + return new ParallelAgentExecuter(scope, executable, AgentSpliterator.of(array, threshold)); + } + + private static ParallelAgentExecuter from(final IScope scope, final IExecutable executable, + final List list, final int threshold) { + return new ParallelAgentExecuter(scope, executable, AgentSpliterator.of(list, threshold)); + } + + protected ParallelAgentRunner(final IScope scope, final Spliterator agents) { + this.agents = agents; + this.originalScope = scope.copy(" - forked - "); + } + + abstract ParallelAgentRunner subTask(Spliterator sub); + + @Override + protected T compute() throws GamaRuntimeException { + final Spliterator sub = agents.trySplit(); + T result; + if (sub == null) { + result = executeOn(originalScope); + } else { + final ParallelAgentRunner left = subTask(sub); + left.fork(); + result = compute(); + left.join(); + } + return result; + } + + // Called for each subtask or can be called directly if no parallelism is + // allowed + @Override + public abstract T executeOn(IScope scope) throws GamaRuntimeException; + +} diff --git a/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentStepper.java b/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentStepper.java new file mode 100644 index 0000000000..ff3d36fd50 --- /dev/null +++ b/msi.gama.core/src/msi/gama/runtime/concurrent/ParallelAgentStepper.java @@ -0,0 +1,31 @@ +package msi.gama.runtime.concurrent; + +import java.util.Spliterator; + +import msi.gama.metamodel.agent.IAgent; +import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.MutableResult; +import msi.gama.runtime.exceptions.GamaRuntimeException; + +public class ParallelAgentStepper extends ParallelAgentRunner { + + public ParallelAgentStepper(final IScope scope, final Spliterator agents) { + super(scope, agents); + } + + @Override + public Boolean executeOn(final IScope scope) throws GamaRuntimeException { + final MutableResult result = new MutableResult(); + agents.forEachRemaining(each -> { + if (result.passed()) + result.accept(scope.step(each)); + }); + return result.passed(); + } + + @Override + ParallelAgentRunner subTask(final Spliterator sub) { + return new ParallelAgentStepper(originalScope, sub); + } + +} \ No newline at end of file diff --git a/msi.gama.core/src/msi/gama/runtime/concurrent/SimulationRunner.java b/msi.gama.core/src/msi/gama/runtime/concurrent/SimulationRunner.java new file mode 100644 index 0000000000..5118e55f44 --- /dev/null +++ b/msi.gama.core/src/msi/gama/runtime/concurrent/SimulationRunner.java @@ -0,0 +1,84 @@ +package msi.gama.runtime.concurrent; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.function.Function; + +import msi.gama.kernel.experiment.IExperimentPlan; +import msi.gama.kernel.simulation.SimulationAgent; +import msi.gama.kernel.simulation.SimulationPopulation; +import msi.gama.runtime.concurrent.GamaExecutorService.Caller; + +public class SimulationRunner { + + final SimulationPopulation population; + final Map> runnables; + static final Function STEP = each -> each.step(each.getScope()); + final int concurrency; + + private int activeThreads; + + public SimulationRunner(final SimulationPopulation pop) { + population = pop; + runnables = new LinkedHashMap<>(); + final IExperimentPlan plan = population.getHost().getSpecies(); + if (plan.isHeadless()) + concurrency = 1; + else + concurrency = GamaExecutorService.getParallelism(population.getHost().getScope(), plan.getConcurrency(), + Caller.SIMULATION); + + } + + public void remove(final SimulationAgent agent) { + runnables.remove(agent); + } + + public void add(final SimulationAgent agent) { + runnables.put(agent, () -> { + activeThreads = computeNumberOfThreads(); + return STEP.apply(agent); + }); + } + + public void step() { + try { + getExecutor().invokeAll(runnables.values()); + } catch (final InterruptedException e) { + } + + } + + private int computeNumberOfThreads() { + final ExecutorService executor = getExecutor(); + if (executor instanceof ForkJoinPool) + // getActiveThreadCount() always overestimates the number of threads + return Math.min(concurrency, ((ForkJoinPool) executor).getActiveThreadCount()); + if (executor instanceof ThreadPoolExecutor) { + return Math.min(concurrency, ((ThreadPoolExecutor) executor).getActiveCount()); + } + return 1; + } + + protected ExecutorService getExecutor() { + return concurrency == 0 ? GamaExecutorService.SAME_THREAD_EXECUTOR + : GamaExecutorService.SIMULATION_PARALLEL_EXECUTOR; + } + + public void dispose() { + runnables.clear(); + } + + public int getActiveThreads() { + return activeThreads; + } + + public boolean hasSimulations() { + return runnables.size() > 0; + } + +} diff --git a/msi.gama.core/src/msi/gama/util/GAML.java b/msi.gama.core/src/msi/gama/util/GAML.java index 97be24fb5d..18ff51e291 100644 --- a/msi.gama.core/src/msi/gama/util/GAML.java +++ b/msi.gama.core/src/msi/gama/util/GAML.java @@ -13,6 +13,7 @@ import org.eclipse.emf.common.util.URI; +import msi.gama.kernel.experiment.ITopLevelAgent; import msi.gama.metamodel.agent.IAgent; import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; @@ -92,7 +93,7 @@ public static Object evaluateExpression(final String expression, final IAgent a) return null; } final IScope scope = a.getScope().copy("in temporary expression evaluator"); - final Object o = scope.evaluate(expr, a); + final Object o = scope.evaluate(expr, a).getValue(); GAMA.releaseScope(scope); return o; } @@ -132,7 +133,10 @@ public static ExperimentDescription getExperimentContext(final IAgent a) { return null; } final IScope scope = a.getScope(); - return (ExperimentDescription) scope.getExperimentContext(); + final ITopLevelAgent agent = scope.getExperiment(); + if (agent == null) + return null; + return (ExperimentDescription) agent.getSpecies().getDescription(); } public static void registerInfoProvider(final IGamlResourceInfoProvider info) { diff --git a/msi.gama.core/src/msi/gama/util/GamaListFactory.java b/msi.gama.core/src/msi/gama/util/GamaListFactory.java index f488b75e9e..99231c53b0 100644 --- a/msi.gama.core/src/msi/gama/util/GamaListFactory.java +++ b/msi.gama.core/src/msi/gama/util/GamaListFactory.java @@ -14,8 +14,8 @@ import com.google.common.collect.Iterables; -import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; +import msi.gama.runtime.concurrent.GamaExecutorService; import msi.gaml.expressions.IExpression; import msi.gaml.types.GamaType; import msi.gaml.types.IType; @@ -199,7 +199,7 @@ public static IList create(final IScope scope, final IExpression fillExpr, final final Object o = fillExpr.value(scope); Arrays.fill(contents, o); } else { - GAMA.executeThreaded(() -> IntStream.range(0, contents.length).parallel().forEach(i -> { + GamaExecutorService.executeThreaded(() -> IntStream.range(0, contents.length).parallel().forEach(i -> { contents[i] = fillExpr.value(scope); })); } diff --git a/msi.gama.core/src/msi/gama/util/graph/AbstractGraphEdgeAgent.java b/msi.gama.core/src/msi/gama/util/graph/AbstractGraphEdgeAgent.java index e9c1014649..957ecbc8b5 100644 --- a/msi.gama.core/src/msi/gama/util/graph/AbstractGraphEdgeAgent.java +++ b/msi.gama.core/src/msi/gama/util/graph/AbstractGraphEdgeAgent.java @@ -33,19 +33,6 @@ public AbstractGraphEdgeAgent(final IPopulation s) throws Gama super(s); } - // - // @Override - // public void step(final IScope scope) { - // if ( scope.interrupted() || dead() ) { return; } - // IAgent s = (IAgent) getAttribute(IKeyword.SOURCE); - // IAgent t = (IAgent) getAttribute(IKeyword.TARGET); - // if ( s == null || t == null ) { return; } - // setGeometry(GamaGeometryType.buildLine(s.getLocation(), - // t.getLocation())); - // - // super.step(scope); - // } - @Override public Object _step_(final IScope scope) { // if ( scope.interrupted() || dead() ) { return null; } diff --git a/msi.gama.core/src/msi/gama/util/graph/AbstractGraphNodeAgent.java b/msi.gama.core/src/msi/gama/util/graph/AbstractGraphNodeAgent.java index fc791293fe..017e923abe 100644 --- a/msi.gama.core/src/msi/gama/util/graph/AbstractGraphNodeAgent.java +++ b/msi.gama.core/src/msi/gama/util/graph/AbstractGraphNodeAgent.java @@ -24,6 +24,7 @@ import msi.gama.precompiler.GamlAnnotations.vars; import msi.gama.precompiler.IConcept; import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.ExecutionResult; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gaml.descriptions.ConstantExpressionDescription; import msi.gaml.operators.Cast; @@ -45,9 +46,8 @@ public static class NodeRelation implements VertexRelationship, IList>>(); + shortestPathComputed = new ConcurrentHashMap, IList>>(); type = Types.GRAPH.of(nodeType, vertexType); } @@ -127,7 +128,7 @@ public GamaGraph(final IScope scope, final IContainer edgesOrVertices, final boo final VertexRelationship rel, final ISpecies edgesSpecies, final IType nodeType, final IType edgeType) { vertexMap = new TOrderedHashMap(); edgeMap = new TOrderedHashMap(); - shortestPathComputed = new TOrderedHashMap, IList>>(); + shortestPathComputed = new ConcurrentHashMap, IList>>(); this.scope = scope; // WARNING TODO Verify this // IType nodeType = byEdge ? Types.NO_TYPE : @@ -142,7 +143,7 @@ public GamaGraph(final IScope scope, final IContainer edgesOrVertices, final boo public GamaGraph(final IScope scope, final IType nodeType, final IType vertexType) { vertexMap = new TOrderedHashMap(); edgeMap = new TOrderedHashMap(); - shortestPathComputed = new TOrderedHashMap, IList>>(); + shortestPathComputed = new ConcurrentHashMap, IList>>(); this.scope = scope; type = Types.GRAPH.of(nodeType, vertexType); } @@ -1261,7 +1262,7 @@ public void setOptimizer(final FloydWarshallShortestPathsGAMA optimizer) { public void loadShortestPaths(final IScope scope, final GamaMatrix matrix) { final GamaList vertices = (GamaList) getVertices(); final int nbvertices = matrix.numCols; - shortestPathComputed = new TOrderedHashMap, IList>>(); + shortestPathComputed = new ConcurrentHashMap, IList>>(); final GamaIntMatrix mat = GamaIntMatrix.from(scope, matrix); final Map edgesVertices = GamaMapFactory.create(Types.INT, getType().getContentType()); diff --git a/msi.gama.core/src/msi/gama/util/random/MersenneTwisterRNG.java b/msi.gama.core/src/msi/gama/util/random/MersenneTwisterRNG.java index 4897291f33..3cffdfc554 100644 --- a/msi.gama.core/src/msi/gama/util/random/MersenneTwisterRNG.java +++ b/msi.gama.core/src/msi/gama/util/random/MersenneTwisterRNG.java @@ -26,7 +26,6 @@ package msi.gama.util.random; import msi.gama.common.util.RandomUtils; -import msi.gaml.operators.fastmaths.CmnFastMath; /** *

@@ -130,7 +129,7 @@ public MersenneTwisterRNG(final byte[] seed) { // version. int i = 1; int j = 0; - for (int k = CmnFastMath.max(N, seedInts.length); k > 0; k--) { + for (int k = Math.max(N, seedInts.length); k > 0; k--) { mt[i] = (mt[i] ^ (mt[i - 1] ^ mt[i - 1] >>> 30) * SEED_FACTOR1) + seedInts[j] + j; i++; j++; diff --git a/msi.gama.core/src/msi/gaml/expressions/GlobalVariableExpression.java b/msi.gama.core/src/msi/gaml/expressions/GlobalVariableExpression.java index 7a212a7434..5caecf3c08 100644 --- a/msi.gama.core/src/msi/gaml/expressions/GlobalVariableExpression.java +++ b/msi.gama.core/src/msi/gaml/expressions/GlobalVariableExpression.java @@ -12,6 +12,7 @@ package msi.gaml.expressions; import msi.gama.common.interfaces.IKeyword; +import msi.gama.kernel.experiment.ITopLevelAgent; import msi.gama.metamodel.agent.IAgent; import msi.gama.runtime.IScope; import msi.gama.runtime.exceptions.GamaRuntimeException; @@ -54,7 +55,18 @@ public IExpression getOwner() { public Object value(final IScope scope) throws GamaRuntimeException { // return scope.getGlobalVarValue(getName()); final IAgent sc = scope.getAgent(); - return sc.getScope().getRoot().getScope().getGlobalVarValue(getName()); + if (sc != null) { + final IScope agentScope = sc.getScope(); + if (agentScope != null) { + final ITopLevelAgent root = agentScope.getRoot(); + if (root != null) { + final IScope globalScope = root.getScope(); + if (globalScope != null) + return globalScope.getGlobalVarValue(getName()); + } + } + } + return null; } @Override diff --git a/msi.gama.core/src/msi/gaml/expressions/PrimitiveOperator.java b/msi.gama.core/src/msi/gaml/expressions/PrimitiveOperator.java index 95878dd63b..6604adc03e 100644 --- a/msi.gama.core/src/msi/gaml/expressions/PrimitiveOperator.java +++ b/msi.gama.core/src/msi/gaml/expressions/PrimitiveOperator.java @@ -76,9 +76,7 @@ public Object value(final IScope scope) throws GamaRuntimeException { // parameters.setCaller(scope.getAgentScope()); // And finally, (3) to execute the executer on the target (it will // be pushed in the scope) - final Object[] result = new Object[1]; - scope.execute(executer, target, parameters, result); - return result[0]; + return scope.execute(executer, target, parameters).getValue(); } return null; } diff --git a/msi.gama.core/src/msi/gaml/operators/Containers.java b/msi.gama.core/src/msi/gaml/operators/Containers.java index 99597378a2..de769e9b17 100644 --- a/msi.gama.core/src/msi/gaml/operators/Containers.java +++ b/msi.gama.core/src/msi/gaml/operators/Containers.java @@ -22,6 +22,7 @@ import static msi.gama.util.GAML.emptyCheck; import static msi.gama.util.GAML.nullCheck; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -463,9 +464,8 @@ public static IList of_species(final IScope scope, final IContainer agents, fina private static IList of_species(final IScope scope, final IContainer agents, final ISpecies s, final boolean generic) { - return GamaListFactory.create(scope, scope.getModelContext().getTypeNamed(s.getName()), - Iterables.filter(agents.iterable(scope), - and(instanceOf(IAgent.class), (Predicate) be -> be.isInstanceOf(s, !generic)))); + return GamaListFactory.create(scope, scope.getType(s.getName()), Iterables.filter(agents.iterable(scope), + and(instanceOf(IAgent.class), (Predicate) be -> be.isInstanceOf(s, !generic)))); } @operator(value = { @@ -707,28 +707,6 @@ public static Object min_of(final IScope scope, final IContainer container, fina return result; } - // @operator(value = "among", content_type = - // ITypeProvider.RIGHT_CONTENT_TYPE) - // @doc(special_cases = { - // "if the right-hand operand is a map, among returns a map of right-hand - // operand element instead of a list" - // }, examples = { "2 among [1::2, 3::4, 5::6] --: [1::2, 3::4]" }) - // public static GamaMap among(final IScope scope, final Integer number, - // final GamaMap l) - // throws GamaRuntimeException { - // final GamaMap result = GamaMapFactory.create(); - // if ( l == null ) { return result; } - // int size = l.size(); - // if ( number == 0 ) { return result; } - // if ( number >= size ) { return l; } - // final IList indexes = among(scope, number, new GamaList(l.keySet())); - // for ( int i = 0; i < number; i++ ) { - // Object o = indexes.get(i); - // result.put(o, l.get(o)); - // } - // return result; - // } - @operator(value = "among", content_type = ITypeProvider.SECOND_CONTENT_TYPE, category = IOperatorCategory.CONTAINER, concept = { IConcept.CONTAINER, IConcept.FILTER }) @doc(value = "Returns a list of length the value of the left-hand operand, containing random elements from the right-hand operand. As of GAMA 1.6, the order in which the elements are returned can be different than the order in which they appear in the right-hand container", special_cases = { @@ -775,62 +753,20 @@ public static IList among(final IScope scope, final Integer number, final IConta @example(value = "(list(node) sort_by (round(node(each).location.x))", equals = "[node5, node1, node0, node2, node3]", isExecutable = false), @example(value = "[1::2, 5::6, 3::4] sort_by (each)", equals = "[2, 4, 6]") }, see = { "group_by" }) public static IList sort(final IScope scope, final IContainer original, final IExpression filter) { + if (original instanceof List) { + final Object[] array = ((List) original).toArray(new Object[((List) original).size()]); + Arrays.parallelSort(array, Guava.orderOn(Guava.function(scope, filter))); + return GamaListFactory.createWithoutCasting(original.getType().getContentType(), array); + } final Iterable it = nullCheck(scope, original).iterable(scope); final int size = size(it); if (size == 0) { return GamaListFactory.create(); } - // if ( size == 1 ) { return - // GamaListFactory.createWithoutCasting(original.getType().getContentType(), - // getFirst(it, null)); } return GamaListFactory.createWithoutCasting(original.getType().getContentType(), Guava.orderOn(Guava.function(scope, filter)).sortedCopy(it)); } - /** - * for maps, we sort the keys and reinsert them in this order in the new map - * - * @param scope - * @param original - * @param filter - * @return - * @throws GamaRuntimeException - */ - // // FIXME Completely false: rewrite this method - // @operator(value = { "sort_by", "sort" }, content_type = - // ITypeProvider.FIRST_CONTENT_TYPE, iterator = true) - // public static GamaMap sort(final IScope scope, final GamaMap original, - // final IExpression filter) - // throws GamaRuntimeException { - // final GamaMap resultMap = GamaMapFactory.create(nullCheck(scope, - // original)); - // // copy in order to prevent any side effect on the left member - // if ( resultMap.isEmpty() ) { return resultMap; } - // final IList sortedPairs = sort(scope, resultMap.getPairs(), - // filter); - // for ( final GamaPair pair : sortedPairs ) { - // resultMap.add(pair); - // } - // return resultMap; - // } - - // @operator(value = { "where", "select" }, priority = IPriority.ITERATOR, - // iterator = true) - // public static GamaMap where(final IScope scope, final GamaMap original, - // final IExpression - // filter) - // throws GamaRuntimeException { - // if ( original == null ) { return GamaMapFactory.create(); } - // final GamaMap result = GamaMapFactory.create(); - // for ( GamaPair p : original.iterable(scope) ) { - // scope.setEach(p); - // if ( Cast.asBool(scope, filter.value(scope)) ) { - // result.add(p); - // } - // } - // return result; - // } - @operator(value = { "where", "select" }, content_type = ITypeProvider.FIRST_CONTENT_TYPE, iterator = true, expected_content_type = IType.BOOL, category = IOperatorCategory.CONTAINER, concept = { IConcept.CONTAINER, IConcept.FILTER }) diff --git a/msi.gama.core/src/msi/gaml/operators/Graphs.java b/msi.gama.core/src/msi/gaml/operators/Graphs.java index 2fc860b74f..0ed3373931 100644 --- a/msi.gama.core/src/msi/gaml/operators/Graphs.java +++ b/msi.gama.core/src/msi/gaml/operators/Graphs.java @@ -738,7 +738,7 @@ public static IGraph gridCellsToGraph(final IScope scope, final IContainer verti "as_intersection_graph", "as_edge_graph" }) public static IGraph spatialDistanceGraph(final IScope scope, final IContainer vertices, final Double distance, final ISpecies edgeSpecies) { - final IType edgeType = scope.getModelContext().getTypeNamed(edgeSpecies.getName()); + final IType edgeType = scope.getType(edgeSpecies.getName()); final IGraph createdGraph = new GamaSpatialGraph(vertices, false, false, new DistanceRelation(distance), edgeSpecies, scope, vertices.getType().getContentType(), edgeType); @@ -754,7 +754,7 @@ public static IGraph spatialDistanceGraph(final IScope scope, final IContainer v final Double distance = (Double) params.get("distance"); final ISpecies edgeSpecies = (ISpecies) params.get("species"); final IType edgeType = edgeSpecies == null ? Types.GEOMETRY - : scope.getModelContext().getTypeNamed(edgeSpecies.getName()); + : scope.getType(edgeSpecies.getName()); final IGraph createdGraph = new GamaSpatialGraph(vertices, false, false, new DistanceRelation(distance), edgeSpecies, scope, vertices.getType().getContentType(), edgeType); diff --git a/msi.gama.core/src/msi/gaml/operators/Spatial.java b/msi.gama.core/src/msi/gaml/operators/Spatial.java index 49435b1c2a..3dbbc7a2cf 100644 --- a/msi.gama.core/src/msi/gaml/operators/Spatial.java +++ b/msi.gama.core/src/msi/gaml/operators/Spatial.java @@ -2777,7 +2777,7 @@ private static IList _gather(final IScope scope, final IAgentFilter filt return GamaListFactory.create(); } final IType type = filter.getSpecies() == null ? Types.AGENT - : scope.getModelContext().getTypeNamed(filter.getSpecies().getName()); + : scope.getType(filter.getSpecies().getName()); return GamaListFactory.createWithoutCasting(type, scope.getTopology().getAgentsIn(scope, Cast.asGeometry(scope, source, false), filter, inside)); } @@ -2807,7 +2807,7 @@ static IList _neighbors(final IScope scope, final IAgentFilter filter, f return GamaListFactory.create(); } final IType type = filter.getSpecies() == null ? Types.AGENT - : scope.getModelContext().getTypeNamed(filter.getSpecies().getName()); + : scope.getType(filter.getSpecies().getName()); return GamaListFactory.createWithoutCasting(type, t.getNeighborsOf(scope, Cast.asGeometry(scope, source, false), Cast.asFloat(scope, distance), filter)); } diff --git a/msi.gama.core/src/msi/gaml/operators/System.java b/msi.gama.core/src/msi/gaml/operators/System.java index 153f07b7ec..c40e4bf4ec 100644 --- a/msi.gama.core/src/msi/gaml/operators/System.java +++ b/msi.gama.core/src/msi/gaml/operators/System.java @@ -134,7 +134,7 @@ public static Object opGetValue(final IScope scope, final IAgent a, final IExpre } return null; } - return scope.evaluate(s, a); + return scope.evaluate(s, a).getValue(); } @operator(value = "copy", type = ITypeProvider.FIRST_TYPE, content_type = ITypeProvider.FIRST_CONTENT_TYPE, category = { @@ -198,7 +198,7 @@ public static Object opEvalGaml(final IScope scope, final String gaml) { final IDescription d = agent.getSpecies().getDescription(); try { final IExpression e = GAML.getExpressionFactory().createExpr(gaml, d); - return scope.evaluate(e, agent); + return scope.evaluate(e, agent).getValue(); } catch (final GamaRuntimeException e) { scope.getGui().getConsole().informConsole( "Error in evaluating Gaml code : '" + gaml + "' in " + scope.getAgent() diff --git a/msi.gama.core/src/msi/gaml/species/AbstractSpecies.java b/msi.gama.core/src/msi/gaml/species/AbstractSpecies.java index 2d731ecef6..40c3b365c3 100644 --- a/msi.gama.core/src/msi/gaml/species/AbstractSpecies.java +++ b/msi.gama.core/src/msi/gaml/species/AbstractSpecies.java @@ -127,7 +127,7 @@ public String stringValue(final IScope scope) { final IList agents = listValue(scope, contentsType, false); // Default behavior : Returns a map containing the names of agents as // keys and the agents themselves as values - final GamaMap result = GamaMapFactory.create(Types.STRING, scope.getModelContext().getTypeNamed(getName())); + final GamaMap result = GamaMapFactory.create(Types.STRING, scope.getType(getName())); for (final IAgent agent : agents.iterable(scope)) { result.put(agent.getName(), agent); } diff --git a/msi.gama.core/src/msi/gaml/species/GamlSpecies.java b/msi.gama.core/src/msi/gaml/species/GamlSpecies.java index 79f6ab97e1..8d7bfa8e54 100644 --- a/msi.gama.core/src/msi/gaml/species/GamlSpecies.java +++ b/msi.gama.core/src/msi/gaml/species/GamlSpecies.java @@ -48,6 +48,8 @@ IKeyword.GRID }, kind = ISymbolKind.SPECIES, with_sequence = true, concept = { IConcept.SPECIES }) @inside(kinds = { ISymbolKind.MODEL, ISymbolKind.ENVIRONMENT, ISymbolKind.SPECIES }) @facets(value = { + @facet(name = IKeyword.PARALLEL, type = { IType.BOOL, + IType.INT }, optional = true, doc = @doc("(experimental) setting this facet to 'true' will allow this species to use concurrency when scheduling its agents; setting it to an integer will set the threshold under which they will be run sequentially (the default is initially 20, but can be fixed in the preferences). This facet has a default set in the preferences (Under Performances > Concurrency)")), @facet(name = IKeyword.WIDTH, type = IType.INT, optional = true, doc = @doc("(grid only), the width of the grid (in terms of agent number)")), @facet(name = IKeyword.HEIGHT, type = IType.INT, optional = true, doc = @doc("(grid only), the height of the grid (in terms of agent number)")), @facet(name = IKeyword.CELL_WIDTH, type = IType.FLOAT, optional = true, doc = @doc("(grid only), the width of the cells of the grid")), @@ -181,8 +183,15 @@ public void validate(final IDescription desc) { } } + private final IExpression concurrency; + private final IExpression schedule; + private final IExpression frequency; + public GamlSpecies(final IDescription desc) { super(desc); + concurrency = this.getFacet(IKeyword.PARALLEL); + schedule = this.getFacet(IKeyword.SCHEDULES); + frequency = this.getFacet(IKeyword.FREQUENCY); } @Override @@ -192,12 +201,17 @@ public String getArchitectureName() { @Override public IExpression getFrequency() { - return this.getFacet(IKeyword.FREQUENCY); + return frequency; } @Override public IExpression getSchedule() { - return this.getFacet(IKeyword.SCHEDULES); + return schedule; + } + + @Override + public IExpression getConcurrency() { + return concurrency; } /** diff --git a/msi.gama.core/src/msi/gaml/species/ISpecies.java b/msi.gama.core/src/msi/gaml/species/ISpecies.java index 01c4d372ff..29ddc5401b 100644 --- a/msi.gama.core/src/msi/gaml/species/ISpecies.java +++ b/msi.gama.core/src/msi/gaml/species/ISpecies.java @@ -58,6 +58,8 @@ public interface ISpecies public abstract IExpression getSchedule(); + public abstract IExpression getConcurrency(); + public abstract boolean extendsSpecies(final ISpecies s); public abstract boolean isGrid(); diff --git a/msi.gama.core/src/msi/gaml/statements/AskStatement.java b/msi.gama.core/src/msi/gaml/statements/AskStatement.java index 8d348adaeb..b6515b50b8 100644 --- a/msi.gama.core/src/msi/gaml/statements/AskStatement.java +++ b/msi.gama.core/src/msi/gaml/statements/AskStatement.java @@ -11,9 +11,6 @@ **********************************************************************************************/ package msi.gaml.statements; -import java.util.Iterator; - -import msi.gama.common.GamaPreferences; import msi.gama.common.interfaces.IKeyword; import msi.gama.metamodel.agent.IAgent; import msi.gama.precompiler.GamlAnnotations.doc; @@ -25,9 +22,9 @@ import msi.gama.precompiler.GamlAnnotations.usage; import msi.gama.precompiler.IConcept; import msi.gama.precompiler.ISymbolKind; -import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; -import msi.gama.runtime.ParallelAgentRunner; +import msi.gama.runtime.IScope.ExecutionResult; +import msi.gama.runtime.concurrent.GamaExecutorService; import msi.gama.util.IContainer; import msi.gaml.compilation.ISymbol; import msi.gaml.descriptions.IDescription; @@ -41,7 +38,7 @@ @symbol(name = IKeyword.ASK, kind = ISymbolKind.SEQUENCE_STATEMENT, with_sequence = true, remote_context = true, concept = { IConcept.SPECIES }) @facets(value = { - @facet(name = "parallel", type = { IType.BOOL, + @facet(name = IKeyword.PARALLEL, type = { IType.BOOL, IType.INT }, optional = true, doc = @doc("(experimental) setting this facet to 'true' will allow 'ask' to use concurrency when traversing the targets; setting it to an integer will set the threshold under which they will be run sequentially (the default is initially 20, but can be fixed in the preferences). This facet is false by default.")), @facet(name = IKeyword.TARGET, type = { IType.CONTAINER, IType.AGENT }, of = IType.AGENT, optional = false, doc = @doc("an expression that evaluates to an agent or a list of agents")), @@ -122,41 +119,18 @@ public void leaveScope(final IScope scope) { super.leaveScope(scope); } - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Object privateExecuteIn(final IScope scope) { final Object t = target.value(scope); if (t instanceof IContainer) { - int threshold = GamaPreferences.SEQUENTIAL_THRESHOLD.getValue(); - boolean runInParallel = parallel != null; - if (runInParallel) { - final Object p = parallel.value(scope); - if (p instanceof Boolean) { - runInParallel = (Boolean) p; - } else { - threshold = (Integer) p; - } - } - - if (runInParallel) { - return privateExecuteInParallel(scope, (IContainer) t, threshold); - } - final Iterator runners = ((IContainer) t).iterable(scope).iterator(); - final Object[] result = new Object[1]; - while (runners.hasNext() && scope.execute(sequence, runners.next(), null, result)) { - } - return result[0]; + GamaExecutorService.execute(scope, sequence, + ((IContainer) t).listValue(scope, Types.AGENT, false), parallel); + return this; } else { - final Object[] result = new Object[1]; - scope.execute(sequence, (IAgent) t, null, result); - return result[0]; + final ExecutionResult result = scope.execute(sequence, (IAgent) t, null); + return result.getValue(); } } - public Object privateExecuteInParallel(final IScope scope, final IContainer agents, - final int threshold) { - final IAgent[] array = agents.listValue(scope, Types.NO_TYPE, false).toArray(new IAgent[0]); - return GAMA.executeThreaded(ParallelAgentRunner.execute(scope, sequence, array, threshold)); - } - } \ No newline at end of file diff --git a/msi.gama.core/src/msi/gaml/statements/CaptureStatement.java b/msi.gama.core/src/msi/gaml/statements/CaptureStatement.java index 3b649e1ad3..6dc3fabb51 100644 --- a/msi.gama.core/src/msi/gaml/statements/CaptureStatement.java +++ b/msi.gama.core/src/msi/gaml/statements/CaptureStatement.java @@ -186,8 +186,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { // scope.addVarWithValue(IKeyword.MYSELF, macroAgent); if (sequence != null && !sequence.isEmpty()) { for (final IAgent capturedA : capturedAgents) { - final Object[] result = new Object[1]; - if (!scope.execute(sequence, capturedA, null, result)) { + if (!scope.execute(sequence, capturedA, null).passed()) { break; } } @@ -205,8 +204,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { capturedAgent = macroAgent.captureMicroAgent(scope, microSpecies, c); if (sequence != null && !sequence.isEmpty()) { - final Object[] result = new Object[1]; - scope.execute(sequence, capturedAgent, null, result); + scope.execute(sequence, capturedAgent, null); } capturedAgents.add(capturedAgent); diff --git a/msi.gama.core/src/msi/gaml/statements/CreateStatement.java b/msi.gama.core/src/msi/gaml/statements/CreateStatement.java index a1f9dd1111..e178d6394f 100644 --- a/msi.gama.core/src/msi/gaml/statements/CreateStatement.java +++ b/msi.gama.core/src/msi/gaml/statements/CreateStatement.java @@ -20,7 +20,7 @@ import msi.gama.common.interfaces.IKeyword; import msi.gama.kernel.experiment.ExperimentAgent; import msi.gama.kernel.experiment.ExperimentPlan; -import msi.gama.kernel.experiment.ExperimentPopulation; +import msi.gama.kernel.experiment.ExperimentPlan.ExperimentPopulation; import msi.gama.kernel.simulation.SimulationAgent; import msi.gama.metamodel.agent.IAgent; import msi.gama.metamodel.agent.IMacroAgent; @@ -311,8 +311,9 @@ public IList privateExecuteIn(final IScope scope) { // hqnghi population of micro-model's experiment is not exist, we // must create the new one if (pop == null && s instanceof ExperimentPlan && executor instanceof IMacroAgent) { - pop = new ExperimentPopulation(s); - final IScope sc = ((ExperimentPlan) s).getExperimentScope(); + final ExperimentPlan ep = (ExperimentPlan) s; + pop = ep.new ExperimentPopulation(s); + final IScope sc = ep.getExperimentScope(); pop.initializeFor(sc); ((IMacroAgent) executor).addExternMicroPopulation( s.getDescription().getModelDescription().getAlias() + "." + s.getName(), pop); @@ -388,8 +389,7 @@ private IList createAgents(final IScope scope, final IPopulati // end-hqnghi if (sequence != null && !sequence.isEmpty()) { for (final IAgent remoteAgent : list.iterable(scope)) { - final Object[] result = new Object[1]; - if (!scope.execute(sequence, remoteAgent, null, result)) { + if (!scope.execute(sequence, remoteAgent, null).passed()) { break; } } diff --git a/msi.gama.core/src/msi/gaml/statements/ReleaseStatement.java b/msi.gama.core/src/msi/gaml/statements/ReleaseStatement.java index d92a975787..afc7e5e706 100644 --- a/msi.gama.core/src/msi/gaml/statements/ReleaseStatement.java +++ b/msi.gama.core/src/msi/gaml/statements/ReleaseStatement.java @@ -129,7 +129,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { if (asExpr != null && inExpr != null) { targetAgent = (IMacroAgent) inExpr.value(scope); if (targetAgent != null && !targetAgent.equals(macroAgent)) { - microSpecies = (ISpecies) scope.evaluate(asExpr, targetAgent); + microSpecies = (ISpecies) scope.evaluate(asExpr, targetAgent).getValue(); releasedMicroAgents = targetAgent.captureMicroAgents(scope, microSpecies, microAgents); } } else if (asExpr != null && inExpr == null) { @@ -193,8 +193,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { // scope.addVarWithValue(IKeyword.MYSELF, macroAgent); if (!sequence.isEmpty()) { for (final IAgent releasedA : releasedMicroAgents) { - final Object[] result = new Object[1]; - if (!scope.execute(sequence, releasedA, null, result)) { + if (!scope.execute(sequence, releasedA, null).passed()) { break; } } diff --git a/msi.gama.core/src/msi/gaml/statements/UserCommandStatement.java b/msi.gama.core/src/msi/gaml/statements/UserCommandStatement.java index b4499f9f6a..bf0740ef50 100644 --- a/msi.gama.core/src/msi/gaml/statements/UserCommandStatement.java +++ b/msi.gama.core/src/msi/gaml/statements/UserCommandStatement.java @@ -174,9 +174,8 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { } if (isWorkaroundForIssue1595) { final SimulationPopulation simulations = scope.getExperiment().getSimulationPopulation(); - final Object[] resultArray = new Object[1]; for (final SimulationAgent sim : simulations.iterable(scope)) { - scope.execute(executer, sim, tempArgs, resultArray); + scope.execute(executer, sim, tempArgs); } } else { executer.setRuntimeArgs(tempArgs); diff --git a/msi.gama.core/src/msi/gaml/types/GamaMatrixType.java b/msi.gama.core/src/msi/gaml/types/GamaMatrixType.java index 271894dd3d..1cb8056f94 100644 --- a/msi.gama.core/src/msi/gaml/types/GamaMatrixType.java +++ b/msi.gama.core/src/msi/gaml/types/GamaMatrixType.java @@ -20,8 +20,8 @@ import msi.gama.precompiler.GamlAnnotations.type; import msi.gama.precompiler.IConcept; import msi.gama.precompiler.ISymbolKind; -import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; +import msi.gama.runtime.concurrent.GamaExecutorService; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.IContainer; import msi.gama.util.IList; @@ -145,7 +145,7 @@ public static IMatrix with(final IScope scope, final IExpression fillExpr, final if (fillExpr.isConst()) { Arrays.fill(dd, Cast.asFloat(scope, fillExpr.value(scope))); } else - GAMA.executeThreaded(() -> IntStream.range(0, dd.length).parallel().forEach(i -> { + GamaExecutorService.executeThreaded(() -> IntStream.range(0, dd.length).parallel().forEach(i -> { dd[i] = Cast.asFloat(scope, fillExpr.value(scope)); })); break; @@ -155,7 +155,7 @@ public static IMatrix with(final IScope scope, final IExpression fillExpr, final if (fillExpr.isConst()) { Arrays.fill(ii, Cast.asInt(scope, fillExpr.value(scope))); } else - GAMA.executeThreaded(() -> IntStream.range(0, ii.length).parallel().forEach(i -> { + GamaExecutorService.executeThreaded(() -> IntStream.range(0, ii.length).parallel().forEach(i -> { ii[i] = Cast.asInt(scope, fillExpr.value(scope)); })); break; @@ -165,7 +165,7 @@ public static IMatrix with(final IScope scope, final IExpression fillExpr, final if (fillExpr.isConst()) { Arrays.fill(contents, fillExpr.value(scope)); } else - GAMA.executeThreaded(() -> IntStream.range(0, contents.length).parallel().forEach(i -> { + GamaExecutorService.executeThreaded(() -> IntStream.range(0, contents.length).parallel().forEach(i -> { contents[i] = fillExpr.value(scope); })); } diff --git a/msi.gama.core/src/msi/gaml/variables/NumberVariable.java b/msi.gama.core/src/msi/gaml/variables/NumberVariable.java index 7606a8de22..d30315dd82 100644 --- a/msi.gama.core/src/msi/gaml/variables/NumberVariable.java +++ b/msi.gama.core/src/msi/gaml/variables/NumberVariable.java @@ -110,13 +110,15 @@ public Object coerce(final IAgent agent, final IScope scope, final Object v) thr protected Integer checkMinMax(final IAgent agent, final IScope scope, final Integer f) throws GamaRuntimeException { if (min != null) { - final Integer m = minVal == null ? Cast.asInt(scope, scope.evaluate(min, agent)) : (Integer) minVal; + final Integer m = minVal == null ? Cast.asInt(scope, scope.evaluate(min, agent).getValue()) + : (Integer) minVal; if (f < m) { return m; } } if (max != null) { - final Integer m = maxVal == null ? Cast.asInt(scope, scope.evaluate(max, agent)) : (Integer) maxVal; + final Integer m = maxVal == null ? Cast.asInt(scope, scope.evaluate(max, agent).getValue()) + : (Integer) maxVal; if (f > m) { return m; } @@ -126,13 +128,15 @@ protected Integer checkMinMax(final IAgent agent, final IScope scope, final Inte protected Double checkMinMax(final IAgent agent, final IScope scope, final Double f) throws GamaRuntimeException { if (min != null) { - final Double fmin = minVal == null ? Cast.asFloat(scope, scope.evaluate(min, agent)) : (Double) minVal; + final Double fmin = minVal == null ? Cast.asFloat(scope, scope.evaluate(min, agent).getValue()) + : (Double) minVal; if (f < fmin) { return fmin; } } if (max != null) { - final Double fmax = maxVal == null ? Cast.asFloat(scope, scope.evaluate(max, agent)) : (Double) maxVal; + final Double fmax = maxVal == null ? Cast.asFloat(scope, scope.evaluate(max, agent).getValue()) + : (Double) maxVal; if (f > fmax) { return fmax; } diff --git a/msi.gama.core/src/msi/gaml/variables/Variable.java b/msi.gama.core/src/msi/gaml/variables/Variable.java index 9db7a4a7a7..4485d1fdd8 100644 --- a/msi.gama.core/src/msi/gaml/variables/Variable.java +++ b/msi.gama.core/src/msi/gaml/variables/Variable.java @@ -382,7 +382,7 @@ public void initializeWith(final IScope scope, final IAgent a, final Object v) t if (v != null) { _setVal(a, scope, v); } else if (initExpression != null) { - _setVal(a, scope, scope.evaluate(initExpression, a)); + _setVal(a, scope, scope.evaluate(initExpression, a).getValue()); } else if (initer != null) { final Object val = initer.run(scope, a, gSkill == null ? a : gSkill); _setVal(a, scope, val); @@ -424,8 +424,6 @@ public void setName(final String name) { this.name = name; } - private static Object[] JunkResults = new Object[1]; - @Override public final void setVal(final IScope scope, final IAgent agent, final Object v) throws GamaRuntimeException { if (isNotModifiable) { @@ -437,7 +435,7 @@ public final void setVal(final IScope scope, final IAgent agent, final Object v) if (on_changer == null) { on_changer = agent.getSpecies().getAction(Cast.asString(scope, onChangeExpression.value(scope))); } - scope.execute(on_changer, agent, null, JunkResults); + scope.execute(on_changer, agent, null); } } @@ -456,7 +454,7 @@ protected Object checkAmong(final IAgent agent, final IScope scope, final Object if (amongExpression == null) { return val; } - final List among = Cast.asList(scope, scope.evaluate(amongExpression, agent)); + final List among = Cast.asList(scope, scope.evaluate(amongExpression, agent).getValue()); if (among == null) { return val; } @@ -481,7 +479,7 @@ public Object value(final IScope scope, final IAgent agent) throws GamaRuntimeEx return getter.run(scope, agent, gSkill == null ? agent : gSkill); } if (functionExpression != null) { - return scope.evaluate(functionExpression, agent); + return scope.evaluate(functionExpression, agent).getValue(); } return agent.getAttribute(name); } diff --git a/msi.gama.models/models/Features/3D Visualization/models/Building Elevation.gaml b/msi.gama.models/models/Features/3D Visualization/models/Building Elevation.gaml index 7a597dcfb8..95191988ed 100644 --- a/msi.gama.models/models/Features/3D Visualization/models/Building Elevation.gaml +++ b/msi.gama.models/models/Features/3D Visualization/models/Building Elevation.gaml @@ -24,7 +24,7 @@ global //Definition of the shape of the world as the bounds of the shapefiles to show everything contained // by the area delimited by the bounds geometry shape <- envelope(shape_file_bounds); - int nb_people <- 100; + int nb_people <- 5000; int day_time update: cycle mod 144; int min_work_start <- 36; int max_work_start <- 60; @@ -83,7 +83,7 @@ species road species people skills: [moving] { float speed <- min_speed + rnd(max_speed - min_speed); - rgb color <- # yellow; + rgb color <- rnd_color(255); building living_place <- one_of(residential_buildings); building working_place <- one_of(industrial_buildings); point location <- any_location_in(living_place) + { 0, 0, living_place.height }; diff --git a/msi.gama.models/models/Toy Models/Ants (Foraging and Sorting)/models/Ant Foraging (Multi-Simulation).gaml b/msi.gama.models/models/Toy Models/Ants (Foraging and Sorting)/models/Ant Foraging (Multi-Simulation).gaml index 7988eb7f74..044190c6b8 100644 --- a/msi.gama.models/models/Toy Models/Ants (Foraging and Sorting)/models/Ant Foraging (Multi-Simulation).gaml +++ b/msi.gama.models/models/Toy Models/Ants (Foraging and Sorting)/models/Ant Foraging (Multi-Simulation).gaml @@ -7,128 +7,7 @@ */ model ants -global { - //Evaporation value per cycle of the pheromons - float evaporation_per_cycle <- 5.0 min: 0.0 max: 240.0 parameter: 'Evaporation of the signal (unit/cycle):' category: 'Signals'; - //Diffusion rate of the pheromons - float diffusion_rate <- 1.0 min: 0.0 max: 1.0 parameter: 'Rate of diffusion of the signal (%/cycle):' category: 'Signals'; - //Size of the grid - int gridsize <- 100 min: 30 parameter: 'Width and Height of the grid:' category: 'Environment and Population'; - //Number of ants that will be created - int ants_number <- 50 min: 1 parameter: 'Number of ants:' category: 'Environment and Population'; - //Number of food places to create - int number_of_food_places <- 5 min: 1 parameter: 'Number of food depots:' category: 'Environment and Population'; - float grid_transparency <- 1.0; - file ant_shape_empty const: true <- file('../icons/ant.png'); - string ant_shape_full const: true <- '../icons/full_ant.png'; - point center const: true <- { round(gridsize / 2), round(gridsize / 2) }; - int food_gathered <- 1; - int food_placed <- 1; - rgb background const: true <- rgb(#99CC66); - rgb food_color const: true <- rgb(#312200); - rgb nest_color const: true <- rgb(#000000); - - geometry shape <- square(gridsize); - init { - //Creation of the food places placed randomly with a certain distance between each - loop times: number_of_food_places { - point loc <- { rnd(gridsize - 10) + 5, rnd(gridsize - 10) + 5 }; - list food_places <- (ant_grid where ((each distance_to loc) < 5)); - ask food_places { - if food = 0 { - food <- 5; - food_placed <- food_placed + 5; - color <- food_color; - } - } - } - //Creation of the ants that will be placed in the nest - create ant number: ants_number with: (location: center); - //Write the index of the simulation - write "Simulation " + int(self) + " created"; - } - //Reflex to diffuse the pheromon among the grid - reflex diffuse { - diffuse var:road on:ant_grid proportion: diffusion_rate radius:2 propagation: gradient; - } - - - -} - -//Grid used to discretize the space to place food -grid ant_grid width: gridsize height: gridsize neighbors: 8 /*frequency: grid_frequency*/ use_regular_agents: false use_individual_shapes: false{ - bool is_nest const: true <- (topology(ant_grid) distance_between [self, center]) < 4; - float road <- 0.0 max:240.0 update: (road<=evaporation_per_cycle) ? 0.0 : road-evaporation_per_cycle; - rgb color <- is_nest ? nest_color : ((food > 0) ? food_color : ((road < 0.001) ? background : rgb(#009900) + int(road * 5))) update: is_nest ? nest_color : ((food > 0) ? - food_color : ((road < 0.001) ? background : rgb(#009900) + int(road * 5))); - int food <- 0; -} -//Species ant that will move and follow a final state machine -species ant skills: [moving] control: fsm { - float speed <- 1.0; - bool has_food <- false; - - //Reflex to place a pheromon stock in the cell - reflex diffuse_road when:has_food=true{ - ant_grid(location).road <- ant_grid(location).road + 100.0; - } - //Action to pick food - action pick (int amount) { - has_food <- true; - ant_grid place <- ant_grid(location); - place.food <- place.food - amount; - } - //Action to drop food - action drop { - food_gathered <- food_gathered + 1; - has_food <- false; - heading <- heading - 180; - } - //Action to find the best place in the neighborhood cells - point choose_best_place { - list list_places <- ant_grid(location).neighbors; - if (list_places count (each.food > 0)) > 0 { - return point(list_places first_with (each.food > 0)); - } else { - list_places <- (list_places where ((each.road > 0) and ((each distance_to center) > (self distance_to center)))) sort_by (each.road); - return point(last(list_places)); - } - } - //Reflex to drop food once the ant is in the nest - reflex drop when: has_food and (ant_grid(location)).is_nest { - do drop(); - } - //Reflex to pick food when there is one at the same location - reflex pick when: !has_food and (ant_grid(location)).food > 0 { - do pick(1); - } - //Initial state to make the ant wander - state wandering initial: true { - do wander(amplitude: 90); - float pr <- (ant_grid(location)).road; - transition to: carryingFood when: has_food; - transition to: followingRoad when: (pr > 0.05) and (pr < 4); - } - //State to carry food once it has been found - state carryingFood { - do goto(target: center); - transition to: wandering when: !has_food; - } - //State to follow a pheromon road if once has been found - state followingRoad { - point next_place <- choose_best_place(); - float pr <- (ant_grid(location)).road; - location <- next_place; - transition to: carryingFood when: has_food; - transition to: wandering when: (pr < 0.05) or (next_place = nil); - } - - aspect icon { - draw ant_shape_empty size: {8,6} rotate: my heading + 1; - } - -} +import "Ant Foraging (Complex).gaml" diff --git a/msi.gama.models/models/Toy Models/Flood Simulation/models/Hydrological Model.gaml b/msi.gama.models/models/Toy Models/Flood Simulation/models/Hydrological Model.gaml index e61be6eeaf..9b92c63685 100644 --- a/msi.gama.models/models/Toy Models/Flood Simulation/models/Hydrological Model.gaml +++ b/msi.gama.models/models/Toy Models/Flood Simulation/models/Hydrological Model.gaml @@ -11,6 +11,7 @@ model hydro global { + bool parallel <- true; //Shapefile for the river file river_shapefile <- file("../includes/RedRiver.shp"); //Shapefile for the dykes @@ -50,14 +51,14 @@ global { //Initialization of the obstacles (buildings and dykes) do init_obstacles; //Set the height of each cell - ask cell parallel: true{ + ask cell parallel: parallel{ obstacle_height <- compute_highest_obstacle(); do update_color; } } //Action to initialize the altitude value of the cell according to the dem file action init_cells { - ask cell parallel: true { + ask cell parallel: parallel { altitude <- grid_value; neighbour_cells <- (self neighbors_at 1) ; } @@ -65,7 +66,7 @@ global { //action to initialize the water cells according to the river shape file and the drain action init_water { geometry river <- geometry(river_shapefile); - ask cell overlapping river { + ask cell overlapping river parallel: parallel { water_height <- 10.0; is_river <- true; is_drain <- grid_y = matrix(cell).rows - 1; @@ -77,7 +78,7 @@ global { do update_cells; } create dyke from: dykes_shapefile; - ask dyke parallel: 2 { + ask dyke parallel: parallel { shape <- shape + dyke_width; do update_cells; } @@ -85,33 +86,33 @@ global { //Reflex to add water among the water cells reflex adding_input_water { float water_input <- rnd(100)/100; - ask river_cells parallel: true{ + ask river_cells parallel: parallel{ water_height <- water_height + water_input; } } //Reflex to flow the water according to the altitute and the obstacle reflex flowing { - ask (cell sort_by ((each.altitude + each.water_height + each.obstacle_height))) parallel: true { + ask (cell sort_by ((each.altitude + each.water_height + each.obstacle_height))) parallel: parallel { already <- false; do flow; } } //Reflex to update the color of the cell reflex update_cell_color { - ask cell parallel: true { + ask cell parallel: parallel { do update_color; } } //Reflex for the drain cells to drain water reflex draining { - ask drain_cells parallel: true{ + ask drain_cells parallel: parallel{ water_height <- 0.0; } } } //Species which represent the obstacle - species obstacle { + species obstacle parallel: parallel { //height of the obstacle float height min: 0.0; //Color of the obstacle @@ -163,12 +164,12 @@ global { } } //Species buildings which is derivated from obstacle - species buildings parent: obstacle { + species buildings parent: obstacle schedules: [] { //The building has a height randomly chosed between 2 and 10 float height <- 2.0 + rnd(8); } //Species dyke which is derivated from obstacle - species dyke parent: obstacle{ + species dyke parent: obstacle parallel: parallel { int counter_wp <- 0; int breaking_threshold <- 24; @@ -202,7 +203,7 @@ global { user_command "Destroy dyke" action: break; } //Grid cell to discretize space, initialized using the dem file - grid cell file: dem_file neighbors: 8 frequency: 0 use_regular_agents: false use_individual_shapes: false use_neighbors_cache: false schedules: [] { + grid cell file: dem_file neighbors: 8 frequency: 0 use_regular_agents: false use_individual_shapes: false use_neighbors_cache: false schedules: [] parallel: parallel { //Altitude of the cell float altitude; //Height of the water in the cell @@ -274,6 +275,7 @@ global { experiment main_gui type: gui { + parameter "Run agents in parallel" var: parallel <- true category: "Model"; parameter "Shapefile for the river" var:river_shapefile category:"Water data"; parameter "Shapefile for the dykes" var:dykes_shapefile category:"Obstacles"; parameter "Shapefile for the buildings" var:buildings_shapefile category:"Obstacles"; diff --git a/msi.gama.models/models/Toy Models/Life/Life.gaml b/msi.gama.models/models/Toy Models/Life/Life.gaml index 9de986802b..d9c37a2d67 100644 --- a/msi.gama.models/models/Toy Models/Life/Life.gaml +++ b/msi.gama.models/models/Toy Models/Life/Life.gaml @@ -13,7 +13,7 @@ global torus: torus_environment { //Size of the environment int environment_width <- 200 min: 10 max: 1000; int environment_height <- 200 min: 10 max: 1000; - + bool parallel <- true; //Declare as torus or not bool torus_environment <- true; //Density @@ -41,7 +41,7 @@ global torus: torus_environment { //Ask at each life_cell to evolve and update reflex generation { // The computation is made in parallel - ask life_cell parallel: 50 { + ask life_cell parallel: parallel { do evolve; } } @@ -55,7 +55,7 @@ global torus: torus_environment { //Grid species representing a cellular automata grid life_cell width: environment_width height: environment_height neighbors: 8 use_individual_shapes: false use_regular_agents: false -use_neighbors_cache: false { +use_neighbors_cache: false parallel: parallel{ //Boolean to know if it is the new state of the cell bool new_state; //List of all the neighbours @@ -89,6 +89,7 @@ use_neighbors_cache: false { experiment "Game of Life" type: gui { + parameter "Run in parallel " var: parallel category: 'Board'; parameter 'Width:' var: environment_width category: 'Board'; parameter 'Height:' var: environment_height category: 'Board'; parameter 'Torus?:' var: torus_environment category: 'Board'; diff --git a/msi.gaml.architecture.simplebdi/src/msi/gaml/architecture/simplebdi/PerceiveStatement.java b/msi.gaml.architecture.simplebdi/src/msi/gaml/architecture/simplebdi/PerceiveStatement.java index c57b5aed6f..63cf571c5b 100644 --- a/msi.gaml.architecture.simplebdi/src/msi/gaml/architecture/simplebdi/PerceiveStatement.java +++ b/msi.gaml.architecture.simplebdi/src/msi/gaml/architecture/simplebdi/PerceiveStatement.java @@ -28,6 +28,7 @@ import msi.gama.precompiler.IConcept; import msi.gama.precompiler.ISymbolKind; import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.ExecutionResult; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.GamaListFactory; import msi.gama.util.IContainer; @@ -139,12 +140,13 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { } } final Iterator runners = ((IContainer) temp).iterable(scope).iterator(); - final Object[] result = new Object[1]; + ExecutionResult result = null; if (runners != null) { - while (runners.hasNext() && scope.execute(sequence, runners.next(), null, result)) { + while (runners.hasNext() + && (result = scope.execute(sequence, runners.next(), null)).passed()) { } } - return result[0]; + return result.getValue(); } else if (inArg instanceof msi.gaml.types.GamaGeometryType || inArg instanceof GamaShape) { IList temp = GamaListFactory.create(); @@ -158,20 +160,21 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { } } final Iterator runners = ((IContainer) temp).iterable(scope).iterator(); - final Object[] result = new Object[1]; + ExecutionResult result = null; if (runners != null) { - while (runners.hasNext() && scope.execute(sequence, runners.next(), null, result)) { + while (runners.hasNext() + && (result = scope.execute(sequence, runners.next(), null)).passed()) { } } - return result[0]; + return result.getValue(); } else { - final Object[] result = new Object[1]; + ExecutionResult result = null; final Iterator runners = obj instanceof IContainer ? ((IContainer) obj).iterable(scope).iterator() : obj instanceof IAgent ? transformAgentToList((IAgent) obj, scope) : null; - while (runners.hasNext() && scope.execute(sequence, runners.next(), null, result)) { + while (runners.hasNext() && (result = scope.execute(sequence, runners.next(), null)).passed()) { } - return result[0]; + return result.getValue(); } } } diff --git a/msi.gaml.extensions.fipa/src/msi/gaml/extensions/fipa/FIPASkill.java b/msi.gaml.extensions.fipa/src/msi/gaml/extensions/fipa/FIPASkill.java index 8d3d3f5c8b..3bef54d982 100644 --- a/msi.gaml.extensions.fipa/src/msi/gaml/extensions/fipa/FIPASkill.java +++ b/msi.gaml.extensions.fipa/src/msi/gaml/extensions/fipa/FIPASkill.java @@ -747,7 +747,7 @@ private IList filter(final IScope scope, final IAgent agent, final return GamaListFactory.create(); } final IList result = GamaListFactory - .create(scope.getModelContext().getTypeNamed(GamaMessageType.MESSAGE_STR)); + .create(scope.getType(GamaMessageType.MESSAGE_STR)); for (final FIPAMessage m : inBox) { final boolean unread = m.isUnread(); final int mperf = m.getPerformative(); diff --git a/ummisco.gama.annotations/src/msi/gama/common/interfaces/IKeyword.java b/ummisco.gama.annotations/src/msi/gama/common/interfaces/IKeyword.java index 4253d759fd..b1b2ba34b1 100644 --- a/ummisco.gama.annotations/src/msi/gama/common/interfaces/IKeyword.java +++ b/ummisco.gama.annotations/src/msi/gama/common/interfaces/IKeyword.java @@ -315,6 +315,7 @@ public interface IKeyword { public static final String PERMANENT = "permanent"; // "show" // "front_end" // // "presentation" // // " + public static final String PARALLEL = "parallel"; public static final String PERSPECTIVE = "perspective"; public static final String PIE = "pie"; public static final String PITCH = "pitch"; diff --git a/ummisco.gama.serialize/src/ummisco/gama/serializer/gamaType/converters/GamaBasicTypeConverter.java b/ummisco.gama.serialize/src/ummisco/gama/serializer/gamaType/converters/GamaBasicTypeConverter.java index bb0c8096be..ec5365a5e1 100644 --- a/ummisco.gama.serialize/src/ummisco/gama/serializer/gamaType/converters/GamaBasicTypeConverter.java +++ b/ummisco.gama.serialize/src/ummisco/gama/serializer/gamaType/converters/GamaBasicTypeConverter.java @@ -56,7 +56,7 @@ public void marshal(final Object arg0, final HierarchicalStreamWriter writer, fi @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext arg1) { reader.moveDown(); - final IType t = convertScope.getScope().getModelContext().getTypeNamed(reader.getValue()); + final IType t = convertScope.getScope().getType(reader.getValue()); // ModelDescription modelDesc = ((ModelDescription) // convertScope.getScope().getModelContext()); // IType t = ((ModelDescription) diff --git a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/commands/RuntimeExceptionHandler.java b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/commands/RuntimeExceptionHandler.java index fc4ade2121..27e9af1f3c 100644 --- a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/commands/RuntimeExceptionHandler.java +++ b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/commands/RuntimeExceptionHandler.java @@ -120,7 +120,6 @@ public void updateUI(final List newExceptions) { @Override public void start() { - System.out.println("Handler launched"); running = true; schedule(); diff --git a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/menus/AgentsMenu.java b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/menus/AgentsMenu.java index 3f6cfc8703..9d51193685 100644 --- a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/menus/AgentsMenu.java +++ b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/menus/AgentsMenu.java @@ -35,6 +35,7 @@ import msi.gama.outputs.InspectDisplayOutput; import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.ExecutionResult; import msi.gaml.operators.fastmaths.CmnFastMath; import msi.gaml.statements.Arguments; import msi.gaml.statements.IStatement; @@ -224,11 +225,10 @@ public void widgetSelected(final SelectionEvent e) { if (c != null && a != null && !a.dead()) { final IScope runningScope = a.getScope(); runningScope.getSimulation().executeAction(scope -> { - final Object[] result = new Object[1]; final Arguments args = new Arguments(); - scope.execute(c, a, args, result); + final ExecutionResult result = scope.execute(c, a, args); GAMA.getExperiment().refreshAllOutputs(); - return result[0]; + return result.getValue(); }); } diff --git a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/console/InteractiveConsoleView.java b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/console/InteractiveConsoleView.java index 47c8f65f7c..d5ff1328bd 100644 --- a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/console/InteractiveConsoleView.java +++ b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/console/InteractiveConsoleView.java @@ -11,11 +11,9 @@ import org.eclipse.jface.text.IDocumentListener; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.custom.VerifyKeyListener; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -108,22 +106,17 @@ public void documentAboutToBeChanged(final DocumentEvent event) { } }); - viewer.getTextWidget().addVerifyKeyListener(new VerifyKeyListener() { + viewer.getTextWidget().addVerifyKeyListener(e -> { + if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) { + final StyledText text = (StyledText) e.widget; + final Point selection = text.getSelection(); + final int line = text.getLineAtOffset(selection.y); + if (line == text.getLineCount() - 1) { + e.doit = false; + insertHistory(e.keyCode == SWT.ARROW_UP); - @Override - public void verifyKey(final VerifyEvent e) { - if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) { - final StyledText text = (StyledText) e.widget; - final Point selection = text.getSelection(); - final int line = text.getLineAtOffset(selection.y); - if (line == text.getLineCount() - 1) { - e.doit = false; - insertHistory(e.keyCode == SWT.ARROW_UP); - - } } } - }); p.layout(true, true); showPrompt(); @@ -138,27 +131,19 @@ public Composite getControlToDisplayInFullScreen() { private void showPrompt() { - new Thread(new Runnable() { - - @Override - public void run() { - append(Strings.LN + PROMPT, false, false); - try { - // Wait for the output stream to finish - Thread.sleep(200); - } catch (final InterruptedException e) { - } - WorkbenchHelper.run(new Runnable() { - - @Override - public void run() { - if (viewer != null && viewer.getTextWidget() != null && !viewer.getTextWidget().isDisposed()) - viewer.getTextWidget().setCaretOffset(viewer.getTextWidget().getCharCount()); + new Thread(() -> { + append(Strings.LN + PROMPT, false, false); + try { + // Wait for the output stream to finish + Thread.sleep(200); + } catch (final InterruptedException e) { + } + WorkbenchHelper.run(() -> { + if (viewer != null && viewer.getTextWidget() != null && !viewer.getTextWidget().isDisposed()) + viewer.getTextWidget().setCaretOffset(viewer.getTextWidget().getCharCount()); - } - }); + }); - } }).start(); ; @@ -204,19 +189,15 @@ private void insertHistory(final boolean back) { public void append(final String text, final boolean error, final boolean showPrompt) { final OutputStreamWriter writer = error ? errorWriter : resultWriter; - WorkbenchHelper.asyncRun(new Runnable() { - - @Override - public void run() { - try { - writer.append(text); - writer.flush(); - if (showPrompt) - showPrompt(); - } catch (final IOException e) { - } - + WorkbenchHelper.asyncRun(() -> { + try { + writer.append(text); + writer.flush(); + if (showPrompt) + showPrompt(); + } catch (final IOException e) { } + }); } @@ -299,15 +280,8 @@ public void append(final String text, final ITopLevelAgent agent, final GamaColo private void setExecutorAgent(final IAgent agent) { listeningAgent = agent; if (agent != null) - WorkbenchHelper.asyncRun(new Runnable() { - - @Override - public void run() { - toolbar.status(GamaIcons.create(IGamaIcons.MENU_AGENT).image(), - "Listening agent: " + Cast.toGaml(agent), IGamaColors.NEUTRAL, SWT.LEFT); - - } - }); + WorkbenchHelper.asyncRun(() -> toolbar.status(GamaIcons.create(IGamaIcons.MENU_AGENT).image(), + "Listening agent: " + Cast.toGaml(agent), IGamaColors.NEUTRAL, SWT.LEFT)); } @@ -323,7 +297,7 @@ protected void processInput(final String s) { try { final IExpression expr = GAML.compileExpression(s, listeningAgent, false); if (expr != null) { - result = Cast.toGaml(listeningAgent.getScope().evaluate(expr, listeningAgent)); + result = Cast.toGaml(listeningAgent.getScope().evaluate(expr, listeningAgent).getValue()); } } catch (final Exception e) { error = true; diff --git a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/inspectors/AgentInspectView.java b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/inspectors/AgentInspectView.java index cd26987b52..7a17ed9b51 100644 --- a/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/inspectors/AgentInspectView.java +++ b/ummisco.gama.ui.experiment/src/ummisco/gama/ui/views/inspectors/AgentInspectView.java @@ -169,9 +169,7 @@ public void widgetSelected(final SelectionEvent e) { // We run into the scope provided by the agent final IScope runningScope = agent.getScope(); runningScope.getSimulation().executeAction(scope -> { - final Object[] result = new Object[1]; - scope.execute(command, agent, null, result); - return result[0]; + return scope.execute(command, agent, null).getValue(); }); } diff --git a/ummisco.gama.ui.shared/src/ummisco/gama/ui/parameters/AgentEditor.java b/ummisco.gama.ui.shared/src/ummisco/gama/ui/parameters/AgentEditor.java index 88c2c29d72..52995e5827 100644 --- a/ummisco.gama.ui.shared/src/ummisco/gama/ui/parameters/AgentEditor.java +++ b/ummisco.gama.ui.shared/src/ummisco/gama/ui/parameters/AgentEditor.java @@ -21,7 +21,6 @@ import msi.gama.kernel.experiment.IParameter; import msi.gama.metamodel.agent.IAgent; import msi.gama.runtime.IScope; -import msi.gama.util.GAML; import msi.gaml.types.IType; import ummisco.gama.ui.interfaces.EditorListener; import ummisco.gama.ui.interfaces.IAgentMenuFactory; @@ -117,7 +116,7 @@ public void widgetSelected(final SelectionEvent e) { @Override public IType getExpectedType() { - return GAML.getModelContext().getTypeNamed(species); + return getScope().getType(species); } /** diff --git a/ummisco.gaml.extensions.maths/src/ummisco/gaml/extensions/maths/ode/statements/SystemOfEquationsStatement.java b/ummisco.gaml.extensions.maths/src/ummisco/gaml/extensions/maths/ode/statements/SystemOfEquationsStatement.java index 2c905178ce..ccdf1db95e 100644 --- a/ummisco.gaml.extensions.maths/src/ummisco/gaml/extensions/maths/ode/statements/SystemOfEquationsStatement.java +++ b/ummisco.gaml.extensions.maths/src/ummisco/gaml/extensions/maths/ode/statements/SystemOfEquationsStatement.java @@ -41,6 +41,7 @@ import msi.gama.precompiler.ISymbolKind; import msi.gama.runtime.GAMA; import msi.gama.runtime.IScope; +import msi.gama.runtime.IScope.ExecutionResult; import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.IList; import msi.gaml.compilation.IDescriptionValidator; @@ -271,9 +272,8 @@ public void computeDerivatives(final double time, final double[] y, final double final Map equaAgents = getEquationAgents(currentScope); for (int i = 0, n = getDimension(); i < n; i++) { try { - final Object[] result = new Object[1]; - currentScope.execute(equations.get(i), equaAgents.get(i), null, result); - ydot[i] = Cast.asFloat(currentScope, result[0]); + final ExecutionResult result = currentScope.execute(equations.get(i), equaAgents.get(i), null); + ydot[i] = Cast.asFloat(currentScope, result.getValue()); } catch (final Throwable e2) { GAMA.reportAndThrowIfNeeded(currentScope, GamaRuntimeException.create(e2, currentScope), true); } diff --git a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/PauseSoundStatement.java b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/PauseSoundStatement.java index bba28b7a69..85cc93aaa5 100644 --- a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/PauseSoundStatement.java +++ b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/PauseSoundStatement.java @@ -67,8 +67,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { soundPlayer.pause(); if (sequence != null) { - final Object[] result = new Object[1]; - scope.execute(sequence, currentAgent, null, result); + scope.execute(sequence, currentAgent, null); } return null; diff --git a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/ResumeSoundStatement.java b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/ResumeSoundStatement.java index 81e3a4599f..49cfe6ca6f 100644 --- a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/ResumeSoundStatement.java +++ b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/ResumeSoundStatement.java @@ -67,8 +67,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { soundPlayer.resume(); if (sequence != null) { - final Object[] result = new Object[1]; - scope.execute(sequence, currentAgent, null, result); + scope.execute(sequence, currentAgent, null); } return null; diff --git a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StartSoundStatement.java b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StartSoundStatement.java index c0b936eb37..1f42df6606 100644 --- a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StartSoundStatement.java +++ b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StartSoundStatement.java @@ -97,8 +97,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { } if (sequence != null) { - final Object[] result = new Object[1]; - scope.execute(sequence, currentAgent, null, result); + scope.execute(sequence, currentAgent, null); } return null; diff --git a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StopSoundStatement.java b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StopSoundStatement.java index f9b679118c..cb333300fd 100644 --- a/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StopSoundStatement.java +++ b/ummisco.gaml.extensions.sound/src/ummisco/gaml/extensions/sound/StopSoundStatement.java @@ -67,8 +67,7 @@ public Object privateExecuteIn(final IScope scope) throws GamaRuntimeException { soundPlayer.stop(false); if (sequence != null) { - final Object[] result = new Object[1]; - scope.execute(sequence, currentAgent, null, result); + scope.execute(sequence, currentAgent, null); } return null;