// NETask.java // // coding: Vytautas Leonavicius email: cpp@maxi.lt // some ideas taken from (NashModel1.java): unknown student work (thank You!) // theory: Tomas Motuzas, Tomas Kikalas // Last update 2002 11 14 16.52 package lt.ktu.gmj.tasks; import lt.ktu.gmj.*; import lt.ktu.gmj.propertySheet.*; import java.util.*; ///////////////////////////////////////////////////////// //****************************** // NashMarket model 1 impl.***** //****************************** class NashMarket { // member vars // Model parameters. Hard change them or implement property provider field to customize them from applet private final int N_CLIENTS = 1000; // clients to share between servers private final int N_SERVERS = 3; // nr of servers private final double D_AVG_CLIENT_COME = 10.0; // average client comming time private final double D_MAX_CLIENT_CAN_PAY = 10.0; // max client can pay private double dCurrentTime = 0.0; // current time variable. private NEDomain domain = null; // domain reference public NashServer nsvServers[]; // nash servers vector /* * Constructor */ public NashMarket(NEDomain domain) { // set domain reference this.domain = domain; // create servers vector this.nsvServers = new NashServer[this.N_SERVERS]; // init for(int iServer = 0; iServer < this.N_SERVERS; iServer++) this.nsvServers[iServer] = new NashServer(); } /* * Helper method. Sets server parameters accourding to domain */ private void SetServerParams() { for(int iServer = 0; iServer < this.N_SERVERS; iServer++){ // // Set server parameters: // this.nsvServers[iServer].dMinPrice = domain.min[iServer * 2]; this.nsvServers[iServer].dMinCapacity = domain.min[iServer * 2 + 1]; this.nsvServers[iServer].dMaxPrice = domain.max[iServer * 2]; this.nsvServers[iServer].dMaxCapacity = domain.max[iServer * 2 + 1]; } } /* * Calculates Nash Equilibrum for specified Point object */ public double CalculateEquilibrum(Point pt) { // // MATHS: NE = abs[U1sb(xSelfBest, ySelfBest, x2, y2, x3, y3) - // U1(x1, y1, x2, y2, x3, y3)] + abs[U2sb(...) - U2(...)] + // abs[U3sb(...) - U3(...)]: // where: UXsb - each server`s max profit. if he brakes the contract, // UX - each servers contract-based profit. // // Calculate each server`s profit with GMJ passed parameters. RunMarket(pt); // save each server`s profit: double[] dvEachServerUnbrokenProfit = new double[this.N_SERVERS]; double[] dvEachServerBrokenProfit = new double[this.N_SERVERS]; for(int iServer = 0; iServer < this.N_SERVERS; iServer++) dvEachServerUnbrokenProfit[iServer] = dvEachServerBrokenProfit[iServer] = this.nsvServers[iServer].GetProfit(this.N_CLIENTS, this.D_AVG_CLIENT_COME); // now, break the contract. Search for max profits. for(int iServer = 0; iServer < this.N_SERVERS; iServer++){ // iterate through prices (maths: ySelfBest[iServer]) for(double dCurrPrice = this.nsvServers[iServer].dMinPrice; dCurrPrice <= this.nsvServers[iServer].dMaxPrice; dCurrPrice += this.nsvServers[iServer].GetPriceStep()){ // iterate through capacities (maths: xSelfBest[iServer]) for(double dCurrCap = this.nsvServers[iServer].dMinCapacity; dCurrCap <= this.nsvServers[iServer].dMaxCapacity; dCurrCap += this.nsvServers[iServer].GetCapacityStep()){ // Create new market state: Point ptNewPoint = new Point(pt); ptNewPoint.x[iServer * 2] = dCurrPrice; ptNewPoint.x[iServer * 2 + 1] = dCurrCap; // look what happens: RunMarket(ptNewPoint); // save profit if this state profit exceeds previous profit(s) if(this.nsvServers[iServer].GetProfit(this.N_CLIENTS, this.D_AVG_CLIENT_COME) > dvEachServerBrokenProfit[iServer]) dvEachServerBrokenProfit[iServer] = this.nsvServers[iServer].GetProfit(this.N_CLIENTS, this.D_AVG_CLIENT_COME); } // dCurrCap } // dCurrPrice } // iServer /* // debug for(int iServer = 0; iServer < this.N_SERVERS; iServer++) System.out.println(iServer + "th sever`s unbr profit " + dvEachServerUnbrokenProfit[iServer] + " broken profit " + dvEachServerBrokenProfit[iServer]); */ // Calculate difference: double dDifference = 0.0; for(int iServer = 0; iServer < this.N_SERVERS; iServer++) dDifference += Math.abs(dvEachServerBrokenProfit[iServer] - dvEachServerUnbrokenProfit[iServer]); return dDifference;// return 0.0; } /* * Helper method. Restarts market and sets servers parameters to passed by GMJ */ private void RestartMarket(Point pt) { // set domain variables SetServerParams(); // restart time this.dCurrentTime = 0.0; for(int iServer = 0; iServer < this.N_SERVERS; iServer++){ // restart servers this.nsvServers[iServer].RestartServer(); // set GMJ passed variables this.nsvServers[iServer].SetServicePrice(pt.x[iServer * 2]); this.nsvServers[iServer].SetServerCapacity(pt.x[iServer * 2 + 1]); } } /* * Helper method. Restarts market and shares N_CLIENTS between servers */ private void RunMarket(Point pt) { // Restart market RestartMarket(pt); // share N_CLIENTS between servers and going away for(int iClient = 0; iClient < this.N_CLIENTS; iClient++){ // calculate current time. this.dCurrentTime += (-1.0 / this.D_AVG_CLIENT_COME) * Math.log(1.0 - Math.random()); // Serve clients for(int iServer = 0; iServer < this.N_SERVERS; iServer++) this.nsvServers[iServer].ServeClient(this.dCurrentTime); // Choose best server int iBestSrv = ClientChooseBestServer(); if(iBestSrv == -1) continue; // Client goes away // Chosen server accepts client this.nsvServers[iBestSrv].AcceptClient(this.dCurrentTime); } /* // debug for(int iServer = 0; iServer < this.N_SERVERS; iServer++){ System.out.println(iServer + " th server: cl. in queue: " + this.nsvServers[iServer].GetClientsInQueue() + " clients served " + this.nsvServers[iServer].GetClientsServed()); System.out.println(iServer + " th server service price: " + this.nsvServers[iServer].GetInitialServicePrice() + " total price: " + this.nsvServers[iServer].GetTotalServicePrice()); }*/ } /* * Helper method. Client choose best server or goes away */ private int ClientChooseBestServer() { // -1 indicates what client goes away. int iBest = 0; double dTotalPrice = this.nsvServers[0].GetTotalServicePrice(); // look for minimal total price for(int iServer = 1; iServer < this.N_SERVERS; iServer++){ if(dTotalPrice > this.nsvServers[iServer].GetTotalServicePrice()){ dTotalPrice = this.nsvServers[iServer].GetTotalServicePrice(); iBest = iServer; } } if(this.D_MAX_CLIENT_CAN_PAY < dTotalPrice) return -1; // Go away // // TODO Implement random server selection. But im not sure it`s really needed // return iBest; } }; //********************************** // NashServer model 1 impl.********* //********************************** class NashServer { private int nClientsServed = 0; // how many clients were served private double dServicePrice = 0.0; // service price private double dServerCapacity = 1.0; // server capacity // during market run, current time increases. Theese two vectors // are representing queue private Vector vecTimesClientsWait = new Vector(0, 10); private Vector vecTimesClientsGoAway = new Vector(0, 10); // change theese public int nPricesCnt = 10; public int nCapacitiesCnt = 10; // domain variables public double dMinPrice = 0.0; public double dMinCapacity = 0.0; public double dMaxPrice = 10.0; public double dMaxCapacity = 10.0; public void RestartServer() { this.nClientsServed = 0; // reset queue. this.vecTimesClientsWait = new Vector(0, 10); this.vecTimesClientsGoAway = new Vector(0, 10); } public void ServeClient(double dCurrentTime) { if(this.vecTimesClientsWait.size() == 0) return; // serve client if he should be if(dCurrentTime >= (((Double)this.vecTimesClientsGoAway.elementAt(0)).doubleValue())){ this.nClientsServed++; // remove client from queue: this.vecTimesClientsWait.removeElementAt(0); this.vecTimesClientsGoAway.removeElementAt(0); } } public void AcceptClient(double dCurrentTime) { // generate this clients serve time double dTimeToWait = (-1.0 / this.dServerCapacity) * Math.log(1.0 - Math.random()); //this.vecTimesClientsWait.addElement(new Double(dTimeToWait)); // calculate total time to wait double dTotalTimeToWait = dTimeToWait; if(this.vecTimesClientsWait.size() != 0){ // if there are clients in queue, calculate, // then they`ll be served: for(int iClient = 0; iClient < this.vecTimesClientsWait.size(); iClient++) dTotalTimeToWait += ((Double)this.vecTimesClientsWait.elementAt(iClient)).doubleValue(); /* //TODO: imagine what some time is ellapsed after first client in queue stand first. // this should be taken in account. // substract by time ellapsed: double dEllapsed = 0.0; if(((Double)this.vecTimesClientGoAway.elementAt(0)).doubleValue() < dCurrentTime) dEllapsed //dTotalTimeToWait -= (dCurrentTime - ((Double)this.vecTimesOfCome.elementAt(0)).doubleValue()); */ } // save this client`s time of quit (this is the time he should wait to be served) this.vecTimesClientsGoAway.addElement(new Double(dTotalTimeToWait + dCurrentTime)); // save this client`s time to wait this.vecTimesClientsWait.addElement(new Double(dTimeToWait)); /* Debug for(int iClient = 0; iClient < this.vecTimesClientsWait.size(); iClient++){ System.out.println(iClient + " th client wait time " + ((Double)this.vecTimesClientsWait.elementAt(iClient)).doubleValue() + " time of quit " + ((Double)this.vecTimesClientsGoAway.elementAt(iClient)).doubleValue()); } */ } public double GetTotalServicePrice() { return this.dServicePrice + (this.vecTimesClientsWait.size() / this.dServerCapacity); } public int GetClientsInQueue(){return this.vecTimesClientsWait.size();} public int GetClientsServed(){return this.nClientsServed;} public double GetInitialServicePrice(){return this.dServicePrice;} public double GetProfit(int nClientsTotal, double dAvgClientCome) { return (((double)this.nClientsServed) / ((double)nClientsTotal / dAvgClientCome)) * this.dServicePrice - this.dServerCapacity; } public double GetCapacityStep(){return (this.dMaxCapacity - this.dMinCapacity) / (double)this.nCapacitiesCnt;} public double GetPriceStep(){return (this.dMaxPrice - this.dMinPrice) / (double)this.nPricesCnt;} public void SetServerCapacity(double dNewCapacity){this.dServerCapacity = dNewCapacity;} public void SetServicePrice(double dNewPrice){this.dServicePrice = dNewPrice;} }; ///////////////////////////////////////////////////// class NEDomain extends DomainWithConstraint { // // Custom parameters // // public static final String []dimensions={ "1st Price", "1st Server Capacity", "2nd Price", "2nd Server Capacity", "3rd Price", "3rd Server Capacity" }; public String[] dimensions() {return dimensions;} NEDomain() { // set default parameters // odd: price // even: capacity min[0] = min[1] = min[2] = min[3] = min[4] = min[5] = 1.0; max[0] = max[1] = max[2] = max[3] = max[4] = max[5] = 10.0; defaultPoint.x[0] = defaultPoint.x[1] = defaultPoint.x[2] = defaultPoint.x[3] = defaultPoint.x[4] = defaultPoint.x[5] = ((min[0] + max[0]) / 2.0); } }; public class NETask extends AbstractTask implements TaskWithAnalyzers { private NEDomain domain=new NEDomain(); private NashMarket nmMarket; public NETask() { nmMarket = new NashMarket(domain); } public void customize (PropertyManager manager) { } public Domain domain() {return domain;} public double f(Point pt) { return this.nmMarket.CalculateEquilibrum(pt);; } public Class[] analyzers () throws ClassNotFoundException { Class spectrumClass=Class.forName("lt.ktu.gmj.analysis.Spectrum"); return new Class[]{ spectrumClass }; } };