diff --git a/AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java b/AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java new file mode 100644 index 0000000000000000000000000000000000000000..9c8516fc5e7f2498595d93f696224beef571804b --- /dev/null +++ b/AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java @@ -0,0 +1,111 @@ +package agents; + +import agents.percept.Percept; +import fr.irit.smac.amak.Agent; +import fr.irit.smac.amak.tools.Loggable; +import gui.RenderStrategy; +import gui.RenderStrategyMutlUI; +import kernel.AMOEBA; +import kernel.World; + +/** + * The base class for all AMOEBA agents + */ +public abstract class AmoebaAgentMultiUI extends Agent<AMOEBA, World> implements Loggable { + // Attributes + protected String name; + private boolean dying; + + protected RenderStrategyMutlUI renderStrategy; + + /** + * Instantiate a new agent attached to an amoeba + * @param the amoeba + */ + public AmoebaAgentMultiUI(AMOEBA amas, Object... params) { + super(amas, params); + this.dying = false; + } + + @Override + protected void onReady() { + super.onReady(); + logger().debug("CYCLE "+getAmas().getCycle(), "Agent %s ready.", toString()); + } + + @Override + protected void onDecide() { + } + + @Override + protected void onRenderingInitialization() { + if(renderStrategy != null) { + renderStrategy.initialize(getAmas().getVUIMulti()); + + } + } + + @Override + public void onUpdateRender() { + amas.getEnvironment().incrementNbActivatedAgent(); + if(renderStrategy != null && !isDying()) { + if (amas.isRenderUpdate()) { + renderStrategy.render(); + } + } + } + + /** + * Set the name of the agent. Useful for visualization, and essential for {@link Percept}. + * @param name + */ + public void setName(String name) { + this.name = name; + } + + @Override + public void destroy() { + dying = true; + if(renderStrategy != null) { + renderStrategy.delete(); + } + super.destroy(); + logger().debug("CYCLE "+getAmas().getCycle(), "Agent %s destroyed.", toString()); + } + + /** + * Get the name of the agent. Useful for visualization, and essential for {@link Percept}. + * @param name + */ + public String getName() { + return name; + } + + /** + * Tell if the agent is dying. A dying agent no longer perform any useful action, but is not yet removed from its system. + * @return + */ + public boolean isDying() { + return dying; + } + + /** + * Set the render strategy of an agent.<br/> + * {@link RenderStrategy#delete()} the old one, and {@link RenderStrategy#initialize()} the new one. + * @param renderStrategy + * @see RenderStrategy + */ + public void setRenderStrategy(RenderStrategyMutlUI renderStrategy) { + if(this.renderStrategy != null) this.renderStrategy.delete(); + this.renderStrategy = renderStrategy; + if(this.renderStrategy != null) this.renderStrategy.initialize(getAmas().getVUIMulti()); + } + + /** + * Get the render strategy of an agent. + * @return + */ + public RenderStrategyMutlUI getRenderStrategy() { + return renderStrategy; + } +} diff --git a/AMOEBAonAMAK/src/gui/ContextRendererFX.java b/AMOEBAonAMAK/src/gui/ContextRendererFX.java index cd4843863eeedd8f763e1103d6246ff541d681f2..6faa371735858022078971e7ade26c9ab8b06417 100644 --- a/AMOEBAonAMAK/src/gui/ContextRendererFX.java +++ b/AMOEBAonAMAK/src/gui/ContextRendererFX.java @@ -2,7 +2,6 @@ package gui; import agents.context.Context; import agents.percept.Percept; -import fr.irit.smac.amak.ui.VUIMulti; import fr.irit.smac.amak.ui.drawables.DrawableRectangle; import gui.utils.ContextColor; import javafx.scene.paint.Color; @@ -65,8 +64,8 @@ public class ContextRendererFX extends RenderStrategy { * window. */ @Override - public void initialize(VUIMulti vui) { - getDrawable(vui).setName(context.toString()); // create the drawable if it does not exist + public void initialize() { + getDrawable().setName(context.toString()); // create the drawable if it does not exist } @@ -82,11 +81,11 @@ public class ContextRendererFX extends RenderStrategy { * * @return */ - public DrawableRectangle getDrawable(VUIMulti vui) { + public DrawableRectangle getDrawable() { if (!context.isDying() && drawable == null) { drawable = new DrawableContext(0, 0, 0, 0, context); - vui.add(drawable); + AmoebaWindow.instance().mainVUI.add(drawable); } return drawable; } -} +} \ No newline at end of file diff --git a/AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java b/AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java new file mode 100644 index 0000000000000000000000000000000000000000..29cbd994b65bffddf40360a4894a190b03732c8f --- /dev/null +++ b/AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java @@ -0,0 +1,92 @@ +package gui; + +import agents.context.Context; +import agents.percept.Percept; +import fr.irit.smac.amak.ui.VUIMulti; +import fr.irit.smac.amak.ui.drawables.DrawableRectangle; +import gui.utils.ContextColor; +import javafx.scene.paint.Color; + +/** + * A render strategy for contexts using AMAKFX tools.<br/> + * A Context is represented by a {@link DrawableRectangle} drawn onto {@link AmoebaWindow#mainVUI}. + * + * @author Hugo + * + */ +public class ContextRendererFXMultiUI extends RenderStrategyMutlUI { + + private Context context; + + private DrawableContext drawable; + + public ContextRendererFXMultiUI(Object o) { + this((Context) o); + } + + /** + * @param context the context to be rendered. + */ + public ContextRendererFXMultiUI(Context context) { + super(context); + this.context = context; + } + + @Override + public void render() { + updatePosition(); + updateColor(); + drawable.setName(context.toString()); + drawable.setInfo(context.toStringFull()); + } + + private void updateColor() { + Double[] c = ContextColor.colorFromCoefs(context.getFunction().getCoef()); + drawable.setColor(new Color(c[0], c[1], c[2], 90d / 255d)); + } + + public String getColorForUnity() { + Double[] c = ContextColor.colorFromCoefs(context.getFunction().getCoef()); + return c[0].intValue() + "," + c[1].intValue() + "," + c[2].intValue() + ",100"; + } + + private void updatePosition() { + Percept p1 = context.getAmas().getDimensionSelector().d1(); + Percept p2 = context.getAmas().getDimensionSelector().d2(); + double x = context.getRanges().get(p1).getStart(); + double y = context.getRanges().get(p2).getStart(); + drawable.setWidth(context.getRanges().get(p1).getLenght()); + drawable.setHeight(context.getRanges().get(p2).getLenght()); + drawable.move(x, y); + } + + /** + * Initialize the drawable. + * window. + */ + @Override + public void initialize(VUIMulti vui) { + getDrawable(vui).setName(context.toString()); // create the drawable if it does not exist + + } + + @Override + public void delete() { + if (drawable != null) + drawable.delete(); + } + + + /** + * Return the visualization for the VUI, may create and add it to the VUI. + * + * @return + */ + public DrawableRectangle getDrawable(VUIMulti vui) { + if (!context.isDying() && drawable == null) { + drawable = new DrawableContext(0, 0, 0, 0, context); + vui.add(drawable); + } + return drawable; + } +} diff --git a/AMOEBAonAMAK/src/gui/NoneRenderer.java b/AMOEBAonAMAK/src/gui/NoneRenderer.java index 438a9809fe1a6c41d54ca611719fdcd80e2e25b7..e78259ddbec1c8b175decafec737e34833b52a58 100644 --- a/AMOEBAonAMAK/src/gui/NoneRenderer.java +++ b/AMOEBAonAMAK/src/gui/NoneRenderer.java @@ -14,7 +14,7 @@ public class NoneRenderer extends RenderStrategy { } @Override - public void initialize(VUIMulti vui) { + public void initialize() { } @Override diff --git a/AMOEBAonAMAK/src/gui/RenderStrategy.java b/AMOEBAonAMAK/src/gui/RenderStrategy.java index 7552c9518486d3050b687bb8f78114e2d274e774..8cb1dd9df1b8e85c7164536223f397f374764ff9 100644 --- a/AMOEBAonAMAK/src/gui/RenderStrategy.java +++ b/AMOEBAonAMAK/src/gui/RenderStrategy.java @@ -18,8 +18,7 @@ public abstract class RenderStrategy { /** * Called when the rendered object need to be initialized */ - //abstract public void initialize(); - abstract public void initialize(VUIMulti vui); + abstract public void initialize(); /** * Called to render the object. diff --git a/AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java b/AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java new file mode 100644 index 0000000000000000000000000000000000000000..1d7bd9e351179a32465847b85ee944ea5a4ed82a --- /dev/null +++ b/AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java @@ -0,0 +1,34 @@ +package gui; + +import fr.irit.smac.amak.ui.VUIMulti; + +/** + * Strategy on how to render an object. + * See {@link ContextRendererFX} for example on how to extends this class. + * @author Hugo + */ +public abstract class RenderStrategyMutlUI { + + /** + * @param o the object to be rendered + */ + public RenderStrategyMutlUI(Object o) { + } + + /** + * Called when the rendered object need to be initialized + */ + //abstract public void initialize(); + abstract public void initialize(VUIMulti vui); + + /** + * Called to render the object. + */ + abstract public void render(); + + /** + * Called when the render of the object is no longer needed. + */ + abstract public void delete(); + +} diff --git a/AMOEBAonAMAK/src/kernel/AMOEBA.java b/AMOEBAonAMAK/src/kernel/AMOEBA.java index bf1b2c6299a6ea8f207ce0eac336f62eefc8d771..70eb7ac78b61deccb63f193217b257c98ef251ba 100644 --- a/AMOEBAonAMAK/src/kernel/AMOEBA.java +++ b/AMOEBAonAMAK/src/kernel/AMOEBA.java @@ -23,8 +23,6 @@ import fr.irit.smac.amak.Scheduling; import fr.irit.smac.amak.tools.Log; import fr.irit.smac.amak.tools.RunLaterHelper; import fr.irit.smac.amak.ui.AmakPlot; -import fr.irit.smac.amak.ui.VUIMulti; -import gui.AmoebaMultiUIWindow; import gui.AmoebaWindow; import gui.DimensionSelector; import kernel.backup.IBackupSystem; @@ -40,9 +38,6 @@ import utils.PrintOnce; */ public class AMOEBA extends Amas<World> implements IAMOEBA { // -- Attributes - - - public VUIMulti vuiMulti; /** * Utility to save, autosave, and load amoebas. */ @@ -53,8 +48,6 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { */ public StudiedSystem studiedSystem; - public AmoebaMultiUIWindow multiUIWindow; - private Head head; private TypeLocalModel localModel = TypeLocalModel.MILLER_REGRESSION; private HashMap<String, Double> perceptions = new HashMap<String, Double>(); @@ -89,9 +82,8 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { * @param studiedSystem * the studied system */ - public AMOEBA(AmoebaMultiUIWindow window, VUIMulti vui) { - super(window, vui, new World(), Scheduling.HIDDEN); - vuiMulti = vui; + public AMOEBA() { + super(new World(), Scheduling.HIDDEN); } /** @@ -99,9 +91,8 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { * * @param path path to the config file. */ - public AMOEBA(AmoebaMultiUIWindow window, VUIMulti vui, String path, StudiedSystem studiedSystem) { - super(window, vui, new World(), Scheduling.HIDDEN); - vuiMulti = vui; + public AMOEBA(String path, StudiedSystem studiedSystem) { + super(new World(), Scheduling.HIDDEN); this.studiedSystem = studiedSystem; setRenderUpdate(true); saver = new SaveHelperImpl(this); @@ -121,22 +112,23 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { @Override protected void onRenderingInitialization() { - ((AmoebaMultiUIWindow) amasMultiUIWindow).initialize(this); + AmoebaWindow.instance().initialize(this); } @Override protected void onUpdateRender() { // Update statistics - if(amasMultiUIWindow!=null) { - - AmakPlot loopNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("This loop NCS"); - AmakPlot allNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("All time NCS"); - AmakPlot nbAgent = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Number of agents"); - AmakPlot errors = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Errors"); - AmakPlot distancesToModels = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Distances to models"); - AmakPlot gloabalMappingCriticality = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Global Mapping Criticality"); - AmakPlot timeExecution = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Time Execution"); - AmakPlot criticalities = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Criticalities"); + if(AmoebaWindow.isInstance()) { + AmoebaWindow window = AmoebaWindow.instance(); + + AmakPlot loopNCS = window.getPlot("This loop NCS"); + AmakPlot allNCS = window.getPlot("All time NCS"); + AmakPlot nbAgent = window.getPlot("Number of agents"); + AmakPlot errors = window.getPlot("Errors"); + AmakPlot distancesToModels = window.getPlot("Distances to models"); + AmakPlot gloabalMappingCriticality = window.getPlot("Global Mapping Criticality"); + AmakPlot timeExecution = window.getPlot("Time Execution"); + AmakPlot criticalities = window.getPlot("Criticalities"); boolean notify = isRenderUpdate(); @@ -182,7 +174,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { } if (isRenderUpdate()) { - ((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas(); + AmoebaWindow.instance().mainVUI.updateCanvas(); updateAgentsVisualisation(); RunLaterHelper.runLater(() -> {resetCycleWithoutRender();}); } @@ -462,7 +454,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { */ public void allowGraphicalScheduler(boolean allow) { if (!Configuration.commandLineMode) { - ((AmoebaMultiUIWindow)amasMultiUIWindow).schedulerToolbar.setDisable(!allow); + AmoebaWindow.instance().schedulerToolbar.setDisable(!allow); } } @@ -484,7 +476,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { super.addPendingAgents(); nextCycleRunAllAgents(); if(!Configuration.commandLineMode) { - ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.update(getPercepts()); + AmoebaWindow.instance().dimensionSelector.update(getPercepts()); updateAgentsVisualisation(); } } @@ -512,7 +504,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { public void setRenderUpdate(boolean renderUpdate) { if (!Configuration.commandLineMode) { this.renderUpdate = renderUpdate; - ((AmoebaMultiUIWindow)amasMultiUIWindow).toggleRender.setSelected(renderUpdate); + AmoebaWindow.instance().toggleRender.setSelected(renderUpdate); if(renderUpdate == true) nextCycleRunAllAgents(); } @@ -603,13 +595,13 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { for(Agent<? extends Amas<World>, World> a : getAgents()) { a.onUpdateRender(); } - ((AmoebaMultiUIWindow)amasMultiUIWindow).point.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue(), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue()); - ((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setHeight(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2())); - ((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setWidth(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1())); - ((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1()), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2())); - ((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas(); - ((AmoebaMultiUIWindow)amasMultiUIWindow).point.toFront(); - ((AmoebaMultiUIWindow)amasMultiUIWindow).point.setInfo(getCursorInfo()); + AmoebaWindow.instance().point.move(AmoebaWindow.instance().dimensionSelector.d1().getValue(), AmoebaWindow.instance().dimensionSelector.d2().getValue()); + AmoebaWindow.instance().rectangle.setHeight(2*getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d2())); + AmoebaWindow.instance().rectangle.setWidth(2*getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d1())); + AmoebaWindow.instance().rectangle.move(AmoebaWindow.instance().dimensionSelector.d1().getValue() - getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d1()), AmoebaWindow.instance().dimensionSelector.d2().getValue() - getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d2())); + AmoebaWindow.instance().mainVUI.updateCanvas(); + AmoebaWindow.instance().point.toFront(); + AmoebaWindow.instance().point.setInfo(getCursorInfo()); } /** @@ -617,7 +609,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { * @return */ public DimensionSelector getDimensionSelector() { - return ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector; + return AmoebaWindow.instance().dimensionSelector; } /** @@ -767,4 +759,4 @@ public class AMOEBA extends Amas<World> implements IAMOEBA { percepts = null; } -} +} \ No newline at end of file diff --git a/AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java b/AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java new file mode 100644 index 0000000000000000000000000000000000000000..e0a809446f18db50baf64360f146ed2cd7925846 --- /dev/null +++ b/AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java @@ -0,0 +1,770 @@ +package kernel; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import agents.AmoebaAgent; +import agents.context.Context; +import agents.context.localModel.LocalModel; +import agents.context.localModel.LocalModelMillerRegression; +import agents.context.localModel.TypeLocalModel; +import agents.head.Head; +import agents.percept.Percept; +import fr.irit.smac.amak.Agent; +import fr.irit.smac.amak.Amas; +import fr.irit.smac.amak.Configuration; +import fr.irit.smac.amak.Scheduling; +import fr.irit.smac.amak.tools.Log; +import fr.irit.smac.amak.tools.RunLaterHelper; +import fr.irit.smac.amak.ui.AmakPlot; +import fr.irit.smac.amak.ui.VUIMulti; +import gui.AmoebaMultiUIWindow; +import gui.AmoebaWindow; +import gui.DimensionSelector; +import kernel.backup.IBackupSystem; +import kernel.backup.ISaveHelper; +import kernel.backup.SaveHelperDummy; +import kernel.backup.SaveHelperImpl; +import ncs.NCS; +import utils.PrintOnce; + +/** + * The AMOEBA amas + * + */ +public class AMOEBAMultiUI extends Amas<World> implements IAMOEBA { + // -- Attributes + + + public VUIMulti vuiMulti; + /** + * Utility to save, autosave, and load amoebas. + */ + public ISaveHelper saver = new SaveHelperDummy(); + + /** + * The system studied by the amoeba. + */ + public StudiedSystem studiedSystem; + + public AmoebaMultiUIWindow multiUIWindow; + + private Head head; + private TypeLocalModel localModel = TypeLocalModel.MILLER_REGRESSION; + private HashMap<String, Double> perceptions = new HashMap<String, Double>(); + private boolean useOracle = true; + + private boolean runAll = false; + private boolean creationOfNewContext = true; + private boolean renderUpdate; + + private int cycleWithoutRender = 0; + + private ArrayList<Context> spatiallyAlteredContext = new ArrayList<>(); + private ArrayList<Context> toKillContexts = new ArrayList<>(); + + private ArrayList<Context> lastModifiedContext = new ArrayList<>(); + + private ArrayList<Context> alteredContexts = new ArrayList<>(); + + private HashSet<Context> validContexts; + private ReadWriteLock validContextLock = new ReentrantReadWriteLock(); + + private HashSet<Context> neighborContexts ; + private ReadWriteLock neighborContextsLock = new ReentrantReadWriteLock(); + + public AmoebaData data; + private ArrayList<Percept> percepts; + + /** + * Instantiates a new, empty, amoeba. + * For ease of use, consider using {@link AMOEBAMultiUI#AMOEBAMultiUI(String, StudiedSystem)}. + * + * @param studiedSystem + * the studied system + */ + public AMOEBAMultiUI(AmoebaMultiUIWindow window, VUIMulti vui) { + super(window, vui, new World(), Scheduling.HIDDEN); + vuiMulti = vui; + } + + /** + * Intantiate a default amoeba from a config file. + * + * @param path path to the config file. + */ + public AMOEBAMultiUI(AmoebaMultiUIWindow window, VUIMulti vui, String path, StudiedSystem studiedSystem) { + super(window, vui, new World(), Scheduling.HIDDEN); + vuiMulti = vui; + this.studiedSystem = studiedSystem; + setRenderUpdate(true); + saver = new SaveHelperImpl(this); + saver.load(path); + } + + @Override + protected void onInitialConfiguration() { + super.onInitialConfiguration(); + if(Configuration.allowedSimultaneousAgentsExecution != 1) { + PrintOnce.print("Warning ! Multithreading is not currently sopported !\n" + + "Please use Configuration.allowedSimultaneousAgentsExecution=1"); + } + getEnvironment().setAmoeba(this); + data = new AmoebaData(); + } + + @Override + protected void onRenderingInitialization() { + ((AmoebaMultiUIWindow) amasMultiUIWindow).initialize(this); + } + + @Override + protected void onUpdateRender() { + // Update statistics + if(amasMultiUIWindow!=null) { + + AmakPlot loopNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("This loop NCS"); + AmakPlot allNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("All time NCS"); + AmakPlot nbAgent = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Number of agents"); + AmakPlot errors = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Errors"); + AmakPlot distancesToModels = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Distances to models"); + AmakPlot gloabalMappingCriticality = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Global Mapping Criticality"); + AmakPlot timeExecution = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Time Execution"); + AmakPlot criticalities = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Criticalities"); + + + boolean notify = isRenderUpdate(); + + HashMap<NCS, Integer> thisLoopNCS = environment.getThisLoopNCS(); + HashMap<NCS, Integer> allTimeNCS = environment.getAllTimeNCS(); + for (NCS ncs : NCS.values()) { + loopNCS.addData(ncs, cycle, thisLoopNCS.get(ncs), notify); + allNCS.addData(ncs, cycle, allTimeNCS.get(ncs), notify); + } + nbAgent.addData("Percepts", cycle, getPercepts().size(), notify); + nbAgent.addData("Contexts", cycle, getContexts().size(), notify); + nbAgent.addData("Activated", cycle, environment.getNbActivatedAgent(), notify); + + errors.addData("Criticality", cycle, head.getNormalizedCriticicality(), notify); + errors.addData("Mean criticality", cycle, head.getAveragePredictionCriticity(), notify); + errors.addData("Error allowed", cycle, head.getErrorAllowed(), notify); + + distancesToModels.addData("Distance to model", cycle, head.getDistanceToRegression(), notify); + distancesToModels.addData("Average distance to model", cycle, head.criticalities.getCriticalityMean("distanceToRegression"), notify); + distancesToModels.addData("Allowed distance to model", cycle, head.getDistanceToRegressionAllowed(), notify); + + gloabalMappingCriticality.addData("Current Value", cycle, head.getAverageSpatialCriticality(), notify); + gloabalMappingCriticality.addData("Zero", cycle, 0.0, notify); + + timeExecution.addData("HeadPlay", cycle, data.executionTimesSums[0], notify); + timeExecution.addData("EndogenousPlay", cycle, data.executionTimesSums[1], notify); + timeExecution.addData("ContextSelfAnalisis", cycle, data.executionTimesSums[2], notify); + timeExecution.addData("IncompetentNCS", cycle, data.executionTimesSums[3], notify); + timeExecution.addData("ConcurrenceNCS", cycle, data.executionTimesSums[4], notify); + timeExecution.addData("NewContextNCS", cycle, data.executionTimesSums[5], notify); + timeExecution.addData("OvermappingNCS", cycle, data.executionTimesSums[6], notify); + timeExecution.addData("Other", cycle, data.executionTimesSums[7], notify); + timeExecution.addData("BestContextInNeighbors", cycle, data.executionTimesSums[8], notify); + timeExecution.addData("CreateContext", cycle, data.executionTimesSums[9], notify); + timeExecution.addData("UpdateStatitics", cycle, data.executionTimesSums[10], notify); + timeExecution.addData("ChildContext", cycle, data.executionTimesSums[11], notify); + timeExecution.addData("PotentialRequest", cycle, data.executionTimesSums[12], notify); + + criticalities.addData("Prediction", cycle, data.evolutionCriticalityPrediction, notify); + criticalities.addData("Mapping", cycle, data.evolutionCriticalityMapping, notify); + criticalities.addData("Confidence", cycle, data.evolutionCriticalityConfidence, notify); + } + + if (isRenderUpdate()) { + ((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas(); + updateAgentsVisualisation(); + RunLaterHelper.runLater(() -> {resetCycleWithoutRender();}); + } + } + + @Override + protected void onSystemCycleBegin() { + if (cycle % 1000 == 0) { + Log.defaultLog.inform("AMOEBA", "Cycle " + cycle + ". Nb agents: "+getAgents().size()); + } + + if(isRenderUpdate()) { + incrementCycleWithoutRender(); + /* deactivate render update and stop simulation if UI is too far + * behind the simulation (10 cycles) + */ + if(getCycleWithoutRender() > 10) { + setRenderUpdate(false); + RunLaterHelper.runLater(()->{ + // we (sadly) have to put it inside a runlater to correctly update the slider + getScheduler().stop(); + }); + Log.defaultLog.warning("AMOEBA UI", "Rendering cannot keep up with simulation, it has been deactivated. " + + "To reactiavte it, slow down the simulation and toggle the \"Allow Rendering\" button."); + } + } + + if (studiedSystem != null) { + + studiedSystem.playOneStep(); + + perceptions = studiedSystem.getOutput(); + + + } + + environment.preCycleActions(); + head.clearAllUseableContextLists(); + validContexts = null; + neighborContexts = null; + environment.resetNbActivatedAgent(); + spatiallyAlteredContext.clear(); + toKillContexts.clear(); + lastModifiedContext.clear(); + alteredContexts.clear(); + } + + synchronized private void incrementCycleWithoutRender() { + cycleWithoutRender += 1; + } + + synchronized private void resetCycleWithoutRender() { + cycleWithoutRender = 0; + } + + synchronized private int getCycleWithoutRender() { + return cycleWithoutRender; + } + + @Override + protected void onSystemCycleEnd() { + + if(studiedSystem != null) { + if(head.isActiveLearning()) { + studiedSystem.setActiveLearning(true); + studiedSystem.setSelfRequest(head.getSelfRequest()); + + } + } + + super.onSystemCycleEnd(); + if(saver != null) + saver.autosave(); + } + + /** + * Define what is done during a cycle, most importantly it launch agents. + * + * Every 1000 cycles, all Context are launched, allowing to delete themselves if + * they're too small. To change this behavior you have to modify this method. + */ + @Override + public void cycle() { + cycle++; + + onSystemCycleBegin(); + + // run percepts + List<Percept> synchronousPercepts = getPercepts().stream().filter(a -> a.isSynchronous()) + .collect(Collectors.toList()); + //Collections.sort(synchronousPercepts, new AgentOrderComparator()); + + for (Percept agent : synchronousPercepts) { + executor.execute(agent); + } + try { + perceptionPhaseSemaphore.acquire(synchronousPercepts.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + decisionAndActionPhasesSemaphore.acquire(synchronousPercepts.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // it is sometime useful to run all context agent + // especially to check if they're not too small, + // or after reactivating rendering. + if (cycle % 1000 == 0) { + runAll = true; + } + + Stream<Context> contextStream = null; + if (runAll) { + contextStream = getContexts().stream(); // update all context + runAll = false; + } else { + HashSet<Context> vcontexts = getValidContexts(); + if (vcontexts == null) { + vcontexts = new HashSet<>(); + } + contextStream = vcontexts.stream(); // or only valid ones + } + + getHeadAgent().setActivatedNeighborsContexts(new ArrayList<Context>(getNeighborContexts())); + + + // run contexts + List<Context> synchronousContexts = contextStream.filter(a -> a.isSynchronous()).collect(Collectors.toList()); + //Collections.sort(synchronousContexts, new AgentOrderComparator()); + + for (Context agent : synchronousContexts) { + executor.execute(agent); + } + try { + perceptionPhaseSemaphore.acquire(synchronousContexts.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + decisionAndActionPhasesSemaphore.acquire(synchronousContexts.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // run head + List<Head> heads = new ArrayList<>(); + heads.add(head); + List<Head> synchronousHeads = heads.stream().filter(a -> a.isSynchronous()).collect(Collectors.toList()); + //Collections.sort(synchronousHeads, new AgentOrderComparator()); + + for (Head agent : synchronousHeads) { + executor.execute(agent); + } + try { + perceptionPhaseSemaphore.acquire(synchronousHeads.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + decisionAndActionPhasesSemaphore.acquire(synchronousHeads.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + removePendingAgents(); + + addPendingAgents(); + + onSystemCycleEnd(); + + if (!Configuration.commandLineMode) { + onUpdateRender(); + + if(Configuration.waitForGUI) { + // we put an action in JavaFX rendering queue + RunLaterHelper.runLater(() -> { + renderingPhaseSemaphore.release(); + }); + // and wait for it to finish + try { + renderingPhaseSemaphore.acquire(); + } catch (InterruptedException e) { + Log.defaultLog.error("[AMAS GUI]", "Failed to wait for GUI update to finish."); + e.printStackTrace(); + } + // now the queue should be clear + } + } + + } + + @Override + public HashMap<String, Double> learn(HashMap<String, Double> perceptionsActionState) { + StudiedSystem ss = studiedSystem; + studiedSystem = null; + setPerceptionsAndActionState(perceptionsActionState); + cycle(); + studiedSystem = ss; + + return null; + } + + @Override + public double request(HashMap<String, Double> perceptionsActionState) { + boolean usingOracle = isUseOracle(); + if (usingOracle) + head.changeOracleConnection(); + StudiedSystem ss = studiedSystem; + studiedSystem = null; + setPerceptionsAndActionState(perceptionsActionState); + cycle(); + if (usingOracle) + head.changeOracleConnection(); + studiedSystem = ss; + return getAction(); + } + + @Override + public HashMap<String, Double> maximize(HashMap<String, Double> known){ + ArrayList<Percept> percepts = getPercepts(); + ArrayList<Percept> unknown = new ArrayList<>(percepts); + unknown.removeIf(p ->known.containsKey(p.getName())); + //System.out.println("known : "+known.keySet()); + //System.out.println("unknow : "+unknown); + if(unknown.isEmpty()) { + return null; + } + + //get partially activated context + ArrayList<Context> pac = new ArrayList<>(); + for(Context c : getContexts()) { + boolean good = true; + for(String p : known.keySet()) { + if(!c.getRangeByPerceptName(p).contains2(known.get(p))) { + good = false; + break; + } + } + if(good) pac.add(c); + } + + ArrayList<HashMap<String, Double>> sol = new ArrayList<>(); + for(Context c : pac) { + sol.add(c.getLocalModel().getMaxWithConstraint(known)); + } + HashMap<String, Double> max = new HashMap<>(); + + Double maxValue = Double.NEGATIVE_INFINITY; + max.put("oracle", maxValue); + //find best solution + for(HashMap<String, Double> s : sol) { + if(s.get("oracle") > maxValue) { + maxValue = s.get("oracle"); + max = s; + } + } + return max; + } + + public LocalModel buildLocalModel(Context context) { + switch (localModel) { + case MILLER_REGRESSION: + return new LocalModelMillerRegression(context); + + default: + throw new IllegalArgumentException("Unknown model " + localModel + "."); + } + } + + /** + * Activate or deactivate the graphical scheduler. Allowing or denying the user + * to change the simulation speed. + * + * @param allow + */ + public void allowGraphicalScheduler(boolean allow) { + if (!Configuration.commandLineMode) { + ((AmoebaMultiUIWindow)amasMultiUIWindow).schedulerToolbar.setDisable(!allow); + } + } + + @Override + public void clearAgents() { + List<Agent<? extends Amas<World>, World>> agents = getAgents(); + for (Agent<? extends Amas<World>, World> agent : agents) { + AmoebaAgent amoebaAgent = (AmoebaAgent) agent; + amoebaAgent.destroy(); + } + this.head = null; + super.removePendingAgents(); + } + + /** + * Called when a {@link IBackupSystem} has finished loading the amoeba. + */ + public void onLoadEnded() { + super.addPendingAgents(); + nextCycleRunAllAgents(); + if(!Configuration.commandLineMode) { + ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.update(getPercepts()); + updateAgentsVisualisation(); + } + } + + @Override + public void setCreationOfNewContext(boolean creationOfNewContext) { + this.creationOfNewContext = creationOfNewContext; + } + + @Override + public void setHead(Head head) { + this.head = head; + } + + @Override + public void setLocalModel(TypeLocalModel localModel) { + this.localModel = localModel; + } + + /** + * Activate or deactivate rendering of agents at runtime. + * + * @param renderUpdate + */ + public void setRenderUpdate(boolean renderUpdate) { + if (!Configuration.commandLineMode) { + this.renderUpdate = renderUpdate; + ((AmoebaMultiUIWindow)amasMultiUIWindow).toggleRender.setSelected(renderUpdate); + if(renderUpdate == true) + nextCycleRunAllAgents(); + } + } + + /** + * Set input used by percepts and oracle. + * + * @param perceptionsAndActions + */ + public void setPerceptionsAndActionState(HashMap<String, Double> perceptionsAndActions) { + this.perceptions = perceptionsAndActions; + } + + /** + * Get the last prediction from the system. + * + * @return + */ + public double getAction() { + return head.getAction(); + } + + public ArrayList<Context> getContexts() { + ArrayList<Context> contexts = new ArrayList<>(); + for (Agent<? extends Amas<World>, World> agent : getAgents()) { + if ((agent instanceof Context)) { + contexts.add((Context) agent); + } + } + return contexts; + } + + public ArrayList<Head> getHeads() { + ArrayList<Head> heads = new ArrayList<>(); + heads.add(head); + return heads; + } + + public ArrayList<Percept> getPercepts() { + if(percepts == null || percepts.size()==0) { + setPercepts(); + } + return percepts; + } + + /** + * Get the value for a perception + * @param key key of the perception + * @return the value of the perception + */ + public Double getPerceptions(String key) { + return this.perceptions.get(key); + } + + @Override + public boolean isCreationOfNewContext() { + return creationOfNewContext; + } + + /** + * Tell AMOEBA to run all (contexts) agent for the next cycle. + */ + public void nextCycleRunAllAgents() { + runAll = true; + } + + /** + * Is rendering activated ? + * @return + */ + public boolean isRenderUpdate() { + return (!Configuration.commandLineMode) && renderUpdate; + } + + /** + * Should AMOEBA use the oracle ? If false then AMOEBA will not learn. + * @return + */ + public boolean isUseOracle() { + return useOracle; + } + + /** + * Ask the agents to update their visualization, and update some UI element related to them. + */ + public void updateAgentsVisualisation() { + for(Agent<? extends Amas<World>, World> a : getAgents()) { + a.onUpdateRender(); + } + ((AmoebaMultiUIWindow)amasMultiUIWindow).point.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue(), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue()); + ((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setHeight(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2())); + ((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setWidth(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1())); + ((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1()), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2())); + ((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas(); + ((AmoebaMultiUIWindow)amasMultiUIWindow).point.toFront(); + ((AmoebaMultiUIWindow)amasMultiUIWindow).point.setInfo(getCursorInfo()); + } + + /** + * The tool telling which dimension to display + * @return + */ + public DimensionSelector getDimensionSelector() { + return ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector; + } + + /** + * Get the last perception. + * @return + */ + public HashMap<String, Double> getPerceptionsAndActionState() { + return perceptions; + } + + /** + * Set the studied system that will be used to learn with the internal scheduler. + * @param studiedSystem + */ + public void setStudiedSystem(StudiedSystem studiedSystem) { + this.studiedSystem = studiedSystem; + } + + public Head getHeadAgent() { + return head; + } + + public ArrayList<Context> getSpatiallyAlteredContextForUnityUI() { + return spatiallyAlteredContext; + } + + public void addSpatiallyAlteredContextForUnityUI(Context ctxt) { + if(!ctxt.isFlat()) + spatiallyAlteredContext.add(ctxt); + } + + public ArrayList<Context> getToKillContextsForUnityUI() { + return toKillContexts; + } + + public void addToKillContextForUnityUI(Context ctxt) { + toKillContexts.add(ctxt); + } + + public void addLastmodifiedContext(Context context) { + if(!lastModifiedContext.contains(context)) { + lastModifiedContext.add(context); + } + } + + public ArrayList<Context> getLastModifiedContexts(){ + return lastModifiedContext; + } + + /** + * Adds the altered context. + * + * @param context the context + */ + public void addAlteredContext(Context context) { + alteredContexts.add(context); + } + + /** + * Return the current set of valid contexts. + * + * Synchronized with a readLock. + * + * @return + */ + public HashSet<Context> getValidContexts() { + HashSet<Context> ret; + validContextLock.readLock().lock(); + if (validContexts == null) { + ret = null; + } else { + ret = new HashSet<>(validContexts); + } + validContextLock.readLock().unlock(); + return ret; + } + + /** + * Update the set of valid context. The update is done with an intersect of the + * previous and new set. + * + * Synchronized with a writeLock. + * @param validContexts new validContexts set. + */ + @SuppressWarnings("unchecked") + public void updateNeighborContexts(HashSet<Context> neighborContexts) { + neighborContextsLock.writeLock().lock(); + if (this.neighborContexts == null) { + this.neighborContexts = (HashSet<Context>) neighborContexts.clone(); + } else { + this.neighborContexts.retainAll(neighborContexts); + } + neighborContextsLock.writeLock().unlock(); + } + + public HashSet<Context> getNeighborContexts() { + HashSet<Context> ret; + neighborContextsLock.readLock().lock(); + if (neighborContexts == null) { + ret = null; + } else { + ret = new HashSet<>(neighborContexts); + } + neighborContextsLock.readLock().unlock(); + return ret; + } + + /** + * Update the set of valid context. The update is done with an intersect of the + * previous and new set. + * + * Synchronized with a writeLock. + * @param validContexts new validContexts set. + */ + @SuppressWarnings("unchecked") + public void updateValidContexts(HashSet<Context> validContexts) { + validContextLock.writeLock().lock(); + if (this.validContexts == null) { + this.validContexts = (HashSet<Context>) validContexts.clone(); + } else { + this.validContexts.retainAll(validContexts); + } + validContextLock.writeLock().unlock(); + } + + private String getCursorInfo() { + String message = ""; + for(Percept pct : getPercepts()) { + message += pct.getName() + "\t" + pct.getValue() +"\t[ " + pct.getMin() +" ; " + pct.getMax() + " ]\n" ; + } + return message; + } + + public void setPercepts() { + percepts = new ArrayList<Percept>(); + for (Agent<? extends Amas<World>, World> agent : getAgents()) { + if ((agent instanceof Percept)) { + Percept p = (Percept) agent; + if(!p.isDying()) { + percepts.add(p); + } + } + } + } + + public void addPercept(Percept pct) { + percepts = null; + } + +}