Holon.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. package classes;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.UUID;
  7. import classes.holonControlUnit.HolonControlUnit;
  8. import classes.holonControlUnit.OptimizationManager;
  9. import classes.holonControlUnit.StateEstimator.StateIndicator;
  10. import ui.controller.Control;
  11. import ui.model.DecoratedNetwork;
  12. import ui.model.IntermediateCableWithState;
  13. import ui.model.MinimumModel;
  14. import ui.model.Model;
  15. public class Holon {
  16. public String name = new String();
  17. private Holon parent = null;
  18. public ArrayList<Holon> childHolons = new ArrayList<Holon>();
  19. private List<HolonElement> elements = new ArrayList<HolonElement>();
  20. //HolonObject is the lowest representation of a holon.
  21. private final HolonObject holonObject;
  22. public final boolean isPhysical;
  23. public HolonControlUnit holonControlUnit;
  24. private String uniqueID;
  25. public Model model;
  26. private MinimumModel minModel;
  27. /** stores whether the part between this holon and the child is occupied by the superholon */
  28. private HashMap<Holon, ArrayList<Edge>> pathsToChildren;
  29. private int mergeCounter = 0, splitCounter = 0;
  30. private int[] stateCounter = {0, 0, 0};
  31. public Holon(String name, Model model) {
  32. this.name = name;
  33. this.holonObject = null;
  34. isPhysical = false;
  35. this.uniqueID = UUID.randomUUID().toString();
  36. this.model = model;
  37. this.holonControlUnit = new HolonControlUnit(this);
  38. this.minModel = new MinimumModel(new ArrayList<AbstractCanvasObject>(), new ArrayList<Edge>());
  39. this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
  40. }
  41. public Holon(HolonObject object, Model model) {
  42. holonObject = object;
  43. object.holon = this;
  44. name = object.getName();
  45. elements.addAll(object.getElements());
  46. for(HolonElement ele : elements) {
  47. ele.holon = this;
  48. }
  49. isPhysical = true;
  50. this.uniqueID = UUID.randomUUID().toString();
  51. this.model = model;
  52. this.holonControlUnit = new HolonControlUnit(this);
  53. ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
  54. list.add(object);
  55. this.minModel = new MinimumModel(list, new ArrayList<Edge>());
  56. this.pathsToChildren = new HashMap<Holon, ArrayList<Edge>>();
  57. }
  58. public void addElement(HolonElement element) {
  59. element.holon = this;
  60. elements.add(element);
  61. }
  62. public void removeElement(HolonElement element) {
  63. element.holon = null;
  64. elements.remove(element);
  65. }
  66. public int elementsCount() {
  67. return elements.size();
  68. }
  69. public void addChild(Holon child) {
  70. if(child.equals(this)) {
  71. System.err.println(this.uniqueID+" wants to merge itself");
  72. }
  73. if(!this.childHolons.contains(child)) {
  74. child.setParent(this);
  75. this.childHolons.add(child);
  76. }
  77. if(this.parent != null) {
  78. this.holonControlUnit.addSubHolon(child);
  79. }
  80. }
  81. public void addChildHolon(Holon child, int index) {
  82. if(!this.childHolons.contains(child)) {
  83. child.setParent(this);
  84. childHolons.add(index, child);
  85. }
  86. if(this.parent != null) {
  87. this.holonControlUnit.addSubHolon(child);
  88. }
  89. }
  90. public void removeChildHolon(Holon child) {
  91. child.setParent(null);
  92. childHolons.remove(child);
  93. if(this.parent == null)
  94. return;
  95. this.holonControlUnit.getHierarchyController().removeSubHolon(child.getUniqueID());
  96. this.pathsToChildren.remove(child);
  97. revalidateMinModel();
  98. }
  99. public void removeFromParent() {
  100. if(parent != null) {
  101. parent.removeChildHolon(this);
  102. }
  103. this.setParent(model.getStateHolon());
  104. }
  105. public int getChildCount() {
  106. return childHolons.size();
  107. }
  108. public Holon getParent() {
  109. return parent;
  110. }
  111. public void setParent(Holon parent) {
  112. this.parent = parent;
  113. if(parent != null) {
  114. this.holonControlUnit.getHierarchyController().setSuperHolon(parent.getUniqueID());
  115. }
  116. }
  117. public HolonObject getHolonObject() {
  118. return holonObject;
  119. }
  120. public List<Holon> getChildView(){
  121. return Collections.unmodifiableList(childHolons);
  122. }
  123. public List<HolonElement> getElementView(){
  124. return Collections.unmodifiableList(elements);
  125. }
  126. @Override
  127. public String toString() {
  128. return name;
  129. }
  130. public void reassignAllChildren(Holon other) {
  131. for(Holon child: this.childHolons) {
  132. other.merge(child, true);
  133. }
  134. childHolons.clear();
  135. }
  136. public void removeAllRefrences() {
  137. this.setParent(null);
  138. this.childHolons.clear();
  139. this.elements.clear();
  140. }
  141. public int getLayer() {
  142. if(this.parent == null)
  143. return 0;
  144. if(this.parent.equals(this)) {
  145. return 0;
  146. }
  147. return parent != null ? parent.getLayer() + 1 : 0;
  148. }
  149. public Holon cloneWithoutParent() {
  150. Holon cloned = new Holon(this.name, this.model);
  151. model.getHolonsByID().put(cloned.getUniqueID(), cloned);
  152. cloned.childHolons = this.childHolons;
  153. cloned.elements = this.elements;
  154. return cloned;
  155. }
  156. public boolean checkHolonArePhysicalConnected(Holon other, Control control) {
  157. HashMap<HolonObject, DecoratedNetwork> table = control.getSimManager().getActualDecorState().getHolonObjectNetworkTable();
  158. HolonObject a = tryGetAPhysicalHolon();
  159. HolonObject b = other.tryGetAPhysicalHolon();
  160. boolean aHolonIsPureAbstract = a == null || b == null;
  161. return aHolonIsPureAbstract || table.get(a) == table.get(b);
  162. }
  163. private HolonObject tryGetAPhysicalHolon() {
  164. if(holonObject != null) {
  165. return holonObject;
  166. }
  167. for(Holon holon : childHolons) {
  168. HolonObject object = holon.tryGetAPhysicalHolon();
  169. if(object != null) {
  170. return object;
  171. }
  172. }
  173. return null;
  174. }
  175. @Deprecated
  176. public void checkRepairHolarchy(HashMap<HolonObject, DecoratedNetwork> table, Holon stateHolon) {
  177. if(childHolons.isEmpty()) {
  178. return;
  179. }
  180. //To establish the invariant that all child holons are repaired
  181. for(Holon other : childHolons) {
  182. other.checkRepairHolarchy(table, stateHolon);
  183. }
  184. //Repair this Holon
  185. HolonObject first = tryGetAPhysicalHolon();
  186. if(first == null) {
  187. return;
  188. }
  189. List<Holon> removeList = new ArrayList<Holon>();
  190. for(Holon other : childHolons) {
  191. HolonObject otherHolonObject = other.tryGetAPhysicalHolon();
  192. boolean isPureAbstract = otherHolonObject == null;
  193. if(isPureAbstract) {
  194. continue;
  195. }
  196. boolean isPhysicalConnected = model.checkHolonObjectsAreConnected(this, other, 0f);
  197. if(!isPhysicalConnected) {
  198. removeList.add(other);
  199. }
  200. }
  201. //Remove holons
  202. for(Holon holon : removeList) {
  203. holon.split(null, true);
  204. }
  205. }
  206. public void addNewVirtualNeighbor(String virtualNeighbor) {
  207. if(!this.uniqueID.equals(virtualNeighbor)) {
  208. this.holonControlUnit.addNewVirtualNeighbor(virtualNeighbor);
  209. }
  210. }
  211. public String getUniqueID() {
  212. return uniqueID;
  213. }
  214. public ArrayList<HolonObject> getAllHolonObjects() {
  215. ArrayList<HolonObject> list = new ArrayList<HolonObject>();
  216. for(Holon h : this.childHolons) {
  217. list.addAll(h.getAllHolonObjects());
  218. }
  219. if(this.holonObject != null) {
  220. list.add(this.holonObject);
  221. }
  222. return list;
  223. }
  224. public ArrayList<AbstractCanvasObject> getAllObjects(){
  225. ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
  226. list.addAll(this.minModel.getHolonObjectList());
  227. list.addAll(this.minModel.getNodeList());
  228. list.addAll(this.minModel.getSwitchList());
  229. list.addAll(this.minModel.getUppderNodeList());
  230. return list;
  231. }
  232. public MinimumModel getMinimumModel() {
  233. return this.minModel;
  234. }
  235. public HashMap<Holon, ArrayList<Edge>> getPathsToChildren() {
  236. return pathsToChildren;
  237. }
  238. /**
  239. * merge this holon as a child with the holon specified by the id
  240. * @param id
  241. */
  242. public void merge(String id, boolean allowOccupiedPath) {
  243. if(id.equals("State Holon")) {
  244. this.split(this.model.getStateHolon(), allowOccupiedPath);
  245. return;
  246. }
  247. Holon h = this.model.getHolonsByID().get(id);
  248. if(h != null) {
  249. h.split(this, allowOccupiedPath);
  250. }
  251. }
  252. /**
  253. * merge this holon with the specified child holon
  254. * @param child
  255. */
  256. public void merge(Holon child, boolean allowOccupiedPath) {
  257. if(!this.model.getHolonsByID().containsKey(child.getUniqueID())) {
  258. System.err.println("could not find: "+child.getHolonObject());
  259. return;
  260. }
  261. if(this.childHolons.contains(child)) {
  262. return;
  263. }
  264. if(this.parent == null) {
  265. this.addChild(child);
  266. return;
  267. }
  268. this.mergeCounter++;
  269. // System.out.println(this.uniqueID+" merge with "+child.getUniqueID());
  270. HashMap<Float, ArrayList<Edge>> paths = this.model.getShortestPathToHolarchy(this.minModel, child.getMinimumModel());
  271. HashMap<Float, ArrayList<Edge>> free_paths = new HashMap<Float, ArrayList<Edge>>();
  272. HashMap<Float, ArrayList<Edge>> occ_paths = new HashMap<Float, ArrayList<Edge>>();
  273. HashMap<ArrayList<Edge>, Holon> occ_by = new HashMap<ArrayList<Edge>, Holon>();
  274. for(Float f : paths.keySet()) {
  275. ArrayList<Edge> path = paths.get(f);
  276. Holon holder = isPathOccupied(path);
  277. if(holder == null || holder.getParent() == null || holder.equals(this) || holder.equals(this.parent)) {
  278. //path between this holon and child holon is free
  279. free_paths.put(f, path);
  280. } else {
  281. //path between this holon and child holon is already occupied
  282. occ_paths.put(f, path);
  283. occ_by.put(path, holder);
  284. }
  285. }
  286. // System.out.println("free: "+free_paths+"\noccupied: "+occ_paths);
  287. if(free_paths.size() > 0) {
  288. //there is a free path, take it and add child directly to sub holons
  289. ArrayList<Edge> path = free_paths.get(getShortestPath(free_paths));
  290. Holon holder = this.containsPath(path, this);
  291. if(holder != null && !holder.equals(this)) {
  292. //the path already used by a child holon
  293. holder.merge(child, true);
  294. return;
  295. }
  296. this.addChild(child);
  297. this.addChildToMinModel(child, path);
  298. this.pathsToChildren.put(child, path);
  299. if(this.parent != null && this.parent.getParent() != null) {
  300. this.parent.recalculateMinModel();
  301. }
  302. return;
  303. }
  304. if(occ_paths.size() < 1) {
  305. System.err.println("something went wrong when looking for shortest path while merging "+this.uniqueID+" and "+child.getUniqueID());
  306. }
  307. ArrayList<ArrayList<Edge>> shortestPaths = sortPaths(occ_paths);
  308. //take the shortest path occupied by another holon
  309. ArrayList<Edge> path = shortestPaths.get(0);
  310. Holon holder = occ_by.get(path);
  311. if(holder != null && holder.getParent() != null && allowOccupiedPath) {
  312. // System.out.println("occupied by "+holder.getUniqueID());
  313. this.split(holder, true);
  314. this.addChild(child);
  315. this.addChildToMinModel(child, path);
  316. this.pathsToChildren.put(child, path);
  317. if(this.parent != null && this.parent.getParent() != null) {
  318. this.parent.recalculateMinModel();
  319. }
  320. }
  321. }
  322. /**
  323. * checks whether a path is occupied
  324. * if true returns the holon in which the path is located
  325. * @param path
  326. * @return
  327. */
  328. private Holon isPathOccupied(ArrayList<Edge> path) {
  329. Holon h = this.parent;
  330. Holon r = this;
  331. Holon holder = null;
  332. while(h != null) {
  333. holder = h.containsPath(path, r);
  334. if(holder != null) {
  335. //found a holon which contains the path
  336. return holder;
  337. }
  338. r = h;
  339. h = h.parent;
  340. }
  341. return null;
  342. }
  343. private ArrayList<ArrayList<Edge>> sortPaths(HashMap<Float, ArrayList<Edge>> paths) {
  344. ArrayList<ArrayList<Edge>> shortestPaths = new ArrayList<ArrayList<Edge>>();
  345. while(paths.size() > 0) {
  346. shortestPaths.add(paths.remove(getShortestPath(paths)));
  347. }
  348. return shortestPaths;
  349. }
  350. private Float getShortestPath(HashMap<Float, ArrayList<Edge>> paths){
  351. float min = Float.MAX_VALUE;
  352. for(Float f : paths.keySet()) {
  353. if(f < min) {
  354. min = f;
  355. }
  356. }
  357. return min;
  358. }
  359. /**
  360. * removes this holon from current superholon and merge with new superholon
  361. */
  362. public void split(Holon newParent, boolean allowOccupiedPath) {
  363. //ensure that this holarchy can run independent(path is not occupied by superholon) from the superholon
  364. if(this.parent == null || !this.parent.canRunIndependent(this)) {
  365. return;
  366. }
  367. if(this.parent.parent != null) {
  368. //we actually split from a super holon and not from the state holon
  369. this.splitCounter++;
  370. }
  371. if(newParent == null) {
  372. newParent = this.model.getStateHolon();
  373. allowOccupiedPath = true;
  374. } else {
  375. //next step is merge with new parent
  376. this.mergeCounter++;
  377. }
  378. this.parent.incSplitCounter();
  379. this.parent.removeChildHolon(this);
  380. this.holonControlUnit.getHierarchyController().resetVirtualNeighbors();
  381. newParent.merge(this, allowOccupiedPath);
  382. }
  383. public void splitById(String id) {
  384. Holon child = this.model.getHolonsByID().get(id);
  385. if(child.parent == this)
  386. child.split(null, false);
  387. }
  388. /**
  389. * recalculates the min model after a holon was added to a subholon
  390. * does NOT recalculate the shortest paths between its subholons
  391. */
  392. public void recalculateMinModel() {
  393. ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
  394. ArrayList<Edge> edges = new ArrayList<Edge>();
  395. for(Holon child : this.childHolons) {
  396. MinimumModel cmm = child.getMinimumModel();
  397. objects.addAll(cmm.getHolonObjectList());
  398. objects.addAll(cmm.getNodeList());
  399. objects.addAll(cmm.getSwitchList());
  400. for(IntermediateCableWithState icws : cmm.getEdgeList()) {
  401. edges.add(icws.getModel());
  402. }
  403. }
  404. //go through the edge list and add all edges connecting the subholons
  405. for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
  406. if(!edges.contains(icws.getModel())) {
  407. edges.add(icws.getModel());
  408. }
  409. }
  410. this.minModel = new MinimumModel(objects, edges);
  411. //notify superholon to recalculate its minModel
  412. if(this.parent != null && this.parent.getParent() != null && this.parent != this) {
  413. this.parent.recalculateMinModel();
  414. }
  415. }
  416. /**
  417. * adds a child and its min model (incl. all its subholons) to this min model
  418. * @param child
  419. */
  420. private void addChildToMinModel(Holon child, ArrayList<Edge> path) {
  421. if(this.minModel.getHolonObjectList().contains(child.getHolonObject()) || this.parent == null)
  422. return;
  423. ArrayList<Edge> edgeList = new ArrayList<Edge>();
  424. //add all holon objects that are part of this holarchy
  425. ArrayList<HolonObject> holarchy = getAllHolonObjects();
  426. holarchy.addAll(child.getAllHolonObjects());
  427. edgeList.addAll(path);
  428. for(IntermediateCableWithState icws : this.minModel.getEdgeList()) {
  429. edgeList.add(icws.getModel());
  430. }
  431. for(IntermediateCableWithState icws : child.minModel.getEdgeList()) {
  432. edgeList.add(icws.getModel());
  433. }
  434. //aggregate all objects
  435. ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
  436. for(Edge e : edgeList) {
  437. AbstractCanvasObject a = e.getA();
  438. AbstractCanvasObject b = e.getB();
  439. if(!objects.contains(a)) {
  440. objects.add(a);
  441. }
  442. if(!objects.contains(b)) {
  443. objects.add(b);
  444. }
  445. }
  446. this.minModel = new MinimumModel(objects, edgeList);
  447. }
  448. /**
  449. * revalidate this min model after a subholon was removed
  450. */
  451. public void revalidateMinModel() {
  452. if(this.parent == null)
  453. return;
  454. ArrayList<AbstractCanvasObject> list = new ArrayList<AbstractCanvasObject>();
  455. list.add(this.holonObject);
  456. this.minModel = new MinimumModel(list, new ArrayList<Edge>());
  457. for(int i=0; i< this.childHolons.size(); i++) {
  458. Holon child = this.childHolons.remove(0);
  459. if(this.model.checkHolonObjectsAreConnected(this, child, this.holonControlUnit.getStateEstimator().getNetThroughput())) {
  460. this.merge(child, true);
  461. }
  462. }
  463. if(this.parent != null) {
  464. this.parent.revalidateMinModel();
  465. }
  466. }
  467. public void revalidateMinModelAfterLoad() {
  468. if(this.childHolons.size() == 0) {
  469. this.revalidateMinModel();
  470. } else {
  471. List<Holon> list = List.copyOf(this.childHolons);
  472. for(Holon child : list) {
  473. child.revalidateMinModelAfterLoad();
  474. }
  475. }
  476. }
  477. /**
  478. * returns the holon which uses the specified path if it is included in min model, otherwise null
  479. */
  480. public Holon containsPath(ArrayList<Edge> path, Holon requester) {
  481. if(this.minModel.containsPath(path) || this.parent == null) {
  482. for(Holon child : this.childHolons) {
  483. if(child.equals(requester))
  484. continue;
  485. Holon h = child.containsPath(path, this);
  486. if(h != null) {
  487. return h;
  488. }
  489. }
  490. return this;
  491. }
  492. for(Edge e : path) {
  493. AbstractCanvasObject a = e.getA();
  494. AbstractCanvasObject b = e.getB();
  495. if(a instanceof HolonObject && this.childHolons.contains(((HolonObject) a).holon))
  496. return ((HolonObject) a).holon;
  497. if(b instanceof HolonObject && this.childHolons.contains(((HolonObject) b).holon))
  498. return ((HolonObject) b).holon;
  499. if(this.getAllObjects().contains(a) || this.getAllObjects().contains(b))
  500. return this;
  501. }
  502. return null;
  503. }
  504. /**
  505. * checks whether the requester can run without this holon (none of the paths inside the requesters model is occupied by this model)
  506. * @param requester
  507. * @return
  508. */
  509. public boolean canRunIndependent(Holon requester) {
  510. if(this.parent == null || this.parent.getParent() == null)
  511. return true;
  512. ArrayList<AbstractCanvasObject> objects = new ArrayList<AbstractCanvasObject>();
  513. objects.addAll(requester.getMinimumModel().getHolonObjectList());
  514. objects.addAll(requester.getMinimumModel().getNodeList());
  515. objects.addAll(requester.getMinimumModel().getSwitchList());
  516. for(Holon child : this.childHolons) {
  517. if(child.equals(requester))
  518. continue;
  519. ArrayList<Edge> path = this.pathsToChildren.get(child);
  520. ArrayList<AbstractCanvasObject> pathObjects = new ArrayList<AbstractCanvasObject>();
  521. for(Edge e : path) {
  522. AbstractCanvasObject a = e.getA();
  523. AbstractCanvasObject b = e.getB();
  524. if(!pathObjects.contains(a))
  525. pathObjects.add(a);
  526. if(!pathObjects.contains(b))
  527. pathObjects.add(b);
  528. }
  529. for(AbstractCanvasObject aco : pathObjects) {
  530. if(objects.contains(aco))
  531. return false;
  532. }
  533. }
  534. return true;
  535. }
  536. public boolean isASuperiorHolon(String holon) {
  537. return this.parent != null ? (this.parent.getUniqueID().equals(holon) || this.parent.isASuperiorHolon(holon)) : false;
  538. }
  539. public int getMergeCounter() {
  540. return mergeCounter;
  541. }
  542. public int getSplitCounter() {
  543. return splitCounter;
  544. }
  545. public void incSplitCounter() {
  546. this.splitCounter++;
  547. }
  548. public int[] getStateCounter() {
  549. return this.stateCounter;
  550. }
  551. public void countState(float dev) {
  552. if(Math.abs(dev) <= 1-OptimizationManager.POWER_THRESHOLD_COMFORT) {
  553. this.stateCounter[0]++;
  554. } else if(Math.abs(dev) <= 1-OptimizationManager.POWER_THRESHOLD_STABILITY) {
  555. this.stateCounter[1]++;
  556. } else {
  557. this.stateCounter[2]++;
  558. }
  559. // switch (this.holonControlUnit.getStateEstimator().getStateIndicator()) {
  560. // case DESIRED:
  561. // this.stateCounter[0]++;
  562. // break;
  563. // case ENDANGERED:
  564. // this.stateCounter[1]++;
  565. // break;
  566. // case DYSFUNCTIONAL:
  567. // this.stateCounter[2]++;
  568. // break;
  569. // default:
  570. // throw new IllegalArgumentException("Unexpected value: " + this.holonControlUnit.getStateEstimator().getStateIndicator());
  571. // }
  572. }
  573. }