diff --git a/msi.gama.core/src/msi/gama/kernel/batch/ExhaustiveSearch.java b/msi.gama.core/src/msi/gama/kernel/batch/ExhaustiveSearch.java index d27bd0d467..dd1cd31b17 100644 --- a/msi.gama.core/src/msi/gama/kernel/batch/ExhaustiveSearch.java +++ b/msi.gama.core/src/msi/gama/kernel/batch/ExhaustiveSearch.java @@ -10,11 +10,13 @@ ********************************************************************************************************/ package msi.gama.kernel.batch; +import java.time.temporal.ChronoUnit; import java.util.List; import msi.gama.common.interfaces.IKeyword; import msi.gama.kernel.experiment.IParameter; import msi.gama.kernel.experiment.ParametersSet; +import msi.gama.metamodel.shape.GamaPoint; import msi.gama.precompiler.GamlAnnotations.doc; import msi.gama.precompiler.GamlAnnotations.example; import msi.gama.precompiler.GamlAnnotations.facet; @@ -26,8 +28,10 @@ import msi.gama.precompiler.ISymbolKind; import msi.gama.runtime.IScope; import msi.gama.runtime.exceptions.GamaRuntimeException; +import msi.gama.util.GamaDate; import msi.gaml.descriptions.IDescription; import msi.gaml.operators.Cast; +import msi.gaml.types.GamaDateType; import msi.gaml.types.IType; @symbol ( @@ -105,22 +109,78 @@ private void testSolutions(final IScope scope, final ParametersSet sol, final in } } } else { - double varValue = Cast.asFloat(scope, var.getMinValue(scope)); - while (varValue <= Cast.asFloat(scope, var.getMaxValue(scope))) { - if (var.getType().id() == IType.INT) { - solution.put(var.getName(), (int) varValue); - } else if (var.getType().id() == IType.FLOAT) { - solution.put(var.getName(), varValue); - } else { - continue; - } - if (solution.size() == variables.size()) { - currentExperiment.launchSimulationsWithSolution(solution); - } else { - testSolutions(scope, solution, index + 1); - } - varValue = varValue + Cast.asFloat(scope, var.getStepValue(scope)); + switch (var.getType().id()) { + case IType.INT: + int intValue = Cast.asInt(scope, var.getMinValue(scope)); + int maxIntValue = Cast.asInt(scope, var.getMaxValue(scope)); + while (intValue <= maxIntValue) { + solution.put(var.getName(), intValue); + if (solution.size() == variables.size()) { + currentExperiment.launchSimulationsWithSolution(solution); + } else { + testSolutions(scope, solution, index + 1); + } + intValue = intValue + Cast.asInt(scope, var.getStepValue(scope)); + } + break; + case IType.FLOAT: + double floatValue = Cast.asFloat(scope, var.getMinValue(scope)); + double maxFloatValue = Cast.asFloat(scope, var.getMaxValue(scope)); + while (floatValue <= maxFloatValue) { + solution.put(var.getName(), floatValue); + if (solution.size() == variables.size()) { + currentExperiment.launchSimulationsWithSolution(solution); + } else { + testSolutions(scope, solution, index + 1); + } + floatValue = floatValue + Cast.asFloat(scope, var.getStepValue(scope)); + } + break; + case IType.DATE: + GamaDate dateValue = GamaDateType.staticCast(scope, var.getMinValue(scope), null, false); + GamaDate maxDateValue = GamaDateType.staticCast(scope, var.getMaxValue(scope), null, false); + while (dateValue.isSmallerThan(maxDateValue, false)) { + solution.put(var.getName(), dateValue); + if (solution.size() == variables.size()) { + currentExperiment.launchSimulationsWithSolution(solution); + } else { + testSolutions(scope, solution, index + 1); + } + dateValue = dateValue.plus(Cast.asFloat(scope, var.getStepValue(scope)), ChronoUnit.SECONDS); + } + break; + case IType.POINT: + GamaPoint pointValue = Cast.asPoint(scope, var.getMinValue(scope)); + GamaPoint maxPointValue = Cast.asPoint(scope, var.getMaxValue(scope)); + while (pointValue.smallerThanOrEqualTo(maxPointValue)) { + solution.put(var.getName(), pointValue); + if (solution.size() == variables.size()) { + currentExperiment.launchSimulationsWithSolution(solution); + } else { + testSolutions(scope, solution, index + 1); + } + pointValue = pointValue.plus(Cast.asPoint(scope, var.getStepValue(scope))); + } + break; + default: + double varValue = Cast.asFloat(scope, var.getMinValue(scope)); + while (varValue <= Cast.asFloat(scope, var.getMaxValue(scope))) { + if (var.getType().id() == IType.INT) { + solution.put(var.getName(), (int) varValue); + } else if (var.getType().id() == IType.FLOAT) { + solution.put(var.getName(), varValue); + } else { + continue; + } + if (solution.size() == variables.size()) { + currentExperiment.launchSimulationsWithSolution(solution); + } else { + testSolutions(scope, solution, index + 1); + } + varValue = varValue + Cast.asFloat(scope, var.getStepValue(scope)); + } } + } } diff --git a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentParameter.java b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentParameter.java index 99afb8c6d0..03896f1a36 100644 --- a/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentParameter.java +++ b/msi.gama.core/src/msi/gama/kernel/experiment/ExperimentParameter.java @@ -10,6 +10,9 @@ ********************************************************************************************************/ package msi.gama.kernel.experiment; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -18,6 +21,7 @@ import msi.gama.common.interfaces.IKeyword; import msi.gama.common.util.StringUtils; +import msi.gama.metamodel.shape.GamaPoint; import msi.gama.precompiler.GamlAnnotations.doc; import msi.gama.precompiler.GamlAnnotations.example; import msi.gama.precompiler.GamlAnnotations.facet; @@ -32,6 +36,8 @@ import msi.gama.runtime.exceptions.GamaRuntimeException; import msi.gama.util.Collector; import msi.gama.util.GamaColor; +import msi.gama.util.GamaDate; +import msi.gama.util.GamaDateInterval; import msi.gaml.compilation.ISymbol; import msi.gaml.compilation.Symbol; import msi.gaml.compilation.annotations.validator; @@ -44,9 +50,11 @@ import msi.gaml.expressions.IExpression; import msi.gaml.factories.DescriptionFactory; import msi.gaml.operators.Cast; +import msi.gaml.operators.Dates; import msi.gaml.statements.ActionStatement; import msi.gaml.statements.IExecutable; import msi.gaml.statements.IStatement; +import msi.gaml.types.GamaDateType; import msi.gaml.types.IType; import msi.gaml.types.Types; import msi.gaml.variables.IVariable; @@ -408,7 +416,8 @@ public void setValue(final IScope scope, final Object val) { getAmongValue(scope); if (amongValue != null) { value = amongValue.get(scope.getRandom().between(0, amongValue.size() - 1)); - } else if (type.id() == IType.INT || type.id() == IType.FLOAT) { + } else if (type.id() == IType.INT || type.id() == IType.FLOAT || type.id() == IType.POINT + || type.id() == IType.DATE) { value = drawRandomValue(scope); } else if (type.id() == IType.BOOL) { value = scope.getRandom().between(1, 100) > 50; @@ -431,17 +440,38 @@ public void tryToInit(final IScope scope) { } - // AD TODO Will not work with points and dates for the moment private Comparable drawRandomValue(final IScope scope) { - final double theStep = stepValue == null ? 1.0 : Cast.asFloat(scope, stepValue); - if (type.id() == IType.INT) { - final int theMin = minValue == null ? Integer.MIN_VALUE : Cast.asInt(scope, minValue); - final int theMax = maxValue == null ? Integer.MAX_VALUE : Cast.asInt(scope, maxValue); - return scope.getRandom().between(theMin, theMax, (int) theStep); + switch (type.id()) { + case IType.INT: + final int iMin = minValue == null ? Integer.MIN_VALUE : Cast.asInt(scope, minValue); + final int iMax = maxValue == null ? Integer.MAX_VALUE : Cast.asInt(scope, maxValue); + final int iStep = stepValue == null ? 1 : Cast.asInt(scope, stepValue); + return scope.getRandom().between(iMin, iMax, iStep); + case IType.POINT: + final GamaPoint pStep = stepValue == null ? new GamaPoint(1, 1, 1) : Cast.asPoint(scope, stepValue); + final GamaPoint pMin = + minValue == null ? new GamaPoint(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE) + : Cast.asPoint(scope, minValue); + final GamaPoint pMax = + maxValue == null ? new GamaPoint(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE) + : Cast.asPoint(scope, maxValue); + return scope.getRandom().between(pMin, pMax, pStep); + case IType.DATE: + final double dStep = + stepValue == null ? Dates.DATES_TIME_STEP.getValue() : Cast.asFloat(scope, stepValue); + final GamaDate dMin = + minValue == null ? GamaDate.of(LocalDateTime.now()).minus(Integer.MAX_VALUE, ChronoUnit.SECONDS) + : GamaDateType.staticCast(scope, minValue, null, false); + final GamaDate dMax = + maxValue == null ? GamaDate.of(LocalDateTime.now()).plus(Integer.MAX_VALUE, ChronoUnit.SECONDS) + : GamaDateType.staticCast(scope, maxValue, null, false); + return new GamaDateInterval(dMin, dMax, Duration.of((long) dStep, ChronoUnit.SECONDS)).anyValue(scope); + default: + final double fStep = stepValue == null ? 1.0 : Cast.asFloat(scope, stepValue); + final double fMin = minValue == null ? Double.MIN_VALUE : Cast.asFloat(scope, minValue); + final double fMax = maxValue == null ? Double.MAX_VALUE : Cast.asFloat(scope, maxValue); + return scope.getRandom().between(fMin, fMax, fStep); } - final double theMin = minValue == null ? Double.MIN_VALUE : Cast.asFloat(scope, minValue); - final double theMax = maxValue == null ? Double.MAX_VALUE : Cast.asFloat(scope, maxValue); - return scope.getRandom().between(theMin, theMax, theStep); } @Override @@ -457,29 +487,82 @@ public Set neighborValues(final IScope scope) throws GamaRuntimeExceptio } return neighborValues.items(); } - final double theStep = stepValue == null ? 1.0 : Cast.asFloat(scope, stepValue); - if (type.id() == IType.INT) { - final int theMin = minValue == null ? Integer.MIN_VALUE : Cast.asInt(scope, minValue); - final int theMax = maxValue == null ? Integer.MAX_VALUE : Cast.asInt(scope, maxValue); - final int val = Cast.asInt(scope, value(scope)); - if (val >= theMin + (int) theStep) { neighborValues.add(val - (int) theStep); } - if (val <= theMax - (int) theStep) { neighborValues.add(val + (int) theStep); } - } else if (type.id() == IType.FLOAT) { - final double theMin = minValue == null ? Double.MIN_VALUE : Cast.asFloat(scope, minValue); - final double theMax = maxValue == null ? Double.MAX_VALUE : Cast.asFloat(scope, maxValue); - final double removeZ = Math.max(100000.0, 1.0 / theStep); - final double val = Cast.asFloat(null, value(scope)); - if (val >= theMin + theStep) { - final double valLow = Math.round((val - theStep) * removeZ) / removeZ; - neighborValues.add(valLow); - } - if (val <= theMax - theStep) { - final double valHigh = Math.round((val + theStep) * removeZ) / removeZ; - neighborValues.add(valHigh); - } + switch (type.id()) { + case IType.INT: + final int iMin = minValue == null ? Integer.MIN_VALUE : Cast.asInt(scope, minValue); + final int iMax = maxValue == null ? Integer.MAX_VALUE : Cast.asInt(scope, maxValue); + final int iStep = stepValue == null ? 1 : Cast.asInt(scope, stepValue); + final int iVal = Cast.asInt(scope, value(scope)); + if (iVal >= iMin + iStep) { neighborValues.add(iVal - iStep); } + if (iVal <= iMax - iStep) { neighborValues.add(iVal + iStep); } + break; + case IType.POINT: + final GamaPoint pStep = stepValue == null ? new GamaPoint(1, 1, 1) : Cast.asPoint(scope, stepValue); + final GamaPoint pMin = + minValue == null ? new GamaPoint(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE) + : Cast.asPoint(scope, minValue); + final GamaPoint pMax = + maxValue == null ? new GamaPoint(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE) + : Cast.asPoint(scope, maxValue); + final GamaPoint pVal = Cast.asPoint(scope, value(scope)); + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + for (int k = -1; k <= 1; k++) { + if (i == 0 && j == 0 && k == 0) { continue; } + double x = pVal.x + i * pStep.x; + double y = pVal.y + j * pStep.y; + double z = pVal.z + k * pStep.z; + int reset = 0; + if (x < pMin.x || x > pMax.x) { + x = pVal.x; + reset++; + } + if (y < pMin.y || y > pMax.y) { + y = pVal.y; + reset++; + } + if (z < pMin.z || z > pMax.z) { + z = pVal.z; + reset++; + } + if (reset < 3) { neighborValues.add(new GamaPoint(x, y, z)); } + } + } + } + break; + case IType.DATE: + final double dStep = + stepValue == null ? Dates.DATES_TIME_STEP.getValue() : Cast.asFloat(scope, stepValue); + final GamaDate dMin = minValue == null + ? GamaDate.of(LocalDateTime.now()).minus(Integer.MAX_VALUE, ChronoUnit.SECONDS) + : GamaDateType.staticCast(scope, minValue, null, false); + final GamaDate dMax = maxValue == null + ? GamaDate.of(LocalDateTime.now()).plus(Integer.MAX_VALUE, ChronoUnit.SECONDS) + : GamaDateType.staticCast(scope, maxValue, null, false); + Duration dd = Duration.of((long) dStep, ChronoUnit.SECONDS); + final GamaDate dVal = GamaDateType.staticCast(scope, value(scope), null, false); + if (dVal.isGreaterThan(dMin.plus(dd), false)) { neighborValues.add(dVal.minus(dd)); } + if (dVal.isSmallerThan(dMax.minus(dd), false)) { neighborValues.add(dVal.plus(dd)); } + break; + default: + final double fStep = stepValue == null ? 1.0 : Cast.asFloat(scope, stepValue); + final double fMin = minValue == null ? Double.MIN_VALUE : Cast.asFloat(scope, minValue); + final double fMax = maxValue == null ? Double.MAX_VALUE : Cast.asFloat(scope, maxValue); + final double fVal = Cast.asFloat(scope, value(scope)); + final double removeZ = Math.max(100000.0, 1.0 / fStep); + if (fVal >= fMin + fStep) { + final double valLow = Math.round((fVal - fStep) * removeZ) / removeZ; + neighborValues.add(valLow); + } + if (fVal <= fMax - fStep) { + final double valHigh = Math.round((fVal + fStep) * removeZ) / removeZ; + neighborValues.add(valHigh); + } } + return neighborValues.items(); } + } @Override diff --git a/msi.gama.core/src/msi/gama/metamodel/shape/GamaPoint.java b/msi.gama.core/src/msi/gama/metamodel/shape/GamaPoint.java index a33b95764e..4afc58f217 100644 --- a/msi.gama.core/src/msi/gama/metamodel/shape/GamaPoint.java +++ b/msi.gama.core/src/msi/gama/metamodel/shape/GamaPoint.java @@ -86,10 +86,18 @@ public boolean smallerThan(final GamaPoint other) { return x < other.x || y < other.y || z < other.z; } + public boolean smallerThanOrEqualTo(final GamaPoint other) { + return x <= other.x || y <= other.y || z <= other.z; + } + public boolean biggerThan(final GamaPoint other) { return x > other.x || y > other.y || z > other.z; } + public boolean biggerThanOrEqualTo(final GamaPoint other) { + return x >= other.x || y >= other.y || z >= other.z; + } + @Override public GamaPoint setLocation(final GamaPoint al) { if (al == this) return this; @@ -310,18 +318,19 @@ public boolean intersects(final IShape g) { if (g.isPoint()) return this.equals(g.getLocation()); return g.intersects(this); } - + + @Override public boolean touches(final IShape g) { if (g.isPoint()) return false; return g.touches(this); } - + + @Override public boolean partiallyOverlaps(final IShape g) { if (g.isPoint()) return false; return g.partiallyOverlaps(this); } - @Override public boolean crosses(final IShape g) { if (g.isPoint()) return false; @@ -633,7 +642,8 @@ public GamaPoint orthogonal() { if (Math.abs(x) <= threshold) { final double inverse = 1 / sqrt(y * y + z * z); return new GamaPoint(0, inverse * z, -inverse * y); - } else if (Math.abs(y) <= threshold) { + } + if (Math.abs(y) <= threshold) { final double inverse = 1 / sqrt(x * x + z * z); return new GamaPoint(-inverse * z, 0, inverse * x); } diff --git a/msi.gama.core/src/msi/gaml/variables/NumberVariable.java b/msi.gama.core/src/msi/gaml/variables/NumberVariable.java index 38458e4870..a92c889a8f 100644 --- a/msi.gama.core/src/msi/gaml/variables/NumberVariable.java +++ b/msi.gama.core/src/msi/gaml/variables/NumberVariable.java @@ -117,11 +117,12 @@ @inside ( kinds = { ISymbolKind.SPECIES, ISymbolKind.EXPERIMENT, ISymbolKind.MODEL }) @doc ("Allows to declare an attribute of a species or experiment") -public class NumberVariable extends Variable { +public class NumberVariable extends Variable { /** The max. */ private final IExpression min, max, step; - private T minVal, maxVal, stepVal; + private T minVal, maxVal; + private Step stepVal; @SuppressWarnings ("unchecked") public NumberVariable(final IDescription sd) throws GamaRuntimeException { @@ -168,16 +169,17 @@ public NumberVariable(final IDescription sd) throws GamaRuntimeException { if (step != null && step.isConst()) { switch (type.id()) { case IType.INT: - stepVal = (T) Cast.asInt(scope, step.value(scope)); + stepVal = (Step) Cast.asInt(scope, step.value(scope)); break; case IType.FLOAT: - stepVal = (T) Cast.asFloat(scope, step.value(scope)); + stepVal = (Step) Cast.asFloat(scope, step.value(scope)); break; case IType.POINT: - stepVal = (T) Cast.asPoint(scope, step.value(scope)); + stepVal = (Step) Cast.asPoint(scope, step.value(scope)); break; case IType.DATE: - stepVal = (T) GamaDateType.staticCast(scope, step.value(scope), null, false); + // Step for dates are durations expressed in seconds ? + stepVal = (Step) Cast.asFloat(scope, step.value(scope)); } } else { stepVal = null; @@ -273,7 +275,7 @@ public T getMaxValue(final IScope scope) { } @Override - public T getStepValue(final IScope scope) { + public Step getStepValue(final IScope scope) { return stepVal; }