package holeg.algorithm.objective_function;
import java.util.logging.Logger;
import holeg.model.HolonElement.Priority;
import holeg.model.Model;
public class ObjectiveFunctionByCarlos {
// Parameters
private static final Logger log = Logger.getLogger(ObjectiveFunctionByCarlos.class.getName());
// weight for f_g(H)
static double w_eb = .3, w_state = .3, w_pro = .2, w_perf = .1, w_holon = .1;
// killswitch weights
// static double w_eb = 0.5, w_state = 0.5, w_pro = 0.0f, w_perf = .0,
// w_holon=.0;
// kappas for squashing function
//
// static double k_eb = 1050000.f, k_state = 10000, k_pro = 2000, k_perf =
// 11000, k_holon= 150000;
// oversupplied
static double k_eb = 750000.f, k_state = 20000, k_pro = 3000, k_perf = 15000, k_holon = 200000;
// old values undersupplied
// static double k_eb = 1000000.f, k_state = 15000, k_pro = 2100, k_perf = 12000, k_holon= 200000;
// theta for f_pro
static double theta = 3;
// kappas for f_perf:
static double kappa_f_unre = 120;
static double kappa_f_cool = 60 * 60 * 24;
static double kappa_f_dur = 60 * 60;
// lambdas for f_perf:
static double lambda_f_unre = 10;
static double lambda_f_cool = 10;
static double lambda_f_dur = 10;
static double lambda_f_change = 1000;
// pre-calculated parameters for partial function terms:
/**
* Pre calculated for the squash function
* {@link ObjectiveFunctionByCarlos#squash}
*/
static double squash_subtract = 100.f / (1.f + (float) Math.exp(5.0));
static double range_for_kappa_f_unre = range(kappa_f_unre);
static double range_for_kappa_f_cool = range(kappa_f_cool);
static double range_for_kappa_f_dur = range(kappa_f_dur);
static {
// init
checkParameter();
}
/**
* Check parameter Setting and print error when wrong values are put in. Here
* should all invariants be placed to be checked on initialization.
*/
private static void checkParameter() {
boolean parameterSumOne = Math.abs(w_eb + w_state + w_pro + w_perf + w_holon - 1) < 0.001;
if (!parameterSumOne) {
log.warning("ParameterError in ObjectiveFunction: w1 + w2 + w3 + w4 + w5 should be 1");
}
}
/**
* ObjectifeFunction by Carlos. Function computes f_g: f_g = w1 * squash(f_eb,
* k1) + w2 * squash(f_state, k2) + w3 * squash(f_pro, k3) + w4 * squash(f_perf,
* k4) + w5 * squash(f_holon, k5)
*
*
* squash is the squashing function {@link ObjectiveFunctionByCarlos#squash}
*
*
* @return f_g value between 0 and 100
*/
//TODO(Tom2022-01-13) Fix ObjectiveFunctionByCarlos
static public double getFitnessValueForState(Model model) {
// // Calculate f_eb the penalty for unbalenced energy in the network
// double f_eb = 0;
// // sum over all objects
// for (DecoratedNetwork net : state.getNetworkList()) {
// double netEnergyDifference = 0;
// netEnergyDifference += net.getConsumerList().stream()
// .map(con -> con.getEnergySelfSupplied() - con.getEnergyFromConsumingElemnets())
// .reduce(0.f, Float::sum);
// netEnergyDifference += net.getConsumerSelfSuppliedList().stream()
// .map(con -> con.getEnergySelfSupplied() - con.getEnergyFromConsumingElemnets())
// .reduce(0.f, Float::sum);
// netEnergyDifference += net.getSupplierList().stream()
// .map(sup -> sup.getEnergyProducing() - sup.getEnergySelfConsuming()).reduce(0.f, Float::sum);
// // abs
// f_eb += Math.abs(netEnergyDifference);
// }
//
// // Calculate f_state the penalty function for the supply state
// double f_state = 0;
// for (DecoratedNetwork net : state.getNetworkList()) {
// f_state += net.getConsumerList().stream().map(con -> supplyPenalty(con.getSupplyBarPercentage())).reduce(0.,
// Double::sum);
// }
//
// // calculate f_pro the penalty function for priority usage
// // for each active flexibility punish
//
// List allFlexOrdered = state.getAllFlex().filter(flex -> flex.getState().equals(FlexState.IN_USE))
// .toList();
// double f_pro = 0;
// f_pro = allFlexOrdered.stream()
// .map(flex -> Math.pow(theta, priorityToDouble(flex.getElement().getPriority())) - 1.0)
// .reduce(0.0, Double::sum);
//
// // calculate f_perf the penalty function for the quality of a flexibility used
//
// // and the subfuction f_unre, f_cool, f_dur
// double f_perf = 0;
// for (Flexibility flex : allFlexOrdered) {
// double f_unre = unresponsivnessPenalty(flex.getSpeed());
// double f_cool = cooldownPenalty(flex.getCooldown());
// double f_dur = durationPenalty(flex.getDuration());
// f_perf += f_unre + f_cool + f_dur;
// }
//
// // calculate f_holon
// double f_holon = 0;
// for (DecoratedNetwork net : state.getNetworkList()) {
// double f_elements_diviation_production = net.getDeviationInProductionInNetworkForHolonObjects();
// double f_elements_diviation_consumption = net.getDeviationInProductionInNetworkForHolonObjects();
// double f_flexibility_diviation_consumption = net.getDiviationInFlexibilityConsumption();
// double f_flexibility_diviation_production = net.getDiviationInFlexibilityProduction();
//
// double con = net.getTotalConsumption();
// double prod = net.getTotalProduction();
// double flexcapProd = net.getFlexibilityProductionCapacity();
// double flexcapCon = net.getFlexibilityConsumptionCapacity();
// double f_change_positive = lambda_f_change
// - lambda_f_change * Math.min(1, (con > 0.0) ? flexcapProd / con : 1.0);
// double f_change_negativ = lambda_f_change
// - lambda_f_change * Math.min(1, (prod > 0.0) ? flexcapCon / prod : 1.0);
//
// double f_element = f_elements_diviation_production + f_elements_diviation_consumption;
// double f_flexibility = f_flexibility_diviation_consumption + f_flexibility_diviation_production;
// double f_change = f_change_positive + f_change_negativ;
//
// f_holon += f_element + f_flexibility + f_change;
// }
// double q1 = squash(f_eb, k_eb);
// double q2 = squash(f_state, k_state);
// double q3 = squash(f_pro, k_pro);
// double q4 = squash(f_perf, k_perf);
// double q5 = squash(f_holon, k_holon);
// log.finer("f_eb= " + f_eb + " f_state= " + f_state + " f_pro= " + f_pro + " f_perf= " + f_perf + " f_holon= "
// + f_holon + " q1= " + q1 + " q2= " + q2 + " q3= " + q3 + " q4= " + q4 + " q5= " + q5);
//
// return w_eb * q1 + w_state * q2 + w_pro * q3 + w_perf * q4 + w_holon * q5;
return 0;
}
/**
* The squashing function in paper
*
* @param x the input
* @param kappa the corresponding kappa
* @return
*/
static public double squash(double x, double kappa) {
return 100.f / (1.0f + Math.exp(-(10.f * (x - kappa / 2.f)) / kappa)) - squash_subtract;
}
/**
* f_sup in paper
*
* @param supply from 0 to 1
* @return
*/
static public double supplyPenalty(double supply) {
double supplyPercentage = 100 * supply;
// double test = (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50:
// supplyPercentage - 100;
return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50 : supplyPercentage - 100;
}
/**
* prio function in the paper
*
* @param priority
* @return
*/
private static double priorityToDouble(Priority priority) {
switch (priority) {
case Essential:
return 3.;
case High:
return 2.;
case Medium:
return 1.;
case Low:
default:
return 0.;
}
}
/**
* Attention Math.log calcultae ln not log
*
* @param kappa
* @return
*/
private static double range(double kappa) {
return -kappa / Math.log(Math.pow(2.0, 0.05) - 1.0);
}
/**
* f_unre
*
* @param unresponsiv
* @return
*/
private static double unresponsivnessPenalty(double unresponsiv) {
return (2.0 * lambda_f_unre) / (1 + Math.exp(-unresponsiv / range_for_kappa_f_unre)) - lambda_f_unre;
}
/**
* f_cool
*
* @param cooldown
* @return
*/
private static double cooldownPenalty(double cooldown) {
return (2.0 * lambda_f_cool) / (1 + Math.exp(-cooldown / range_for_kappa_f_cool)) - lambda_f_cool;
}
private static double durationPenalty(double duration) {
double lambda_dur_times2 = 2.0 * lambda_f_dur;
return -lambda_dur_times2 / (1 + Math.exp(-duration / range_for_kappa_f_dur)) + lambda_dur_times2;
}
}