TargetStateAssembler.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. package classes.holonControlUnit;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import com.google.gson.Gson;
  6. import classes.holonControlUnit.OptimizationManager.OptimizationScheme;
  7. import classes.holonControlUnit.messages.MergeMsg;
  8. import classes.holonControlUnit.messages.Message;
  9. import classes.holonControlUnit.messages.OrderMsg;
  10. import classes.holonControlUnit.messages.StateMsg;
  11. public class TargetStateAssembler {
  12. private HolonControlUnit hcu;
  13. private float desiredPowerUsage = 100f;
  14. private OrderMsg order;
  15. public TargetStateAssembler(HolonControlUnit hcu) {
  16. this.order = null;
  17. this.hcu = hcu;
  18. }
  19. public void assembleTargetState(int timeStep) {
  20. getDesiredPowerUsage(timeStep);
  21. //balance the sub holons
  22. OptimizationScheme optScheme = this.hcu.getOptimizer().getOptimizationScheme();
  23. switch(optScheme) {
  24. case COMFORT:
  25. assembleTargetStateComfort(timeStep);
  26. break;
  27. case STABILITY:
  28. assembleTargetStateStability(timeStep);
  29. break;
  30. case RECOVERY:
  31. assembleTargetStateRecovery(timeStep);
  32. break;
  33. default:
  34. System.err.println("Unknown optimization scheme in "+this.hcu.getHolon().getUniqueID());
  35. }
  36. this.hcu.getHierarchyController().propagateMergeReqToParent(timeStep-1);
  37. }
  38. private void assembleTargetStateComfort(int timeStep) {
  39. //overall power usage inside this holarchy
  40. float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
  41. ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
  42. //check if this holon can run independent from parent without risking stability
  43. if(this.hcu.matchPowerRange(powerUsage, 0f, predictedPowerUsage, OptimizationManager.POWER_THRESHOLD_COMFORT)
  44. && this.hcu.getHolon().getLayer() > 1 && this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon())) {
  45. this.hcu.getHolon().incIndeCounter();
  46. this.hcu.getHierarchyController().splitSuperHolon(timeStep);
  47. this.desiredPowerUsage = 0f;
  48. orderSubholonsPredictedPower(timeStep);
  49. return;
  50. }
  51. //powerUsage already matches desired value, everything as before
  52. if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage)) {
  53. orderSubholonsPredictedPower(timeStep);
  54. return;
  55. }
  56. float requiredPower = this.desiredPowerUsage - powerUsage;
  57. //find flexibility which matches required power
  58. float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
  59. if(savedWithFlexibilities == requiredPower) {
  60. orderSubholonsPredictedPower(timeStep);
  61. return;
  62. }
  63. requiredPower -= savedWithFlexibilities;
  64. if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  65. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  66. return;
  67. }
  68. //go through merge requests from last iteration
  69. float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT);
  70. if(savedByMerging == requiredPower) {
  71. orderSubholonsPredictedPower(timeStep);
  72. return;
  73. }
  74. requiredPower -= savedByMerging;
  75. //look out for another superholon
  76. if(!this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  77. findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
  78. }
  79. //tell all holons to use a little more/less energy
  80. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  81. }
  82. private void assembleTargetStateStability(int timeStep) {
  83. //overall power usage inside this holarchy
  84. float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
  85. ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
  86. //powerUsage already matches desired value, everything as before
  87. if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage)) {
  88. orderSubholonsPredictedPower(timeStep);
  89. return;
  90. }
  91. float requiredPower = this.desiredPowerUsage - powerUsage;
  92. //find flexibility which matches required power
  93. float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
  94. if(savedWithFlexibilities == requiredPower) {
  95. orderSubholonsPredictedPower(timeStep);
  96. return;
  97. }
  98. requiredPower -= savedWithFlexibilities;
  99. if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  100. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  101. return;
  102. }
  103. //go through merge requests from last iteration
  104. float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY);
  105. if(savedByMerging == requiredPower) {
  106. orderSubholonsPredictedPower(timeStep);
  107. return;
  108. }
  109. requiredPower -= savedByMerging;
  110. //look out for another superholon
  111. if(!this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  112. findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
  113. }
  114. //tell all holons to use a little more/less energy
  115. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  116. }
  117. private void assembleTargetStateRecovery(int timeStep) {
  118. //overall power usage inside this holarchy
  119. float powerUsage = this.hcu.getStateEstimator().getPowerUsage();
  120. ArrayList<Float> predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage();
  121. //powerUsage already matches desired value, everything as before
  122. if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage)) {
  123. orderSubholonsPredictedPower(timeStep);
  124. return;
  125. }
  126. float requiredPower = this.desiredPowerUsage - powerUsage;
  127. //find flexibility which matches required power
  128. float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep);
  129. if(savedWithFlexibilities == requiredPower) {
  130. orderSubholonsPredictedPower(timeStep);
  131. return;
  132. }
  133. requiredPower -= savedWithFlexibilities;
  134. if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  135. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  136. return;
  137. }
  138. //go through merge requests from last iteration
  139. float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY);
  140. if(savedByMerging == requiredPower) {
  141. orderSubholonsPredictedPower(timeStep);
  142. return;
  143. }
  144. requiredPower -= savedByMerging;
  145. if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  146. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  147. return;
  148. }
  149. float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep) : 0f;
  150. requiredPower = this.desiredPowerUsage - p;
  151. //split dysfunctional parts
  152. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  153. List<List<String>> childPerm = getAllPermutations(List.copyOf(childStates.keySet()));
  154. HashMap<Float, List<String>> potChild = new HashMap<Float, List<String>>();
  155. for(List<String> l : childPerm) {
  156. //check how much power this subset of child would consume
  157. Float[] savings = new Float[predictedPowerUsage.size()+1];
  158. for(int i=0; i<savings.length; i++)
  159. savings[i] = 0f;
  160. for(String s : l) {
  161. StateMsg state = childStates.get(s);
  162. savings[0] = savings[0] + state.getPowerUsage();
  163. for(int i=1; i<savings.length; i++) {
  164. savings[i] += state.getPredictedPowerUsage().get(i-1);
  165. }
  166. }
  167. if(this.hcu.decreasesPowerUsage(List.of(savings), powerUsage, predictedPowerUsage, this.desiredPowerUsage)) {
  168. float pu = 0f;
  169. for(int i=0; i<savings.length; i++)
  170. pu += savings[i];
  171. pu = pu/savings.length;
  172. if(potChild.containsKey(pu) && potChild.get(pu).size() >= l.size())
  173. continue;
  174. potChild.put(pu, l);
  175. }
  176. }
  177. //find subset of children with most fitting powerUsage
  178. float min = Float.MAX_VALUE;
  179. //the required power usage without any child holons
  180. float r = this.desiredPowerUsage - this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep);
  181. for(float f : potChild.keySet()) {
  182. if(Math.abs(r-f) < Math.abs(r-min)) {
  183. min = f;
  184. }
  185. }
  186. //split all other subholons
  187. List<String> list = new ArrayList<String>();
  188. if(potChild.containsKey(min)) {
  189. list = potChild.get(min);
  190. List<String> subs = List.copyOf(this.hcu.getHierarchyController().getSubHolons());
  191. for(String s : subs) {
  192. if(!list.contains(s)) {
  193. this.hcu.getHolon().incKickCounter();
  194. this.hcu.getHierarchyController().splitSubHolon(s, timeStep);
  195. }
  196. }
  197. requiredPower = r - min;
  198. if(requiredPower == 0) {
  199. //by removing child holons we have regained stability
  200. orderSubholonsPredictedPower(timeStep);
  201. return;
  202. }
  203. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  204. return;
  205. }
  206. //Split from superholon?
  207. if(Math.abs(requiredPower) > Math.abs(powerUsage) && this.hcu.getHolon().getLayer() > 1
  208. && this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon())
  209. && !this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  210. this.hcu.getHolon().incIndeCounter();
  211. this.hcu.getHierarchyController().splitSuperHolon(timeStep);
  212. orderSubholonsRequiredPower(timeStep, powerUsage, 0f-powerUsage);
  213. return;
  214. }
  215. //look out for another superholon
  216. if(!this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep))
  217. findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage);
  218. //tell all holons to use a little more/less energy
  219. orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower);
  220. }
  221. /**
  222. * go through all previously received merge requests from other holons
  223. * if there is a fitting one merge
  224. * @param timeStep
  225. * @param requiredPower
  226. * @return saved power
  227. */
  228. private float gothroughMergeReq(int timeStep, float currentPower, float requiredPower, ArrayList<Float> predictedPower,
  229. OptimizationScheme optScheme) {
  230. List<MergeMsg> requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1);
  231. if(requests == null)
  232. return 0f;
  233. if(this.hcu.getHierarchyController().alreadyMergedAtTimeStep(timeStep)) {
  234. return 0f;
  235. }
  236. //store holon which would help decrease |requiredPower|
  237. ArrayList<MergeMsg> poten = new ArrayList<MergeMsg>();
  238. //find a perfect match or holon which would help decrease |requiredPower|
  239. for(MergeMsg req : requests) {
  240. String requester = req.getRequester();
  241. float newThroughput = req.getNetThroughput() + this.hcu.getStateEstimator().getNetThroughput();
  242. if(!this.hcu.getHierarchyController().canMerge(requester, newThroughput)) {
  243. //cannot merge with the requester
  244. continue;
  245. }
  246. // ask the requester whether it is still interested in merging
  247. this.hcu.getHierarchyController().sendMergeAck(timeStep, req);
  248. }
  249. poten = this.hcu.getHierarchyController().getReceivedMergeAckII(timeStep);
  250. //go through all poten candidates and find most suiting subset
  251. //all candidates have either power < 0 or > 0
  252. if(poten.size() < 1)
  253. return 0f;
  254. List<List<MergeMsg>> potPermut = getAllPermutations(poten);
  255. HashMap<Float, List<MergeMsg>> potSavings = new HashMap<Float, List<MergeMsg>>();
  256. for(List<MergeMsg> l : potPermut) {
  257. //check how much power this subset of merges would save
  258. Float[] savings = new Float[predictedPower.size()];
  259. for(int i=0; i<savings.length; i++)
  260. savings[i] = 0f;
  261. for(MergeMsg m : l) {
  262. for(int i=0; i<savings.length; i++) {
  263. savings[i] = savings[i] + m.getPredictedPowerUsage().get(i);
  264. }
  265. }
  266. if(this.hcu.decreasesPowerUsage(List.of(savings), currentPower, predictedPower, requiredPower)) {
  267. float s = 0f;
  268. for(int i=0; i<savings.length; i++)
  269. s += savings[i];
  270. s = s/savings.length; //average saving over the next time periods
  271. if(potSavings.containsKey(s) && potSavings.get(s).size() >= l.size())
  272. continue;
  273. potSavings.put(s, l);
  274. }
  275. }
  276. if(potSavings.size() < 1) {
  277. return 0f;
  278. }
  279. float min = Float.MAX_VALUE;
  280. for(float f : potSavings.keySet()) {
  281. if(Math.abs(requiredPower-f) < Math.abs(requiredPower-min)) {
  282. min = f;
  283. }
  284. }
  285. //merge with all holons that are part of the subset with the max saving
  286. if(potSavings.containsKey(min)) {
  287. for(MergeMsg req : potSavings.get(min)) {
  288. this.hcu.getHierarchyController().merge(req, timeStep);
  289. }
  290. //remove merge requests so they don't get propagated to super holon
  291. requests.removeAll(potSavings.get(min));
  292. this.hcu.getHierarchyController().resetPaths();
  293. return min;
  294. }
  295. return 0f;
  296. }
  297. private void findNewSuperHolon(int timeStep, float powerUsage, ArrayList<Float> predictedPowerUsage) {
  298. if(!this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon())) {
  299. return;
  300. }
  301. for(String physicalNeighbor : this.hcu.getHierarchyController().getPhysicalNeighborsFromOtherHolarchy()) {
  302. this.hcu.getHierarchyController().sendMergeReq(powerUsage, predictedPowerUsage, timeStep, physicalNeighbor);
  303. }
  304. }
  305. private void orderSubholonsPredictedPower(int timeStep) {
  306. HashMap<String, StateMsg> childStates = this.hcu.getStateEstimator().getChildStates();
  307. Gson gson = this.hcu.getCommunicator().getGson();
  308. for(String s : childStates.keySet()) {
  309. OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().size() > 0 ?childStates.get(s).getPredictedPowerUsage().get(0) : 0, timeStep);
  310. this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o));
  311. }
  312. }
  313. /**
  314. * compute a new target value for all subholons
  315. * "fairness": all subholons get same target value
  316. * @param timeStep
  317. * @param powerUsage
  318. * @param requiredPower
  319. * @param optScheme
  320. */
  321. private void orderSubholonsRequiredPower(int timeStep, float powerUsage, float requiredPower) {
  322. Gson gson = this.hcu.getCommunicator().getGson();
  323. float opt = - requiredPower/this.hcu.getHierarchyController().getSubHolons().size();
  324. this.hcu.getStateEstimator().calculateNetThroughput(timeStep);
  325. for(String s : this.hcu.getHierarchyController().getSubHolons()) {
  326. //order for subholon
  327. OrderMsg o = new OrderMsg(opt, timeStep);
  328. //send order to subholon
  329. this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o));
  330. }
  331. }
  332. private <T> List<List<T>> getAllPermutations(List<T> set){
  333. List<List<T>> out = new ArrayList<List<T>>();
  334. for(int i=0; i<set.size(); i++) {
  335. for(int j=i; j<set.size(); j++) {
  336. List<T> l = new ArrayList<T>();
  337. l.addAll(set.subList(i, j+1));
  338. out.add(l);
  339. }
  340. }
  341. return out;
  342. }
  343. public float getDesiredPowerUsage(int timeStep) {
  344. if(timeStep <= 0) {
  345. //for init
  346. this.desiredPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage().get(0);
  347. } else if(this.order == null || this.order.getTimeStep() < timeStep-1) {
  348. this.desiredPowerUsage = 0f;
  349. } else {
  350. this.desiredPowerUsage = this.order.getDesiredPowerUsage();
  351. }
  352. return this.desiredPowerUsage;
  353. }
  354. public void setOrder(OrderMsg order, String sender) {
  355. if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) {
  356. this.order = order;
  357. }
  358. }
  359. }