123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 |
- package classes;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.UUID;
- import classes.holonControlUnit.HolonControlUnit;
- import classes.holonControlUnit.OptimizationManager;
- import classes.holonControlUnit.StateEstimator.StateIndicator;
- import ui.controller.Control;
- import ui.model.DecoratedNetwork;
- import ui.model.IntermediateCableWithState;
- import ui.model.MinimumModel;
- import ui.model.Model;
- public class Holon {
- public String name = new String();
- private Holon parent = null;
- public ArrayList<Holon> childHolons = new ArrayList<Holon>();
- private List<HolonElement> elements = new ArrayList<HolonElement>();
- //HolonObject is the lowest representation of a holon.
- private final HolonObject holonObject;
- public final boolean isPhysical;
- public HolonControlUnit holonControlUnit;
- private String uniqueID;
- public Model model;
- private MinimumModel minModel;
- /** stores whether the part between this holon and the child is occupied by the superholon */
- private HashMap<Holon, ArrayList<Edge>> pathsToChildren;
-
- private int mergeCounter = 0, splitCounter = 0;
- private int[] stateCounter = {0, 0, 0};
-
- public Holon(String name, Model model) {
- this.name = name;
- this.holonObject = null;
- isPhysical = false;
- this.uniqueID = UUID.randomUUID().toString();
- this.model = model;
- this.holonControlUnit = new HolonControlUnit(this);
- this.minModel = new MinimumModel(new ArrayList<AbstractCanvasObject>(), new ArrayList<Edge>());
- this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
- }
-
- public Holon(HolonObject object, Model model) {
- holonObject = object;
- object.holon = this;
- name = object.getName();
- elements.addAll(object.getElements());
- for(HolonElement ele : elements) {
- ele.holon = this;
- }
- isPhysical = true;
- this.uniqueID = UUID.randomUUID().toString();
- this.model = model;
- this.holonControlUnit = new HolonControlUnit(this);
- ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
- list.add(object);
- this.minModel = new MinimumModel(list, new ArrayList<Edge>());
- this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
- }
-
-
- public void addElement(HolonElement element) {
- element.holon = this;
- elements.add(element);
- }
- public void removeElement(HolonElement element) {
- element.holon = null;
- elements.remove(element);
- }
- public int elementsCount() {
- return elements.size();
- }
-
- public void addChild(Holon child) {
- if(child.equals(this)) {
- System.err.println(this.uniqueID+" wants to merge itself");
- }
- if(!this.childHolons.contains(child)) {
- child.setParent(this);
- this.childHolons.add(child);
- }
- if(this.parent != null) {
- this.holonControlUnit.addSubHolon(child);
- }
- }
-
- public void addChildHolon(Holon child, int index) {
- if(!this.childHolons.contains(child)) {
- child.setParent(this);
- childHolons.add(index, child);
- }
- if(this.parent != null) {
- this.holonControlUnit.addSubHolon(child);
- }
- }
-
- public void removeChildHolon(Holon child) {
- child.setParent(null);
- childHolons.remove(child);
- if(this.parent == null)
- return;
- this.holonControlUnit.getHierarchyController().removeSubHolon(child.getUniqueID());
- this.pathsToChildren.remove(child);
- revalidateMinModel();
- }
-
- public void removeFromParent() {
- if(parent != null) {
- parent.removeChildHolon(this);
- }
- this.setParent(model.getStateHolon());
- }
-
-
- public int getChildCount() {
- return childHolons.size();
- }
-
- public Holon getParent() {
- return parent;
- }
-
- public void setParent(Holon parent) {
- this.parent = parent;
- if(parent != null) {
- this.holonControlUnit.getHierarchyController().setSuperHolon(parent.getUniqueID());
- }
- }
-
- public HolonObject getHolonObject() {
- return holonObject;
- }
-
-
-
- public List<Holon> getChildView(){
- return Collections.unmodifiableList(childHolons);
- }
-
- public List<HolonElement> getElementView(){
- return Collections.unmodifiableList(elements);
- }
-
- @Override
- public String toString() {
- return name;
- }
- public void reassignAllChildren(Holon other) {
- for(Holon child: this.childHolons) {
- other.merge(child, true);
- }
- childHolons.clear();
- }
-
-
- public void removeAllRefrences() {
- this.setParent(null);
- this.childHolons.clear();
- this.elements.clear();
- }
-
-
-
- public int getLayer() {
- if(this.parent == null)
- return 0;
- if(this.parent.equals(this)) {
- return 0;
- }
- return parent != null ? parent.getLayer() + 1 : 0;
- }
-
-
-
- public Holon cloneWithoutParent() {
- Holon cloned = new Holon(this.name, this.model);
- model.getHolonsByID().put(cloned.getUniqueID(), cloned);
- cloned.childHolons = this.childHolons;
- cloned.elements = this.elements;
- return cloned;
- }
-
- public boolean checkHolonArePhysicalConnected(Holon other, Control control) {
- HashMap<HolonObject, DecoratedNetwork> table = control.getSimManager().getActualDecorState().getHolonObjectNetworkTable();
- HolonObject a = tryGetAPhysicalHolon();
- HolonObject b = other.tryGetAPhysicalHolon();
- boolean aHolonIsPureAbstract = a == null || b == null;
- return aHolonIsPureAbstract || table.get(a) == table.get(b);
- }
-
- private HolonObject tryGetAPhysicalHolon() {
- if(holonObject != null) {
- return holonObject;
- }
- for(Holon holon : childHolons) {
- HolonObject object = holon.tryGetAPhysicalHolon();
- if(object != null) {
- return object;
- }
- }
- return null;
- }
-
- @Deprecated
- public void checkRepairHolarchy(HashMap<HolonObject, DecoratedNetwork> table, Holon stateHolon) {
- if(childHolons.isEmpty()) {
- return;
- }
- //To establish the invariant that all child holons are repaired
- for(Holon other : childHolons) {
- other.checkRepairHolarchy(table, stateHolon);
- }
- //Repair this Holon
- HolonObject first = tryGetAPhysicalHolon();
- if(first == null) {
- return;
- }
- List<Holon> removeList = new ArrayList<Holon>();
- for(Holon other : childHolons) {
- HolonObject otherHolonObject = other.tryGetAPhysicalHolon();
- boolean isPureAbstract = otherHolonObject == null;
- if(isPureAbstract) {
- continue;
- }
- boolean isPhysicalConnected = model.checkHolonObjectsAreConnected(this, other, 0f);
- if(!isPhysicalConnected) {
- removeList.add(other);
- }
- }
- //Remove holons
- for(Holon holon : removeList) {
- holon.split(null, true);
- }
-
- }
-
- public void addNewVirtualNeighbor(String virtualNeighbor) {
- if(!this.uniqueID.equals(virtualNeighbor)) {
- this.holonControlUnit.addNewVirtualNeighbor(virtualNeighbor);
- }
- }
-
- public String getUniqueID() {
- return uniqueID;
- }
-
- public ArrayList<HolonObject> getAllHolonObjects() {
- ArrayList<HolonObject> list = new ArrayList<HolonObject>();
- for(Holon h : this.childHolons) {
- list.addAll(h.getAllHolonObjects());
- }
- if(this.holonObject != null) {
- list.add(this.holonObject);
- }
- return list;
- }
-
- public ArrayList<AbstractCanvasObject> getAllObjects(){
- ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
-
- list.addAll(this.minModel.getHolonObjectList());
- list.addAll(this.minModel.getNodeList());
- list.addAll(this.minModel.getSwitchList());
- list.addAll(this.minModel.getUppderNodeList());
-
- return list;
- }
-
- public MinimumModel getMinimumModel() {
- return this.minModel;
- }
-
- public HashMap<Holon, ArrayList<Edge>> getPathsToChildren() {
- return pathsToChildren;
- }
- /**
- * merge this holon as a child with the holon specified by the id
- * @param id
- */
- public void merge(String id, boolean allowOccupiedPath) {
- if(id.equals("State Holon")) {
- this.split(this.model.getStateHolon(), allowOccupiedPath);
- return;
- }
- Holon h = this.model.getHolonsByID().get(id);
- if(h != null) {
- h.split(this, allowOccupiedPath);
- }
- }
-
- /**
- * merge this holon with the specified child holon
- * @param child
- */
- public void merge(Holon child, boolean allowOccupiedPath) {
- if(!this.model.getHolonsByID().containsKey(child.getUniqueID())) {
- System.err.println("could not find: "+child.getHolonObject());
- return;
- }
- if(this.childHolons.contains(child)) {
- return;
- }
- if(this.parent == null) {
- this.addChild(child);
- return;
- }
- this.mergeCounter++;
- // System.out.println(this.uniqueID+" merge with "+child.getUniqueID());
- HashMap<Float, ArrayList<Edge>> paths = this.model.getShortestPathToHolarchy(this.minModel, child.getMinimumModel());
- HashMap<Float, ArrayList<Edge>> free_paths = new HashMap<Float, ArrayList<Edge>>();
- HashMap<Float, ArrayList<Edge>> occ_paths = new HashMap<Float, ArrayList<Edge>>();
- HashMap<ArrayList<Edge>, Holon> occ_by = new HashMap<ArrayList<Edge>, Holon>();
- for(Float f : paths.keySet()) {
- ArrayList<Edge> path = paths.get(f);
- Holon holder = isPathOccupied(path);
- if(holder == null || holder.getParent() == null || holder.equals(this) || holder.equals(this.parent)) {
- //path between this holon and child holon is free
- free_paths.put(f, path);
- } else {
- //path between this holon and child holon is already occupied
- occ_paths.put(f, path);
- occ_by.put(path, holder);
- }
- }
-
- // System.out.println("free: "+free_paths+"\noccupied: "+occ_paths);
-
- if(free_paths.size() > 0) {
- //there is a free path, take it and add child directly to sub holons
- ArrayList<Edge> path = free_paths.get(getShortestPath(free_paths));
- Holon holder = this.containsPath(path, this);
- if(holder != null && !holder.equals(this)) {
- //the path already used by a child holon
- holder.merge(child, true);
- return;
- }
- this.addChild(child);
- this.addChildToMinModel(child, path);
- this.pathsToChildren.put(child, path);
- if(this.parent != null && this.parent.getParent() != null) {
- this.parent.recalculateMinModel();
- }
- return;
- }
- if(occ_paths.size() < 1) {
- System.err.println("something went wrong when looking for shortest path while merging "+this.uniqueID+" and "+child.getUniqueID());
- }
- ArrayList<ArrayList<Edge>> shortestPaths = sortPaths(occ_paths);
- //take the shortest path occupied by another holon
- ArrayList<Edge> path = shortestPaths.get(0);
- Holon holder = occ_by.get(path);
- if(holder != null && holder.getParent() != null && allowOccupiedPath) {
- // System.out.println("occupied by "+holder.getUniqueID());
- this.split(holder, true);
- this.addChild(child);
- this.addChildToMinModel(child, path);
- this.pathsToChildren.put(child, path);
- if(this.parent != null && this.parent.getParent() != null) {
- this.parent.recalculateMinModel();
- }
- }
- }
-
- /**
- * checks whether a path is occupied
- * if true returns the holon in which the path is located
- * @param path
- * @return
- */
- private Holon isPathOccupied(ArrayList<Edge> path) {
- Holon h = this.parent;
- Holon r = this;
- Holon holder = null;
- while(h != null) {
- holder = h.containsPath(path, r);
- if(holder != null) {
- //found a holon which contains the path
- return holder;
- }
- r = h;
- h = h.parent;
- }
- return null;
- }
-
- private ArrayList<ArrayList<Edge>> sortPaths(HashMap<Float, ArrayList<Edge>> paths) {
- ArrayList<ArrayList<Edge>> shortestPaths = new ArrayList<ArrayList<Edge>>();
-
- while(paths.size() > 0) {
- shortestPaths.add(paths.remove(getShortestPath(paths)));
- }
-
- return shortestPaths;
- }
-
- private Float getShortestPath(HashMap<Float, ArrayList<Edge>> paths){
- float min = Float.MAX_VALUE;
- for(Float f : paths.keySet()) {
- if(f < min) {
- min = f;
- }
- }
- return min;
- }
-
- /**
- * removes this holon from current superholon and merge with new superholon
- */
- public void split(Holon newParent, boolean allowOccupiedPath) {
- //ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
- if(this.parent == null || !this.parent.canRunIndependent(this)) {
- return;
- }
- if(this.parent.parent != null) {
- //we actually split from a super holon and not from the state holon
- this.splitCounter++;
- }
-
- if(newParent == null) {
- newParent = this.model.getStateHolon();
- allowOccupiedPath = true;
- } else {
- //next step is merge with new parent
- this.mergeCounter++;
- }
- this.parent.incSplitCounter();
- this.parent.removeChildHolon(this);
-
- this.holonControlUnit.getHierarchyController().resetVirtualNeighbors();
- newParent.merge(this, allowOccupiedPath);
- }
-
- public void splitById(String id) {
- Holon child = this.model.getHolonsByID().get(id);
- if(child.parent == this)
- child.split(null, false);
- }
-
- /**
- * recalculates the min model after a holon was added to a subholon
- * does NOT recalculate the shortest paths between its subholons
- */
- public void recalculateMinModel() {
- ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
- ArrayList<Edge> edges = new ArrayList<Edge>();
- for(Holon child : this.childHolons) {
- MinimumModel cmm = child.getMinimumModel();
- objects.addAll(cmm.getHolonObjectList());
- objects.addAll(cmm.getNodeList());
- objects.addAll(cmm.getSwitchList());
- for(IntermediateCableWithState icws : cmm.getEdgeList()) {
- edges.add(icws.getModel());
- }
- }
- //go through the edge list and add all edges connecting the subholons
- for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
- if(!edges.contains(icws.getModel())) {
- edges.add(icws.getModel());
- }
- }
- this.minModel = new MinimumModel(objects, edges);
-
- //notify superholon to recalculate its minModel
- if(this.parent != null && this.parent.getParent() != null && this.parent != this) {
- this.parent.recalculateMinModel();
- }
- }
-
- /**
- * adds a child and its min model (incl. all its subholons) to this min model
- * @param child
- */
- private void addChildToMinModel(Holon child, ArrayList<Edge> path) {
- if(this.minModel.getHolonObjectList().contains(child.getHolonObject()) || this.parent == null)
- return;
-
- ArrayList<Edge> edgeList = new ArrayList<Edge>();
- //add all holon objects that are part of this holarchy
- ArrayList<HolonObject> holarchy = getAllHolonObjects();
- holarchy.addAll(child.getAllHolonObjects());
- edgeList.addAll(path);
- for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
- edgeList.add(icws.getModel());
- }
- for(IntermediateCableWithState icws : child.minModel.getEdgeList()) {
- edgeList.add(icws.getModel());
- }
- //aggregate all objects
- ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
- for(Edge e : edgeList) {
- AbstractCanvasObject a = e.getA();
- AbstractCanvasObject b = e.getB();
- if(!objects.contains(a)) {
- objects.add(a);
- }
- if(!objects.contains(b)) {
- objects.add(b);
- }
- }
- this.minModel = new MinimumModel(objects, edgeList);
- }
-
- /**
- * revalidate this min model after a subholon was removed
- */
- public void revalidateMinModel() {
- if(this.parent == null)
- return;
- ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
- list.add(this.holonObject);
- this.minModel = new MinimumModel(list, new ArrayList<Edge>());
- for(int i=0; i< this.childHolons.size(); i++) {
- Holon child = this.childHolons.remove(0);
- if(this.model.checkHolonObjectsAreConnected(this, child, this.holonControlUnit.getStateEstimator().getNetThroughput())) {
- this.merge(child, true);
- }
- }
-
- if(this.parent != null) {
- this.parent.revalidateMinModel();
- }
- }
-
- public void revalidateMinModelAfterLoad() {
- if(this.childHolons.size() == 0) {
- this.revalidateMinModel();
- } else {
- List<Holon> list = List.copyOf(this.childHolons);
- for(Holon child : list) {
- child.revalidateMinModelAfterLoad();
- }
- }
- }
-
- /**
- * returns the holon which uses the specified path if it is included in min model, otherwise null
- */
- public Holon containsPath(ArrayList<Edge> path, Holon requester) {
- if(this.minModel.containsPath(path) || this.parent == null) {
- for(Holon child : this.childHolons) {
- if(child.equals(requester))
- continue;
- Holon h = child.containsPath(path, this);
- if(h != null) {
- return h;
- }
- }
-
- return this;
- }
- for(Edge e : path) {
- AbstractCanvasObject a = e.getA();
- AbstractCanvasObject b = e.getB();
- if(a instanceof HolonObject && this.childHolons.contains(((HolonObject) a).holon))
- return ((HolonObject) a).holon;
- if(b instanceof HolonObject && this.childHolons.contains(((HolonObject) b).holon))
- return ((HolonObject) b).holon;
- if(this.getAllObjects().contains(a) || this.getAllObjects().contains(b))
- return this;
- }
- return null;
- }
-
- /**
- * checks whether the requester can run without this holon (none of the paths inside the requesters model is occupied by this model)
- * @param requester
- * @return
- */
- public boolean canRunIndependent(Holon requester) {
- if(this.parent == null || this.parent.getParent() == null)
- return true;
-
- ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
- objects.addAll(requester.getMinimumModel().getHolonObjectList());
- objects.addAll(requester.getMinimumModel().getNodeList());
- objects.addAll(requester.getMinimumModel().getSwitchList());
-
- for(Holon child : this.childHolons) {
- if(child.equals(requester))
- continue;
- ArrayList<Edge> path = this.pathsToChildren.get(child);
- ArrayList<AbstractCanvasObject> pathObjects = new ArrayList<AbstractCanvasObject>();
- for(Edge e : path) {
- AbstractCanvasObject a = e.getA();
- AbstractCanvasObject b = e.getB();
- if(!pathObjects.contains(a))
- pathObjects.add(a);
- if(!pathObjects.contains(b))
- pathObjects.add(b);
- }
- for(AbstractCanvasObject aco : pathObjects) {
- if(objects.contains(aco))
- return false;
- }
- }
-
- return true;
- }
-
- public boolean isASuperiorHolon(String holon) {
- return this.parent != null ? (this.parent.getUniqueID().equals(holon) || this.parent.isASuperiorHolon(holon)) : false;
- }
- public int getMergeCounter() {
- return mergeCounter;
- }
- public int getSplitCounter() {
- return splitCounter;
- }
-
- public void incSplitCounter() {
- this.splitCounter++;
- }
-
- public int[] getStateCounter() {
- return this.stateCounter;
- }
-
- public void countState(float dev) {
- if(Math.abs(dev) <= 1-OptimizationManager.POWER_THRESHOLD_COMFORT) {
- this.stateCounter[0]++;
- } else if(Math.abs(dev) <= 1-OptimizationManager.POWER_THRESHOLD_STABILITY) {
- this.stateCounter[1]++;
- } else {
- this.stateCounter[2]++;
- }
- // switch (this.holonControlUnit.getStateEstimator().getStateIndicator()) {
- // case DESIRED:
- // this.stateCounter[0]++;
- // break;
- // case ENDANGERED:
- // this.stateCounter[1]++;
- // break;
- // case DYSFUNCTIONAL:
- // this.stateCounter[2]++;
- // break;
- // default:
- // throw new IllegalArgumentException("Unexpected value: " + this.holonControlUnit.getStateEstimator().getStateIndicator());
- // }
- }
- }
|