package resa.optimize;
/**
* Created by Tom.fu on 23/4/2014.
*/
public class ServiceNode {
public static enum ServiceType {EXPONENTIAL, DETERMINISTIC, UNIFORM, OTHER}
private double lambda;
private double mu;
private ServiceType type = ServiceType.OTHER;
private double i2oRatio;
public ServiceNode(double l, double m, ServiceType t, double r) {
lambda = l;
if (Double.compare(m, 0.0) == 0) {
throw new IllegalArgumentException("mu cannot be 0");
}
mu = m;
type = t;
i2oRatio = r;
}
public void setLambda(double value) {
this.lambda = value;
}
public double getLambda() {
return this.lambda;
}
public void setMu(double value) {
this.mu = value;
}
public double getMu() {
return this.mu;
}
public void setO2IRatio(double value) {
this.i2oRatio = value;
}
public double getI2oRatio() {
return this.i2oRatio;
}
public String getServiceTypeString() {
return type.name().toLowerCase();
}
public int getMinReqServerCount() {
return getMinReqServerCount(this.lambda, this.mu);
}
public double getRho(int serverCount) {
return getRho(this.lambda, this.mu, serverCount);
}
public boolean isStable(int serverCount) {
return isStable(this.lambda, this.mu, serverCount);
}
public double getRhoSingleServer() {
return getRhoSingleServer(this.lambda, this.mu);
}
public double estErlangT(int serverCount) {
return estErlangT(this.lambda, this.mu, serverCount);
}
public double estMM1T(int serverCount) {
return estMM1T(this.lambda, this.mu, serverCount);
}
public String serviceNodeKeyStats(int serverCount, boolean showMinRequirement) {
if (showMinRequirement) {
return String.format("lambda: %.3f, mu: %.3f, rho: %.3f, k: %d, MinRequire: %d", lambda, mu,
getRho(serverCount), serverCount, getMinReqServerCount());
} else {
return String.format("lambda: %.3f, mu: %.3f, rho: %.3f, k: %d", lambda, mu, getRho(serverCount), serverCount);
}
}
///static function implementation!
/**
* if mu = 0.0 or serverCount not positive, then rho is not defined, we consider it as the unstable case (represented by Double.MAX_VALUE)
* otherwise, return the calculation results. Leave the interpretation to the calling function, like isStable();
*
* @param lambda
* @param mu
* @param serverCount
* @return
*/
private static double getRho(double lambda, double mu, int serverCount) {
return (mu == 0.0 || serverCount <= 0) ? Double.MAX_VALUE : lambda / (mu * (double) serverCount);
}
/**
* First call getRho,
* then determine when rho is validate, i.e., rho < 1.0
* otherwise return unstable (FALSE)
*
* @param lambda
* @param mu
* @param serverCount
* @return
*/
public static boolean isStable(double lambda, double mu, int serverCount) {
return getRho(lambda, mu, serverCount) < 1.0;
}
private static double getRhoSingleServer(double lambda, double mu) {
return getRho(lambda, mu, 1);
}
public static int getMinReqServerCount(double lambda, double mu) {
return (int) (lambda / mu) + 1;
}
/**
* First Check isStable(), if it is stable, return the validate estimated erlang delay
* else, return Double.Max_VALUE
*
* @param lambda, average arrival rate
* @param mu, average execute rate
* @param serverCount
* @return
*/
public static double estErlangT(double lambda, double mu, int serverCount) {
if (isStable(lambda, mu, serverCount)) {
double r = lambda / (mu * (double) serverCount);
double kr = lambda / mu;
double phi0_p1 = 1.0;
for (int i = 1; i < serverCount; i++) {
double a = Math.pow(kr, i);
double b = (double) factorial(i);
phi0_p1 += (a / b);
}
double phi0_p2_nor = Math.pow(kr, serverCount);
double phi0_p2_denor = (1.0 - r) * (double) (factorial(serverCount));
double phi0_p2 = phi0_p2_nor / phi0_p2_denor;
double phi0 = 1.0 / (phi0_p1 + phi0_p2);
double pWait = phi0_p2 * phi0;
double estT = pWait * r / ((1.0 - r) * lambda) + 1.0 / mu;
return estT;
} else {
//System.out.println("Service is not stable!!!");
return Double.MAX_VALUE;
}
}
public static double estMM1T(double lambda, double mu, int serverCount) {
if (isStable(lambda, mu, serverCount)) {
return 1.0 / (mu * (double) serverCount - lambda);
} else {
System.out.println("Service is not stable!!!");
return Double.MAX_VALUE;
}
}
private static int factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException("Attention, negative input is not allowed: " + n);
} else if (n == 0) {
return 1;
} else {
int ret = 1;
for (int i = 2; i <= n; i++) {
ret = ret * i;
}
return ret;
}
}
}