package classes.holonControlUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import com.google.gson.Gson; import classes.holonControlUnit.OptimizationManager.OptimizationScheme; import classes.holonControlUnit.messages.MergeMsg; import classes.holonControlUnit.messages.Message; import classes.holonControlUnit.messages.OrderMsg; import classes.holonControlUnit.messages.StateMsg; public class TargetStateAssembler { private HolonControlUnit hcu; private float desiredPowerUsage = 100f; private OrderMsg order; // private HashMap ordersForSubholon; public TargetStateAssembler(HolonControlUnit hcu) { this.order = null; this.hcu = hcu; // this.ordersForSubholon = new HashMap(); } public void assembleTargetState(int timeStep) { if(timeStep <= 1) { //for init this.desiredPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage().get(0); } else if(this.order == null || this.order.getTimeStep() < timeStep-1) { this.desiredPowerUsage = 0f; } else { this.desiredPowerUsage = this.order.getDesiredPowerUsage(); } // this.ordersForSubholon.clear(); // System.out.println(this.hcu.getHolon().name+" opt scheme: "+this.hcu.getOptimizer().getOptimizationScheme()); // System.out.println(this.hcu.getHolon().getUniqueID()+" power: "+this.hcu.getStateEstimator().getPowerUsage()+" des: "+this.desiredPowerUsage); //balance the sub holons OptimizationScheme optScheme = this.hcu.getOptimizer().getOptimizationScheme(); switch(optScheme) { case COMFORT: assembleTargetStateComfort(timeStep); break; case MIN_COST: break; case ENERGY_CONSUMPTION: break; case STABILITY: assembleTargetStateStability(timeStep); break; case RECOVERY: assembleTargetStateRecovery(timeStep); break; default: System.err.println("Unknown optimization scheme in "+this.hcu.getHolon().getUniqueID()); } this.hcu.getHierarchyController().propagateMergeReqToParent(timeStep-1); } private void assembleTargetStateComfort(int timeStep) { //overall power usage inside this holarchy float powerUsage = this.hcu.getStateEstimator().getPowerUsage(); ArrayList predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage(); if(predictedPowerUsage.size() < 1) { //no more iterations inside simulator return; } //check if this holon can run independent from parent without risking stability if(this.hcu.matchPowerRange(powerUsage, 0f, predictedPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold()) && this.hcu.getHolon().getParent().canRunIndependent(this.hcu.getHolon()) && this.hcu.getHolon().getLayer() > 1) { // System.out.println(this.hcu.getHolon().getUniqueID()+" can run independent"); this.hcu.getHierarchyController().splitSuperHolon(timeStep); this.desiredPowerUsage = 0f; orderSubholonsPredictedPower(timeStep); return; } //powerUsage already matches desired value, everything as before if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) { // System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage); orderSubholonsPredictedPower(timeStep); return; } // System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage); float requiredPower = this.desiredPowerUsage - powerUsage; //find flexibility which matches required power float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep); if(savedWithFlexibilities == requiredPower) { orderSubholonsPredictedPower(timeStep); return; } requiredPower -= savedWithFlexibilities; //go through merge requests from last iteration float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.COMFORT); if(savedByMerging == requiredPower) { orderSubholonsPredictedPower(timeStep); return; } requiredPower -= savedByMerging; //look out for another superholon findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage); //tell all holons to use a little more/less energy orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower); } private void assembleTargetStateStability(int timeStep) { //overall power usage inside this holarchy float powerUsage = this.hcu.getStateEstimator().getPowerUsage(); ArrayList predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage(); if(predictedPowerUsage.size() < 1) { //no more iterations inside simulator return; } //powerUsage already matches desired value, everything as before if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) { // System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage); orderSubholonsPredictedPower(timeStep); return; } // System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage); float requiredPower = this.desiredPowerUsage - powerUsage; //find flexibility which matches required power float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep); if(savedWithFlexibilities == requiredPower) { orderSubholonsPredictedPower(timeStep); return; } requiredPower -= savedWithFlexibilities; //go through merge requests from last iteration float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.STABILITY); if(savedByMerging == requiredPower) { orderSubholonsPredictedPower(timeStep); return; } requiredPower -= savedByMerging; //look out for another superholon findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage); //tell all holons to use a little more/less energy orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower); } private void assembleTargetStateRecovery(int timeStep) { //overall power usage inside this holarchy float powerUsage = this.hcu.getStateEstimator().getPowerUsage(); ArrayList predictedPowerUsage = this.hcu.getStateEstimator().getPredictedPowerUsage(); if(predictedPowerUsage.size() < 1) { //no more iterations inside simulator return; } //powerUsage already matches desired value, everything as before if(this.hcu.matchPowerRange(powerUsage, this.desiredPowerUsage, this.hcu.getOptimizer().getCurrentPowerThreshold())) { // System.out.println(this.hcu.getHolon().getUniqueID()+" power usage as desired "+powerUsage); orderSubholonsPredictedPower(timeStep); return; } // System.out.println(this.hcu.getHolon().getUniqueID()+" power usage "+powerUsage+" not as desired "+this.desiredPowerUsage); float requiredPower = this.desiredPowerUsage - powerUsage; //find flexibility which matches required power float savedWithFlexibilities = this.hcu.getFlexMan().applyFlexibilities(powerUsage, requiredPower, predictedPowerUsage, timeStep); if(savedWithFlexibilities == requiredPower) { orderSubholonsPredictedPower(timeStep); return; } requiredPower -= savedWithFlexibilities; //go through merge requests from last iteration float savedByMerging = gothroughMergeReq(timeStep, powerUsage, requiredPower, predictedPowerUsage, OptimizationScheme.RECOVERY); if(savedByMerging == requiredPower) { orderSubholonsPredictedPower(timeStep); return; } requiredPower -= savedByMerging; // float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep) : 0f; // requiredPower = this.desiredPowerUsage - p; //split dysfunctional parts HashMap childStates = this.hcu.getStateEstimator().getChildStates(); List> childPerm = getAllPermutations(List.copyOf(childStates.keySet())); HashMap> potChild = new HashMap>(); for(List l : childPerm) { //check how much power this subset of child would consume Float[] savings = new Float[predictedPowerUsage.size()+1]; for(int i=0; i= l.size()) continue; potChild.put(pu, l); } } //find subset of children with most fitting powerUsage float min = Float.MAX_VALUE; //the required power usage without any child holons float r = this.desiredPowerUsage - this.hcu.getHolon().getHolonObject().getEnergyAtTimeStepFlex(timeStep); for(float f : potChild.keySet()) { if(Math.abs(f+r) < Math.abs(min+r)) { min = f; } } //split all other subholons List list = new ArrayList(); if(potChild.containsKey(min)) { list = potChild.get(min); } List subs = List.copyOf(this.hcu.getHierarchyController().getSubHolons()); for(String s : subs) { if(!list.contains(s)) { this.hcu.getHierarchyController().splitSubHolon(s, timeStep); // requiredPower -= childStates.getOrDefault(s, new StateMsg(0f, 0f, null, null)).getPowerUsage(); } } requiredPower = r + min; if(requiredPower == 0) { //by removing child holons we have regained stability orderSubholonsPredictedPower(timeStep); return; } //Split from superholon? if(Math.abs(requiredPower) > Math.abs(powerUsage) && this.hcu.getHolon().getLayer() > 1) { // System.out.println("----"+requiredPower+" "+powerUsage); this.hcu.getHierarchyController().splitSuperHolon(timeStep); orderSubholonsRequiredPower(timeStep, powerUsage, 0f-powerUsage); return; } //look out for another superholon findNewSuperHolon(timeStep, powerUsage, predictedPowerUsage); //tell all holons to use a little more/less energy orderSubholonsRequiredPower(timeStep, powerUsage, requiredPower); } /** * go through all previously received merge requests from other holons * if there is a fitting one merge * @param timeStep * @param requiredPower * @return saved power */ private float gothroughMergeReq(int timeStep, float currentPower, float requiredPower, ArrayList predictedPower, OptimizationScheme optScheme) { List requests = this.hcu.getHierarchyController().getMergeRequestsForTimeStep(timeStep-1); if(requests == null) return 0f; //store holon which would help decrease |requiredPower| ArrayList poten = new ArrayList(); //find a perfect match or holon which would help decrease |requiredPower| for(MergeMsg req : requests) { float r = req.getPredictedPowerUsage().get(0); //since merge req is from timeStep-1 String requester = req.getRequester(); float newThroughput = req.getNetThroughput() + this.hcu.getStateEstimator().getNetThroughput(); if(!this.hcu.getHierarchyController().canMerge(requester, newThroughput)) { //cannot merge with the requester continue; } // System.out.println(this.hcu.getHolon().getUniqueID()+" merge req "+req.getPower()+" " // +this.hcu.matchPowerRange(r, requiredPower, predictedPower, this.hcu.getOptimizer().getCurrentPowerThreshold())); if(this.hcu.matchPowerRange(r, requiredPower, predictedPower, this.hcu.getOptimizer().getCurrentPowerThreshold())) { //perfect match this.hcu.getHierarchyController().sendMergeAck(timeStep, req, true); // OrderMsg o = new OrderMsg(r, optScheme, timeStep); // this.ordersForSubholon.put(requester, o); requests.remove(req); return r; } // } else if( ((r < 0 && requiredPower < 0) || (r > 0 && requiredPower > 0)) // && this.hcu.decreasesPowerUsage(req.getPredictedPowerUsage(), currentPower, predictedPower, requiredPower)) { //accepting this request would help this holon poten.add(req); // } } //go through all poten candidates and find most suiting subset //all candidates have either power < 0 or > 0 if(poten.size() < 1) return 0f; List> potPermut = getAllPermutations(poten); HashMap> potSavings = new HashMap>(); for(List l : potPermut) { //check how much power this subset of merges would save Float[] savings = new Float[predictedPower.size()]; for(int i=0; i= l.size()) continue; potSavings.put(s, l); } } if(potSavings.size() < 1) { return 0f; } float min = Float.MAX_VALUE; for(float f : potSavings.keySet()) { // System.out.println(requiredPower+" "+currentPower+" "+min+" "+f+" "+Math.abs(requiredPower-f)+" < "+Math.abs(requiredPower-min)); if(Math.abs(requiredPower-f) < Math.abs(requiredPower-min)) { min = f; } } // System.out.println("min "+min); // System.out.println(potSavings.keySet()); //merge with all holons that are part of the subset with the max saving if(potSavings.containsKey(min)) { for(MergeMsg req : potSavings.get(min)) { // System.out.println("I wanna merge"); // float r = req.getPower(); // String requester = req.getRequester(); this.hcu.getHierarchyController().sendMergeAck(timeStep, req, min == requiredPower); // OrderMsg o = new OrderMsg(r, optScheme, timeStep); // this.ordersForSubholon.put(requester, o); } //remove merge requests so they don't get propagated to super holon requests.removeAll(potSavings.get(min)); return min; } return 0f; } private void findNewSuperHolon(int timeStep, float powerUsage, ArrayList predictedPowerUsage) { for(String physicalNeighbor : this.hcu.getHierarchyController().getPhysicalNeighborsFromOtherHolarchy()) { this.hcu.getHierarchyController().sendMergeReq(powerUsage, predictedPowerUsage, timeStep, physicalNeighbor); } } private void orderSubholonsPredictedPower(int timeStep) { HashMap childStates = this.hcu.getStateEstimator().getChildStates(); Gson gson = this.hcu.getCommunicator().getGson(); for(String s : childStates.keySet()) { OrderMsg o = new OrderMsg(childStates.get(s).getPredictedPowerUsage().get(0), timeStep); // this.ordersForSubholon.put(s, o); this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o)); } } /** * compute a new target value for all subholons * "fairness": all subholons get same target value * @param timeStep * @param powerUsage * @param requiredPower * @param optScheme */ private void orderSubholonsRequiredPower(int timeStep, float powerUsage, float requiredPower) { // float p = this.hcu.getHolon().isPhysical ? this.hcu.getHolon().getHolonObject().getEnergyAtTimeStep(timeStep) : 0f; // requiredPower = this.desiredPowerUsage - p; // HashMap childStates = this.hcu.getStateEstimator().getChildStates(); Gson gson = this.hcu.getCommunicator().getGson(); float opt = - requiredPower/this.hcu.getHierarchyController().getSubHolons().size(); //(childStates.size() - this.ordersForSubholon.size() != 0 ? childStates.size() - this.ordersForSubholon.size() : 1); for(String s : this.hcu.getHierarchyController().getSubHolons()) { //order for subholon // if(this.ordersForSubholon.containsKey(s)) // continue; OrderMsg o = new OrderMsg(opt, timeStep); // this.ordersForSubholon.put(s, o); //send order to subholon this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(o)); } //send order to subholons // for(String s : this.ordersForSubholon.keySet()) { // if(this.hcu.getHierarchyController().getSubHolons().contains(s)) // this.hcu.getCommunicator().sendMsg(s, Message.Type.ORDER, gson.toJson(this.ordersForSubholon.get(s))); // } } private List> getAllPermutations(List set){ List> out = new ArrayList>(); for(int i=0; i l = new ArrayList(); l.addAll(set.subList(i, j+1)); out.add(l); } } return out; } public float getDesiredPowerUsage() { return this.desiredPowerUsage; } public void setOrder(OrderMsg order, String sender) { // System.out.println(this.hcu.getHolon().getUniqueID()+" received order "+order); if(sender.equals(this.hcu.getHierarchyController().getSuperHolon())) { this.order = order; } } }