Package jmt.analytical

Source Code of jmt.analytical.SolverDispatcher$SolverListener

/**   
  * Copyright (C) 2006, Laboratorio di Valutazione delle Prestazioni - Politecnico di Milano

  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.

  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.

  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */

package jmt.analytical;

import java.io.File;

import jmt.common.exception.InputDataException;
import jmt.common.exception.SolverException;
import jmt.framework.data.ArrayUtils;
import jmt.framework.xml.XMLUtils;
import jmt.gui.exact.ExactConstants;
import jmt.gui.exact.ExactModel;

import org.xml.sax.SAXException;

/**
* Server side of the solver interface.<br>
* This object takes a model, instantiates the correct solver, and solves it.<br>
* Should probably be rewritten using a different data structure to hold model information
*
* @author unknown, Bertoli Marco (what-if analysis)
*/
public class SolverDispatcher {

  private static final boolean DEBUG = true;
  private static final boolean PRINTMODEL = false;

  private boolean stopped = false;

  private XMLUtils xmlUtils;
  /** Used to notify when a computation ends */
  private SolverListener listener;

  public SolverDispatcher() {
    xmlUtils = new XMLUtils();
  }

  /**
   * Solves the model in file.
   * @throws jmt.common.exception.SolverException if there were errors operation was not successful
   */
  public void solve(File file) throws SolverException, InputDataException {
    ExactModel model = new ExactModel();
    try {
      if (!model.loadDocument(xmlUtils.loadXML(file))) {
        fail("Error loading model from tempfile", null);
      }
    } catch (SAXException e) {
      fail("XML parse error in tempfile", e);
    } catch (Exception e) {
      fail("Error loading model from tempfile", e);
    }

    if (PRINTMODEL) {
      System.out.println(model);
    }

    solve(model);

    if (PRINTMODEL) {
      System.out.println(model);
    }

    try {
      if (!xmlUtils.saveXML(model.createDocument(), file)) {
        fail("Error saving solved model to tempfile", null);
      }
    } catch (SAXException e) {
      fail("XML parse error in tempfile", e);
    } catch (Exception e) {
      fail("Error saving solved model to tempfile", e);
    }

  }

  /**
   * Stops What-if analysis and invalidates results
   */
  public void stop() {
    stopped = true;
  }

  /**
   * Solves input model. This method will look for what-if analysis data and
   * perform a what-if analysis if requested.
   * <br>
   * Author: Bertoli Marco
   * @param model model to be solved
   * @throws SolverException if something goes wrong during solution
   * @throws InputDataException if some input data are malformed
   */
  public void solve(ExactModel model) throws SolverException, InputDataException {
    stopped = false;
    model.resetResults();
    // Solves normal models
    if (!model.isWhatIf()) {
      finalDispatch(model, 0);
    }
    // Now solves what-if models
    else {
      // Arrival rates what-if analysis
      if (model.getWhatIfType().equalsIgnoreCase(ExactConstants.WHAT_IF_ARRIVAL)) {
        whatIfArrival(model);
      }
      // Customers number what-if analysis
      else if (model.getWhatIfType().equalsIgnoreCase(ExactConstants.WHAT_IF_CUSTOMERS)) {
        whatIfCustomers(model);
      }
      // Service demands what-if analysis
      else if (model.getWhatIfType().equalsIgnoreCase(ExactConstants.WHAT_IF_DEMANDS)) {
        whatIfDemands(model);
      }
      // Population mix what-if analysis
      else if (model.getWhatIfType().equalsIgnoreCase(ExactConstants.WHAT_IF_MIX)) {
        whatIfMix(model);
      }
    }
  }

  public void finalDispatch(ExactModel model, int iteration) throws SolverException, InputDataException {

    /* disable all change-checking */
    model.discardChanges();
    model.setChanged();
    ModelFESCApproximator fesc = new ModelFESCApproximator(model, iteration);
    try {
      /** Edited by Abhimanyu Chugh **/
      if (model.isClosed() && model.isWhatIf() && model.isWhatifAlgorithms()) {
        SolverAlgorithm origAlgType = model.getAlgorithmType();
        double origAlgTolerance = model.getTolerance();
        for (SolverAlgorithm algo : model.getWhatifAlgorithms()) {
          model.setAlgorithmType(algo);
          model.setTolerance(model.getWhatifAlgorithmTolerance(algo));
          if (model.isMultiClass()) {
            solveMulti(fesc.getModelToBeSolved(), iteration);
          } else {
            solveSingle(fesc.getModelToBeSolved(), iteration);
          }
        }
        model.setAlgorithmType(origAlgType);
        model.setTolerance(origAlgTolerance);
      } else {
        if (model.isMultiClass() || model.isOpen()) {
          solveMulti(fesc.getModelToBeSolved(), iteration);
        } else {
          solveSingle(fesc.getModelToBeSolved(), iteration);
        }
      }
      // set boolean to notify results have been computed
      model.setResultsBooleans(true);
      /** End **/
     
      // Notify termination of current model solution
      if (listener != null) {
        listener.computationTerminated(iteration);
      }
    } catch (InputDataException rse) {
      throw rse;
    } catch (SolverException se) {
      throw se;
    } catch (Exception e) {
      fail("Unhandled exception", e);
    }
    fesc.processModelAfterSolution();
  }

  private void fail(String message, Throwable t) throws SolverException {
    if (DEBUG && t != null) {
      t.printStackTrace();
    }
    StringBuffer s = new StringBuffer(message);
    if (t != null) {
      s.append("\n");
      s.append(t.toString());
    }

    throw new SolverException(s.toString(), t);
  }

  private void solveSingle(ExactModel model, int iteration) throws Exception, InputDataException {

    int stations = model.getStations();
    Solver solver = null;
    /** Edited by Abhimanyu Chugh **/
    SolverAlgorithm algorithmType = model.getAlgorithmType();
    int algIterations = 0;
    /** End **/

    //init
    String[] names = model.getStationNames();
    int[] types = mapStationTypes(model.getStationTypes());
    double[][] servicetimes = (ArrayUtils.extract13(model.getServiceTimes(), 0));

    //no supplemental copy here since extract13 already copies the first level of the array
    adjustLD(servicetimes, types);
    double[] visits = ArrayUtils.extract1(model.getVisits(), 0);

    try {
      if (model.isClosed()) {
        //single closed
        int pop = model.getMaxpop();
        //First of all controls that the closed class has population greater than 0.
        //Otherwise throws a InputDataException
        if (pop <= 0) {
          //error: population is not greater than 0.0
          throw new InputDataException("Population must be greater than zero");
        }
       
        /** Edited by Abhimanyu Chugh **/
        if (SolverAlgorithm.EXACT.equals(algorithmType)) {
          solver = new SolverSingleClosedMVA(pop, stations);
        /*} else if (SolverAlgorithm.MoM.equals(algorithmType)) {
          solver = new SolverSingleClosedMoM(pop, stations);
        */} else {
          SolverAlgorithm algType = model.getAlgorithmType();
          solver = new SolverSingleClosedAMVA(pop, stations, algType, model.getTolerance());
        }
        /** End **/
       
        if (!solver.input(names, types, servicetimes, visits)) {
          /** Edited by Abhimanyu Chugh **/
          String algName = algorithmType.toString().replace(" ", "").replace("-", "");
          fail("Error initializing " + algName + "SingleSolver", null);
          //fail("Error initializing MVASolver", null);
          /** End **/
        }
      } else {
        /** Edited by Abhimanyu Chugh **/
        algorithmType = SolverAlgorithm.EXACT;
        /** End **/
        //TODO this is not used any more (multi solver is used instead)
        /* single open */
        double lambda = (model.getClassData())[0];
        //First of all controls that the open class has rate greater than 0.
        //Otherwise throws a InputDataException
        if (lambda <= 0) {
          //error: rate is not greater than 0.0
          throw new InputDataException("Arrival rate must be greater than zero");

        }
        solver = new SolverSingleOpen(model.getClassData()[0], stations);
        if (!solver.input(names, types, servicetimes, visits)) {
          fail("Error initializing OpenSolver", null);
        }
      }
    } catch (Exception e) {
      fail("Error initializing SingleClass solver", e);
    }
    //controls processing capacity
    if (!solver.hasSufficientProcessingCapacity()) {
      throw new InputDataException("One or more resources are in saturation. Decrease arrival rates or service demands.");
    }

    /* solve */
    solver.solve();
   
    /** Edited by Abhimanyu Chugh **/
    if (solver instanceof SolverSingleClosedAMVA) {
      algIterations = ((SolverSingleClosedAMVA) solver).getIterations();
    }
    /** End **/

    /* solution */
    double[][] ql = ArrayUtils.makeFilled(stations, 1, -1);
    ArrayUtils.insert1(ql, solver.getQueueLen(), 0);

    double[][] tp = ArrayUtils.makeFilled(stations, 1, -1);
    ArrayUtils.insert1(tp, solver.getThroughput(), 0);

    double[][] rt = ArrayUtils.makeFilled(stations, 1, -1);
    ArrayUtils.insert1(rt, solver.getResTime(), 0);

    double[][] util = ArrayUtils.makeFilled(stations, 1, -1);
    ArrayUtils.insert1(util, solver.getUtilization(), 0);

    /** Edited by Abhimanyu Chugh **/
    model.setResults(algorithmType, algIterations, ql, tp, rt, util, iteration);
    /** End **/
  }

  private void solveMulti(ExactModel model, int iteration) throws SolverException, InputDataException {
    if (model.isLd()) {
      throw new SolverException("Multiclass solver does not support LD stations");
    }

    int classes = model.getClasses();
    int stations = model.getStations();

    String[] stationNames = model.getStationNames();
    int[] stationTypes = mapStationTypes(model.getStationTypes());
    double[] classData = model.getClassData();
    double[][][] serviceTimes = model.getServiceTimes();
    double[][] visits = model.getVisits();
    int[] classPop = ArrayUtils.toInt(classData);
   
    /** Edited by Abhimanyu Chugh **/
    SolverAlgorithm algorithmType = model.getAlgorithmType();
    int algIterations = 0;
    /** End **/

    SolverMulti solver = null;

    //First of all controls that all classes have population or rate greater than 0.
    //Otherwise throws a InputDataException
    for (double element : classData) {
      if (element <= 0) {
        //error: population or rate not greater than 0.0
        //prepare message according to model type (mixed, open or closed)

        if (model.isMixed()) {
          //mixed model -> populations or rates
          throw new InputDataException("Populations and arrival rates must be greater than zero");
        } else if (model.isOpen()) {
          //open model -> rates
          throw new InputDataException("Arrival rates must be greater than zero");
        } else {
          //closed model -> populations
          throw new InputDataException("Populations must be greater than zero");
        }

      }
    }

    /* init */
    try {
      if (model.isOpen()) {
        /** Edited by Abhimanyu Chugh **/
        algorithmType = SolverAlgorithm.EXACT;
        /** End **/
        solver = new SolverMultiOpen(classes, stations, model.getClassData(), model.getStationServers());
        if (!solver.input(stationNames, stationTypes, serviceTimes, visits)) {
          fail("Error initializing SolverMultiOpen", null);
        }
      } else {
        if (model.isClosed()) {
          /** Edited by Abhimanyu Chugh **/
          if (SolverAlgorithm.EXACT.equals(algorithmType)) {
            SolverMultiClosedMVA closedsolver = new SolverMultiClosedMVA(classes, stations);
            if (!closedsolver.input(stationNames, stationTypes, serviceTimes, visits, classPop)) {
              fail("Error initializing MVAMultiSolver", null);
            }
            solver = closedsolver;
          } else if (SolverAlgorithm.RECAL.equals(algorithmType)) {
            int nThreads = 1;
            SolverMultiClosedRECAL closedSolver = new SolverMultiClosedRECAL(classes, stations, classPop);
            if (!closedSolver.input(stationTypes, serviceTimes, visits, nThreads)) {
                fail("Error initializing RECALMultiSolver", null);
            }
            solver = closedSolver;
          } else if (SolverAlgorithm.MOM.equals(algorithmType)) {
            int nThreads = 1;
            SolverMultiClosedMoM closedSolver = new SolverMultiClosedMoM(classes, stations, classPop);
            if (!closedSolver.input(stationTypes, serviceTimes, visits, nThreads)) {
                fail("Error initializing MoMMultiSolver", null);
            }
            solver = closedSolver;
          } else if (SolverAlgorithm.COMOM.equals(algorithmType)) {
            int nThreads = 1;
            SolverMultiClosedCoMoM closedSolver = new SolverMultiClosedCoMoM(classes, stations, classPop);
            if (!closedSolver.input(stationTypes, serviceTimes, visits, nThreads)) {
                fail("Error initializing CoMoMMultiSolver", null);
            }
            solver = closedSolver;
          } else {
            double tolerance = model.getTolerance();
            SolverMultiClosedAMVA closerSolver = null;
            if (SolverAlgorithm.CHOW.equals(algorithmType)) {
              closerSolver = new SolverMultiClosedChow(classes, stations, classPop);
            } else if (SolverAlgorithm.BARD_SCHWEITZER.equals(algorithmType)) {
              closerSolver = new SolverMultiClosedBardSchweitzer(classes, stations, classPop);
            } else if (SolverAlgorithm.AQL.equals(algorithmType)) {
              closerSolver = new SolverMultiClosedAQL(classes, stations, classPop);
            } else {
              closerSolver = new SolverMultiClosedLinearizer(classes, stations, classPop, SolverAlgorithm.DESOUZA_MUNTZ_LINEARIZER.equals(algorithmType));
            }
            ((SolverMultiClosedAMVA)closerSolver).setTolerance(tolerance);
           
            if (!closerSolver.input(stationNames, stationTypes, serviceTimes, visits)) {
              String algName = algorithmType.toString().replace(" ", "").replace("-", "");
              fail("Error initializing " + algName + "MultiSolver", null);
            }
            solver = closerSolver;
          }
          /** End **/
     
        } else {
          //model is multiclass mixed
          /** Edited by Abhimanyu Chugh **/
          algorithmType = SolverAlgorithm.EXACT;
          /** End **/
          int[] classTypes = mapClassTypes(model.getClassTypes());

          SolverMultiMixed mixedsolver = new SolverMultiMixed(classes, stations);
          if (!mixedsolver.input(stationNames, stationTypes, serviceTimes, visits, classData, classTypes)) {
            fail("Error initializing SolverMultiMixed", null);
          }
          solver = mixedsolver;
        }
      }
    } catch (Exception e) {
      fail("Error initializing Multiclass solver", e);
    }
    if (!solver.hasSufficientProcessingCapacity()) {
      throw new InputDataException("One or more resources are in saturation. Decrease arrival rates or service demands.");
    }
   
    long start = System.currentTimeMillis();
   
    /* solution */
    solver.solve();
   
    /** Edited by Abhimanyu Chugh **/
    if (solver instanceof SolverMultiClosedAMVA) {
      algIterations = ((SolverMultiClosedAMVA) solver).getIterations();
    }
    /** End **/

    double[][] ql = ArrayUtils.resize2(solver.getQueueLen(), stations, classes, 0);

    double[][] tp = ArrayUtils.resize2(solver.getThroughput(), stations, classes, 0);

    double[][] rt = ArrayUtils.resize2(solver.getResTime(), stations, classes, 0);

    double[][] util = ArrayUtils.resize2(solver.getUtilization(), stations, classes, 0);

    /** Edited by Abhimanyu Chugh **/
    model.setResults(algorithmType, algIterations, ql, tp, rt, util, iteration);
    /** End **/
  }

  /**
   * Map station types from model constants to solver constants
   */
  private int[] mapStationTypes(int[] stationTypes) {
    int len = stationTypes.length;
    int[] res = new int[len];
    for (int i = 0; i < len; i++) {
      switch (stationTypes[i]) {
        case ExactConstants.STATION_LD:
          res[i] = Solver.LD;
          break;
        case ExactConstants.STATION_LI:
          res[i] = Solver.LI;
          break;
        case ExactConstants.STATION_DELAY:
          res[i] = Solver.DELAY;
          break;
        default:
          res[i] = -1;
      }
    }
    return res;
  }

  /**
   * Map class types from model constants to solver constants
   */
  private int[] mapClassTypes(int[] classTypes) {
    int len = classTypes.length;
    int[] res = new int[len];
    for (int i = 0; i < len; i++) {
      switch (classTypes[i]) {
        case ExactConstants.CLASS_OPEN:
          res[i] = SolverMulti.OPEN_CLASS;
          break;
        case ExactConstants.CLASS_CLOSED:
          res[i] = SolverMulti.CLOSED_CLASS;
          break;
        default:
          res[i] = -1;
      }
    }
    return res;
  }

  /*
   * To conserve memory, service times arrays for LI stations are "compressed" to a single value. This
   * method expands them back to full length (single class version)
   */
  private void expand(double[][] st, int pop) {
    if (pop == 1) {
      return;
    }
    int len1 = st.length;
    for (int i = 0; i < len1; i++) {
      if (st[i].length < pop) {
        st[i] = ArrayUtils.resize(st[i], pop, st[i][0]);
      }
    }
  }

  /*
     * To conserve memory, service times arrays for LI stations are "compressed" to a single value. This
     * method expands them back to full length (multiclass version)
     */
  private void expand(double[][][] st, int pop) {
    if (pop == 1) {
      return;
    }
    int len1 = st.length;
    for (int i = 0; i < len1; i++) {
      expand(st[i], pop);
    }
  }

  /** HACK: adds an itial zero to all LD stations */
  private void adjustLD(double[][] st, int[] types) {
    for (int i = 0; i < st.length; i++) {
      if (types[i] == Solver.LD) {
        st[i] = ArrayUtils.prepend0(st[i]);
      }
    }
  }

  /** HACK: adds an initial zero to all LD stations */
  private void adjustLD(double[][][] st, int[] types) {
    for (int i = 0; i < st.length; i++) {
      if (types[i] == Solver.LD) {
        for (int j = 0; j < st[i].length; j++) {
          st[i][j] = ArrayUtils.prepend0(st[i][j]);
        }
      }
    }
  }

  // --- What-if Analysis methods --- Bertoli Marco -------------------------------------
  /**
   * Performs a what-if analysis by changing arrival rates
   * @param model input model
   */
  private void whatIfArrival(ExactModel model) throws SolverException, InputDataException {
    // Sanity checks on input model.
    if (model.getWhatIfClass() >= 0 && model.getClassTypes()[model.getWhatIfClass()] != ExactConstants.CLASS_OPEN) {
      throw new InputDataException("Cannot change arrival rate of a closed class.");
    }
    if (model.isClosed()) {
      throw new InputDataException("Cannot change arrival rates in a closed model.");
    }

    // Values for what-if
    double[] values = model.getWhatIfValues();

    // Backup class datas
    double[] initials = model.getClassData().clone();

    // Iterates for what-if executions
    for (int i = 0; i < model.getWhatIfValues().length && !stopped; i++) {
      double[] current = initials.clone();
      // If this is one class only
      if (model.getWhatIfClass() >= 0) {
        current[model.getWhatIfClass()] = values[i];
      }
      // If this is all open classes
      else {
        for (int j = 0; j < current.length; j++) {
          if (model.getClassTypes()[j] == ExactConstants.CLASS_OPEN) {
            current[j] = initials[j] * values[i];
          }
        }
      }
      model.setClassData(current);

      // Checks if stopped
      if (stopped) {
        break;
      }

      // Now solves current model - we cannot interrupt this as it's not designed to be done.
      finalDispatch(model, i);
    }
    // Resets initial model
    model.setClassData(initials);
    // Results are ok if the process was not stopped.
    model.setResultsOK(!stopped);
  }

  /**
   * Performs a what-if analysis by changing number of customers
   * @param model input model
   */
  private void whatIfCustomers(ExactModel model) throws SolverException, InputDataException {
    // Sanity checks on input model.
    if (model.getWhatIfClass() >= 0 && model.getClassTypes()[model.getWhatIfClass()] != ExactConstants.CLASS_CLOSED) {
      throw new InputDataException("Cannot change number of customers of an open class.");
    }
    if (model.isOpen()) {
      throw new InputDataException("Cannot change number of customers in an open model.");
    }

    // Values for what-if
    double[] values = model.getWhatIfValues();

    // Backup class datas
    double[] initials = model.getClassData().clone();

    // Iterates for what-if executions
    int i;
    for (i = 0; i < model.getWhatIfValues().length && !stopped; i++) {
      double[] current = initials.clone();
      // If this is one class only
      if (model.getWhatIfClass() >= 0) {
        current[model.getWhatIfClass()] = values[i];
        // Check for not integer values
        if (Math.abs(current[model.getWhatIfClass()] - Math.rint(current[model.getWhatIfClass()])) > 1e-8) {
          throw new InputDataException("A fractional population value was assigned to class "
              + model.getClassNames()[model.getWhatIfClass()] + " during step " + i);
        }
        // Rounds number to avoid truncation problems
        current[model.getWhatIfClass()] = Math.round(current[model.getWhatIfClass()]);

      }
      // If this is all closed classes
      else {
        for (int j = 0; j < current.length; j++) {
          if (model.getClassTypes()[j] == ExactConstants.CLASS_CLOSED) {
            current[j] = initials[j] * values[i];
            // Check for not integer values
            if (Math.abs(current[j] - Math.rint(current[j])) > 1e-8) {
              throw new InputDataException("A fractional population value was assigned to class " + model.getClassNames()[j]
                  + " during step " + i);
            }
            // Rounds number to avoid truncation problems
            current[j] = Math.round(current[j]);
          }
        }
      }
      model.setClassData(current);

      // Checks if stopped
      if (stopped) {
        break;
      }

      // Now solves current model - we cannot interrupt this as it's not designed to be done.
      finalDispatch(model, i);
    }
    // Resets initial model
    model.setClassData(initials);
    // Results are ok if the process was not stopped.
    model.setResultsOK(!stopped);
  }

  /**
   * Performs a what-if analysis by changing service demands of a given station.
   * @param model input model
   */
  private void whatIfDemands(ExactModel model) throws SolverException, InputDataException {
    // Sanity checks on input model.
    if (model.getWhatIfStation() < 0 || model.getWhatIfStation() >= model.getStations()) {
      throw new InputDataException("Station for what-if analysis not specified.");
    }
    if (model.getStationTypes()[model.getWhatIfStation()] == ExactConstants.STATION_LD) {
      throw new InputDataException("Service Demands what-if analysis not supported on Load Dependent stations.");
    }

    // Values for what-if
    double[] values = model.getWhatIfValues();

    // Backup service times datas (note: we multiply only service times as it's the same of multiply service demands)
    double[][][] initials = ArrayUtils.copy3(model.getServiceTimes());

    // Saves what-if class and station indices
    int cl = model.getWhatIfClass();
    int st = model.getWhatIfStation();

    // Iterates for what-if executions
    int i;
    for (i = 0; i < values.length && !stopped; i++) {
      double[][][] current = ArrayUtils.copy3(initials);
      // If this is one class only
      if (cl >= 0) {
        if (model.getVisits()[st][cl] > 0) {
          current[st][cl][0] = values[i] / model.getVisits()[st][cl];
        } else {
          current[st][cl][0] = 0.0;
        }
      }
      // If this is all classes
      else {
        for (int j = 0; j < model.getClasses(); j++) {
          current[st][j][0] = initials[st][j][0] * values[i];
        }
      }
      model.setServiceTimes(current);

      // Checks if stopped
      if (stopped) {
        break;
      }

      // Now solves current model - we cannot interrupt this as it's not designed to be done.
      finalDispatch(model, i);
    }
    // Resets initial model
    model.setServiceTimes(initials);
    // Results are ok if the process was not stopped.
    model.setResultsOK(!stopped);
  }

  /**
   * Performs a what-if analysis by changing population mix
   * @param model input model
   */
  private void whatIfMix(ExactModel model) throws SolverException, InputDataException {
    // First and second closed class for population mix what-if
    int class1, class2 = -1;
    class1 = model.getWhatIfClass();
    if (class1 < 0) {
      throw new InputDataException("Class not specified for population mix what-if analysis.");
    }
    // Find second class
    for (int i = 0; i < model.getClasses(); i++) {
      if (model.getClassTypes()[i] == ExactConstants.CLASS_CLOSED && i != class1) {
        if (class2 < 0) {
          class2 = i;
        } else {
          throw new InputDataException("Only models with two closed classes are supported. More than two classes detected.");
        }
      }
    }
    if (class2 < 0) {
      throw new InputDataException("Only models with two closed classes are supported. Only one classes detected.");
    }

    // Values for what-if
    double[] values = model.getWhatIfValues();

    // Backup class datas
    double[] initials = model.getClassData().clone();

    // Value for total number of customer
    double N = initials[class1] + initials[class2];

    // Iterates for what-if executions
    int i;
    for (i = 0; i < model.getWhatIfValues().length && !stopped; i++) {
      double[] current = initials.clone();
      current[class1] = values[i] * N;
      current[class2] = (1 - values[i]) * N;
      // Check for not integer values
      if (Math.abs(current[class1] - Math.rint(current[class1])) > 1e-8) {
        throw new InputDataException("A fractional population value was assigned to class " + model.getClassNames()[class1] + " during step "
            + i);
      } else if (Math.abs(current[class2] - Math.rint(current[class2])) > 1e-8) {
        throw new InputDataException("A fractional population value was assigned to class " + model.getClassNames()[class2] + " during step "
            + i);
      }
      // Rounds number to avoid truncation problems
      current[class1] = Math.round(current[class1]);
      current[class2] = Math.round(current[class2]);

      model.setClassData(current);

      // Checks if stopped
      if (stopped) {
        break;
      }

      // Now solves current model - we cannot interrupt this as it's not designed to be done.
      finalDispatch(model, i);
    }
    // Resets initial model
    model.setClassData(initials);
    // Results are ok if the process was not stopped.
    model.setResultsOK(!stopped);
  }

  // ------------------------------------------------------------------------------------

  // ---- Callbacks ---------------------------------------------------------------------
  /**
   * Adds a solver listener to be notified when computation of an iteration terminates.
   * This is useful for notification of a progress window. Only one listener is allowed.
   * @param listener listener to be added or null to remove previous one.
   */
  public void addSolverListener(SolverListener listener) {
    this.listener = listener;
  }

  /**
   * Listener used to notify when computation of a model is terminated
   */
  public interface SolverListener {
    /**
     * This method is called each time the computation of a model is terminated
     * @param num number of computated model (used for iterated solutions)
     */
    public void computationTerminated(int num);
  }
  // ------------------------------------------------------------------------------------

}
TOP

Related Classes of jmt.analytical.SolverDispatcher$SolverListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.