gama-platform / gama

Main repository for developing the 2024+ versions of GAMA
https://gama-platform.org
GNU General Public License v3.0
11 stars 4 forks source link

[BATCH] clean sensitivity analysis method in exploration #186

Open chapuisk opened 1 month ago

chapuisk commented 1 month ago

Sensitivity analysis methods, have been added to Gama as of 1.9.x, but have never been polished since, notably in the provided feedbacks and outputs. I list the foreseen improvement

There is also part of the improvement to further deploy SA features to every exploration methods:

Don't hesitate to add more task to upgrade SA & exploration in Gama.

lesquoyb commented 3 weeks ago

Ok so I've read your remaining spotbugs violations, and I made a more human readable summary with my point of view on how seriously you should take them:

  1. the 3 CT_CONSTRUCTOR_THROW it's up to you to fix it or not but I don't think it's important, if an exception is raised in those constructors gama will probably catch it and display it the user so there's no real risk even though it's a bit ugly
  2. the 6 WMI_WRONG_MAP_ITERATOR are just telling you that you could use entrySet to get the key and value in the same object for your loops instead of iterating on keySet and get the value with the get function. To me it doesn't matter if you fix it or not as it's not in parts of the code where optimization could be important.
  3. the 2 RV_RETURN_VALUE_IGNORED_BAD_PRACTICE are more important as they highlight that you didn't handle the case of error while creating a directory or deleting a file. I think you should probably use the GAMA.reportAndThrowIfNeeded method to stop the execution and report an error.
  4. the SBSC_USE_STRINGBUFFER_CONCATENATION indicates that you could have used the StringBuffer's append method instead of concatenated strings, which is more efficient, and particularly in a loop it could amount to good performance gains. I advise that you do it.
  5. the 3 EI_EXPOSE_REP2 you could probably ignore. It indicates that you are keeping a reference on lists/maps that could be modified from the outside. If you want to be "clean" you could probably clone those lists/maps
  6. the NP_ALWAYS_NULL is very important, it indicates that you are trying to access a method on an object that we already know is null, thus it will raise a NullPointerException. Reading the code it seems like the condition is wrong (&& instead of ||) but as you told me you never have any exception you should consider completely deleting this constructor as it's probably never called
  7. the NP_NULL_PARAM_DEREF is raised because it is (theoretically) possible to reach this code with a value of null for the variable fr which will lead to more exception. In reality it may not be reached because some exceptions are raised before, but I'm not sure. I recommend that either you explicitly use a return in the catch blocks to make sure that this code is never reach in case of exception, or you move all the code following the initialization of fr in the try block.
  8. the OS_OPEN_STREAM is raised because you open a stream but it is never explicitly closed in case of exception. I think you should also solve this one and this can be done using a try with resource. It would be something like: try (BufferedReader br = new BufferedReader(fr)){.... This construction will make sure that br is disposed (and thus closed) at the end of the block.
  9. And finally there are 3 RV_EXCEPTION_NOT_THROWN and I think those are really important as it means you have created exceptions that are not thrown. I've also recently learned about this, but GamaRuntimeException.error only creates a GamaRuntimeException object, and you still need to raise the exception for it to be seen by the user. You can do so either with throw GamaRuntimeException.create... or using the method GAMA.reportAndThrowIfNeeded. I personally use the GAMA.reportAndThrowIfNeeded syntax as I think it's the most gama way but I'm not 100% sure it's the best option every time.

To be honest I could have resolved almost all of those by myself and commited the fixes, but I think it's important to do that kind of explanation as you will probably encounter them again and I might not always be available to fix them.

lesquoyb commented 2 weeks ago

Some additional information: I found out that the compilation check that fails is actually due to unit tests, that's why when I tried your branch on my computer I didn't have any problem, but if I try to run the unit tests it is indeed broken and I can track some of the errors stacks to AExplorationAlgorithm:

java.lang.ClassCastException: class gama.core.kernel.experiment.TestAgent cannot be cast to class gama.core.kernel.simulation.SimulationAgent (gama.core.kernel.experiment.TestAgent and gama.core.kernel.simulation.SimulationAgent are in unnamed module of loader org.eclipse.osgi.internal.loader.EquinoxClassLoader @76680c63)
    at gaml.additions.core.GamlAdditions.lambda$146(GamlAdditions.java:232)
    at gama.gaml.compilation.GamaHelper.run(GamaHelper.java:75)
    at gama.gaml.compilation.IGamaHelper.run(IGamaHelper.java:51)
    at gama.gaml.variables.Variable.value(Variable.java:822)
    at gama.gaml.variables.Variable.value(Variable.java:816)
    at gama.gaml.variables.Variable.getInitialValue(Variable.java:871)
    at gama.core.kernel.experiment.ExperimentAgent$ExperimentAgentScope.getGlobalVarValue(ExperimentAgent.java:1100)
    at gama.gaml.expressions.variables.GlobalVariableExpression._value(GlobalVariableExpression.java:95)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.BinaryOperator._value(BinaryOperator.java:148)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.BinaryOperator._value(BinaryOperator.java:149)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.variables.Variable.getInitialValue(Variable.java:866)
    at gama.core.kernel.experiment.ExperimentAgent$ExperimentAgentScope.getGlobalVarValue(ExperimentAgent.java:1100)
    at gama.gaml.expressions.variables.GlobalVariableExpression._value(GlobalVariableExpression.java:95)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.UnaryOperator._value(UnaryOperator.java:97)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.BinaryOperator._value(BinaryOperator.java:148)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.BinaryOperator._value(BinaryOperator.java:148)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.BinaryOperator._value(BinaryOperator.java:149)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.expressions.operators.BinaryOperator._value(BinaryOperator.java:148)
    at gama.gaml.expressions.AbstractExpression.value(AbstractExpression.java:87)
    at gama.gaml.statements.test.AssertStatement.privateExecuteIn(AssertStatement.java:100)
    at gama.gaml.statements.AbstractStatement.executeOn(AbstractStatement.java:47)
    at gama.gaml.statements.test.TestStatement.privateExecuteIn(TestStatement.java:145)
    at gama.gaml.statements.AbstractStatement.executeOn(AbstractStatement.java:47)
    at gama.gaml.statements.AbstractStatementSequence.executeOn(AbstractStatementSequence.java:59)
    at gama.core.runtime.ExecutionScope.execute(ExecutionScope.java:510)
    at gama.core.runtime.IScope.execute(IScope.java:443)
    at gama.core.runtime.IScope.execute(IScope.java:414)
    at gama.gaml.architecture.reflex.ReflexArchitecture.executeReflexes(ReflexArchitecture.java:126)
    at gama.gaml.architecture.reflex.ReflexArchitecture.executeOn(ReflexArchitecture.java:112)
    at gama.core.runtime.ExecutionScope.execute(ExecutionScope.java:510)
    at gama.core.runtime.IScope.execute(IScope.java:443)
    at gama.core.metamodel.agent.AbstractAgent.doStep(AbstractAgent.java:269)
    at gama.core.metamodel.agent.MinimalAgent.doStep(MinimalAgent.java:260)
    at gama.core.metamodel.agent.AbstractAgent.step(AbstractAgent.java:240)
    at gama.core.kernel.experiment.BatchAgent.launchSimulationsWithSolution(BatchAgent.java:368)
    at gama.core.kernel.batch.exploration.Exploration.explore(Exploration.java:194)
    at gama.core.kernel.batch.exploration.AExplorationAlgorithm.run(AExplorationAlgorithm.java:124)
    at gama.core.kernel.experiment.BatchAgent.step(BatchAgent.java:233)
    at gama.core.kernel.experiment.TestAgent.step(TestAgent.java:93)
    at gaml.compiler.ui.utils.ModelRunner.runHeadlessTests(ModelRunner.java:114)
    at gama.ui.shared.utils.SwtGui.runHeadlessTests(SwtGui.java:391)
    at gama.ui.shared.commands.TestsRunner.lambda$0(TestsRunner.java:69)
    at org.eclipse.core.runtime.jobs.Job$2.run(Job.java:187)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)

So at least that "mystery" is solved