 
/*
 * $Log: Network.java,v $
# Revision 1.17  1996/06/21  21:07:47  hma
# minor typos
#
# Revision 1.16  1996/06/21  20:49:01  hma
# added calculateLinkDimensionAndLowerBound().
# added lowerBound, cost, getLowerBound(), getCost().
#
# Revision 1.15  1996/05/23  03:43:02  hma
# added dimensioningLinks(), getLowerBound(), and change switches and links to Vectors.
#
# Revision 1.14  1996/05/13  16:45:32  inder
# defined function removeLink()
#
# Revision 1.13  1996/05/13  15:12:31  inder
# added removeSwitch() function.
#
# Revision 1.12  1996/05/12  09:50:12  inder
# reflected change in the constructor of Switch class.
#
# Revision 1.11  1996/05/12  08:57:36  inder
# Corrected exception handling.
#
# Revision 1.10  1996/04/29  09:04:44  inder
# added getBounds() function. Removed diagnostic println's.
#
# Revision 1.9  1996/04/29  08:02:27  rlj1
# Added addLink() and set up findBestCenterFromAscii() to add the links
#
# Revision 1.8  1996/04/28  20:47:15  rlj1
# Added bestCenter...()
#
# Revision 1.7  1996/04/22  17:02:44  rlj1
# Debugged the bestStarCenter and getDistance procedures
#
# Revision 1.6  1996/04/15  05:48:08  inder
# removed unclean way of creating Sets of links and switches.
#
# Revision 1.5  1996/04/15  04:32:35  rlj1
# added the best star algorithm
#
# Revision 1.4  1996/04/14  22:45:56  inder
# made changes arising due to changed constructor definition of Set
# class.
#
# Revision 1.3  1996/04/14  16:40:12  rlj1
# made streamble
#
# Revision 1.2  1996/03/26  06:29:33  inder
# made switches and lins public.
#
# Revision 1.1  1996/03/18  18:51:00  rlj1
# Initial revision
#
 */
//////////////////////////////////////////////////
package network;

// Standard packages.
import java.util.*;
import java.lang.*;
import java.io.*;
import java.awt.Rectangle;

// Packages specific to network design tool.
import lp.*;
import general.Set;
import general.GenericException;
import general.GeneralProperties;
import physical.Place;
//////////////////////////////////////////////////
public class Network {
// A collection of Switches and their interconnection by Links.
public Set switches;
public Set links;
public GeneralProperties prop;

private String name;
private int numS=0;
private int numL=0;
  
private int max = 100; //a hack for now...
private Switch sarray[] = new Switch[max];
private double distances[][] = new double[max][max];
  
private Rectangle bounds;	    // Keeps extents of this network.
private double lowerBound = Double.MAX_VALUE; // lower bound of the link costs
private double cost = 0; // cost of this network.

  /* Vector v; */
//************************************************    
public Network(String Name, int numlinks, int numswitches) throws
ClassNotFoundException { 
  name = Name;
  switches = new Set(Class.forName("network.Switch")); 
  links = new Set(Class.forName("network.Link")); 
  constraints = new Set(Class.forName("network.SetPairConstraint"));
  bounds = new Rectangle(0, 0, 0, 0);
  switchVec = new Vector();
  linkVec = new Vector();
}

//************************************************
// create a new network from name
//
public Network(String Name) throws
ClassNotFoundException { 
  name = Name;
  switches = new Set(Class.forName("network.Switch")); 
  links = new Set(Class.forName("network.Link")); 
  constraints = new Set(Class.forName("network.SetPairConstraint"));
  bounds = new Rectangle(0, 0, 0, 0);
  switchVec = new Vector();
  linkVec = new Vector();
}

//************************************************
// create a network from the input file
//
public Network(FileInputStream f) throws IOException, GenericException, 
ClassNotFoundException
{
  switches = new Set(Class.forName("network.Switch")); 
  links = new Set(Class.forName("network.Link")); 
  constraints = new Set(Class.forName("network.SetPairConstraint"));
  bounds = new Rectangle(0, 0, 0, 0);
  switchVec = new Vector();
  linkVec = new Vector();

  Switch s;
  Link l;
  SetPairConstraint spc;

  StreamTokenizer stk = new StreamTokenizer(f);
  stk.slashStarComments(true);
  stk.slashSlashComments(true);
  
  int tokenType;
  
  // get the name of the network
  while( stk.nextToken() != StreamTokenizer.TT_WORD );
  name = stk.sval;
    
  while ( (tokenType = stk.nextToken()) != StreamTokenizer.TT_EOF ) {
    if (tokenType == '<' ) {
      stk.pushBack();
      s = new Switch(stk);
      addSwitch(s);
    }
    else if (tokenType == '[' ) {
      stk.pushBack();
      l = readLink(stk);
      addLink(l);
    }
    else if (tokenType == '{' ) {
      stk.pushBack();
      spc = readSetPairConstraint(stk);
      addConstraint(spc);
    }
  }
}

//*******************************************
// calculate link dimensions and lower bounds
//
public void calculateLinkDimensionAndLowerBound() {
  getAllPairsShortestPathes();
  dimensioningLinks();
  this.lowerBound = this.calculateLowerBound();  
}

//*******************************************
public double getCost() {
  return cost;
}

//*******************************************
public double getLowerBound() {
  return lowerBound;
}

//*******************************************
// read a set of numbers from {n1, n2, ...}
//
private Set readSwitchSet(StreamTokenizer stk)
throws IOException, ClassNotFoundException {
  int tokenType;
  Switch s;
  Set set = new Set(Class.forName("network.Switch"));
  while (stk.nextToken() != '{');
  while ( (tokenType = stk.nextToken()) != '}' ) {
    if (tokenType == StreamTokenizer.TT_WORD
	&& ((s = (Switch)switches.get(stk.sval)) != null))
      set.put(s.getName(), s);
  }
  return set;
}

//******************************************
// read constraint of the network from input file
// called only by the constructor
// format :
// {name {set1} {set2}(optional) out in}
private SetPairConstraint readSetPairConstraint(StreamTokenizer stk)
throws IOException, ClassNotFoundException, GenericException {
  int tokenType;
  Set swtSet1, swtSet2 = null;
  String name;
  double out, in;

  // read the starting '{'
  while (stk.nextToken() != '{');

  // read the constraint name;
  while (stk.nextToken() != StreamTokenizer.TT_WORD);
  name = stk.sval;

  // read the first set in the constraint
  swtSet1 = readSwitchSet(stk);
  
  while ( (tokenType = stk.nextToken()) != StreamTokenizer.TT_NUMBER 
	 && tokenType != '{' );
  
  // read the second set in the constraint, if there is a second set
  if (tokenType == '{') {
    stk.pushBack();
    swtSet2 = readSwitchSet(stk);
  }
  else // we have over read the next value, it should be "out", push it back
    stk.pushBack();
  
  // get the value of out flow
  while ( stk.nextToken() != StreamTokenizer.TT_NUMBER );
  out = stk.nval;

  // get the value of in flow
  while ( stk.nextToken() != StreamTokenizer.TT_NUMBER );
  in = stk.nval;

  // read the closing "}"
  while (stk.nextToken() != '}');
  
  if (swtSet1.size() == 0)
    throw (new GenericException("set size zero in SetPairConstraint"));

  SetPairConstraint spc;
  if(swtSet2 == null) {
    spc = new SetPairConstraint(name, swtSet1, in, out);
    spc.setBValue(switches);
  }
  else
    spc = new SetPairConstraint(name, swtSet1, swtSet2, in, out);

  return spc;
}

//***************************************
public void addConstraint(SetPairConstraint spc) {
  constraints.put(spc.getName(), spc);
}

//***************************************
// called only by constructor
// Link format:
// [name left_switch_name right_switch_name length]
//
private Link readLink(StreamTokenizer stk) throws IOException{
  int tokenType;
  String leftSwitch, rightSwitch;
  double length = 0;
  String name;
  Link l;

  // get the starting '['
  while (stk.nextToken() != '[');

  // get the name
  while (stk.nextToken() != StreamTokenizer.TT_WORD);
  name = stk.sval;

  // get the name of left switch  
  while (stk.nextToken() != StreamTokenizer.TT_WORD);
  leftSwitch = stk.sval;
  
  // get the name of right switch
  while (stk.nextToken() != StreamTokenizer.TT_WORD);
  rightSwitch = stk.sval;
  
  while ( (tokenType = stk.nextToken()) != StreamTokenizer.TT_NUMBER &&
	 tokenType != ']');
  if (tokenType == StreamTokenizer.TT_NUMBER) {
    // get the number, it would be the length of the link
    length = stk.nval;
    // get the closing braket
    while ( stk.nextToken() != ']' );
  }

  // and length is not less than the Euclid distance

  Switch s1 = (Switch)switches.get(leftSwitch);
  Switch s2 = (Switch)switches.get(rightSwitch);
  if (length != 0)
    l = new Link(name, s1, s2, length);
  else
    l = new Link(name, s1, s2);
  return l;
}

//************************************************    
public String getName(){
  return name;
}
//************************************************    
public Switch getSwitch(int n) {
  return sarray[n];
}
//************************************************    
public int numSwitches() {
  return numS;
}
//************************************************    
public int numLinks() {
  return numL;
}
//************************************************    
public void addSwitch(Switch s) throws GenericException {
    Integer i = new Integer(numS);
    sarray[numS] = s;
    switches.put(s.getName(), s); 
    numS = numS + 1; 
    switchVec.addElement(s);
    
    int sx = (int) s.getX();
    int sy = (int) s.getY();
    if(sx < bounds.x)
	bounds.x = sx;
    if(sy < bounds.y)
      bounds.y = sy;
    if(sx > bounds.x + bounds.width)
      bounds.width = sx - bounds.x;
    if(sy > bounds.y + bounds.height)
	bounds.height = sy - bounds.y;

    // update set pair constraints. for constraints with only one set (not set pair),
    // when new switches are added, the complement set should be updated.
    Enumeration e = constraints.elements();
    SetPairConstraint c;
    for (;e.hasMoreElements();) {
      c = (SetPairConstraint)e.nextElement();
      if (c.noSetB == true) 
	c.setBValue(switches);
    }
  }

//************************************************    
public void removeSwitch(Switch s) {
  if(switches.remove(s.getName()) != null) { // Check if s is in Set switches.
    --numS;
    
    switchVec.removeElement(s);
    
    // A hack for now. Got to repair sarray[] and bounds properly.
    numS = 0;
    Switch s1;
    int sx;
    int sy;
    bounds = new Rectangle(0, 0, 0, 0);
    for(Enumeration e=switches.elements(); e.hasMoreElements(); ) {
      s1 = (Switch) e.nextElement();
      sarray[numS] = s1;
      ++numS;
      // Rechecking bounds.
      sx = (int) s1.getX();
      sy = (int) s1.getY();
      if(sx < bounds.x)
	bounds.x = sx;
      if(sy < bounds.y)
	bounds.y = sy;
      if(sx > bounds.x + bounds.width)
	bounds.width = sx - bounds.x;
      if(sy > bounds.y + bounds.height)
	bounds.height = sy - bounds.y;
    }
  }
}
//************************************************
public void addLink(Link l) throws GenericException {
  try {
    Integer i = new Integer(numL);
    links.put(l.getName(), l); 
    linkVec.addElement(l);
    numL = numL + 1; 
    //  Should also verify if link l's endpoints are also switches of
    //  network. 
  }
  catch (Exception e) {
    throw(new GenericException(this, "In addLink(): " + e.getMessage()));
  } 
}
//************************************************
public void removeLink(Link l) {
  if(links.remove(l.getName()) != null) { // Check if l is in Set links.
    --numL;
    linkVec.removeElement(l);
  }
}
//************************************************
  /* Following are the best star algorithm methods */
public double getDistance(Switch s1, Switch s2) { 
  /* double xdiff =(s1.getX() - s2.getX())*(s1.getX() - s2.getX()); */
  if (s1!=null && s2!=null)
    return Math.sqrt((s1.getX() - s2.getX())*(s1.getX() - s2.getX())
		     +(s1.getY() - s2.getY())*(s1.getY() - s2.getY()));
  else return 0;
}
//************************************************ 
public void findDistances() {
  double dist;
  for (int i=0; i < numS; i++)
    for (int j=0; j < numS; j++) {
      dist=getDistance(sarray[i],sarray[j]);
      distances[i][j]=dist; 
      /* distances[j][i]=dist; */
    }
}
//************************************************
public void printDistances() {
  for (int i=0; i < numS; i++)
    for (int j=0; j < numS; j++)
      System.err.print("  From "+i+" to "+j+" is " + distances[i][j]+
		       ".");	
}
//************************************************
public Switch bestStarCenter() {
  double bestCost,currentCost=0;
  int i=0,j=0;
  Switch winner=sarray[0];
/*    System.err.out(distances[i][j]); 
      System.err.out(sarray[j].getAlpha()); 
      System.err.out(sarray[j].getOmega()); */
    try {
      for (j=0 ; j<numS ; j++) {
	currentCost += distances[i][j]*(sarray[j].getAlpha() + sarray[j].getOmega());
//	System.err.println("current: " + currentCost);
      }
      bestCost = currentCost;
//      System.err.println("now printing best center so far: " + winner);
      for (i=1 ; i<numS ; i++) {
	currentCost = 0;
	for (j=0 ; j<numS ; j++) {
	  currentCost += distances[i][j]*(sarray[j].getAlpha() + sarray[j].getOmega());
	}
	if ( currentCost < bestCost ) {
	  bestCost = currentCost ;
	  winner = sarray[i];
//	  System.err.println("now printing best center so far: "+ winner);
	}
      }
    }
  catch (Exception e) {
    throw(new GenericException("In bestStarCenter(): " + e.getMessage()));
  }
//  System.out.println("Network--findBestCenter: i am done ");
  return winner;
}
//************************************************
  /* Following are the i/o methods */
public void readSwitches(DataInputStream d) throws GenericException {
  Switch s = new Switch("Switch", new Place("Place", 0, 0, 0, 0));
  boolean EOF = false;
  try {
    while (s.readValues(d)) {
      addSwitch(s);
      s = new Switch("Switch", new Place("Place", 0, 0, 0, 0));
    } 
  } catch (Exception e) {
    throw(new GenericException("In readSwitches(): " + e.getMessage()));
  }    
}
//************************************************
public void outStreamSwitches(DataOutputStream d) {
  try {
    for (Enumeration e = switches.elements() ; e.hasMoreElements() ;) {
      ((Switch) e.nextElement()).outStream(d);
    }
  } catch (Exception e) {
    throw(new GenericException(this, "In outStreamSwitches(): " +
			       e.getMessage())); 
  }    
}

/*
//************************************************
public Switch bestCenterFromAsciiFile(String FileName) {
  Switch s1 = new Switch("Switch", new Place("Place", 0, 0, 0, 0));
  try {
    DataInputStream i = new DataInputStream(new FileInputStream(FileName)) ;
    readSwitches(i);  
    findDistances(); 
    printDistances();
    s1 = bestStarCenter();
    for (Enumeration e = switches.elements() ; e.hasMoreElements() ;) {
      Integer j = new Integer(numL);
      Link l = new Link((Switch)e.nextElement(),s1,j.toString());
      addLink(l);
    }

  }
  catch(Exception e) {
    throw(new GenericException(this, "In bestCenterFromAsciiFile(): " +
			       e.getMessage())); 
  }
  return s1;
}
*/
//************************************************
public void print() {
  
  System.out.println(getName());

  System.out.println("Switches:");
  for (Enumeration e = switches.elements() ; e.hasMoreElements() ;) {
    System.out.println((Switch)e.nextElement());
  }
  
  System.out.println("Links:");
  for (Enumeration e = links.elements() ; e.hasMoreElements() ;) {
    System.out.println((Link)e.nextElement());
  }

  System.out.println("Constraints:");
  for (Enumeration e = constraints.elements(); e.hasMoreElements(); ) {
    System.out.println( (SetPairConstraint)e.nextElement() );
  }
}

//************************************************  
public Rectangle getBounds() {
// REQUIRES: private variable bounds is set properly.
// RETURNS: Rectangle for covering the switches of this network.
// PROMISES: nothing.

  return bounds;
}

//************************************************
// added by Hongzhou Ma, May 21, 96
// used for dimensioning links and calculating lower bounds

// SetPairConstraints, PlaceSet should be replaced by SwitchSet
public Set constraints; 

// when new links are put in, it should be cleared
private boolean adjacentConstructed;

// Vector of switches.
// now we have set, vector, and array of switches :-)
public Vector switchVec; 

// class link should have variables capL2R and capR2L, and length
// and 2 Vectors of switch pairs whose shortest path use this link
// Vector of links
public Vector linkVec; 

// these variables are used internally by the Dijkstra's algorithm
// to find out the shortest path.
Vector[] adjs; 
int[][] predecessor;
double[][] dist; // "distance" is already used elsewhere
Link[][] edge; // matrix of links

//***************************************
// fills "adjs" and "edge", to be used by Dijkstra's algorithm.
//
private void constructAdjacentAndEdge() {
  int i, l, r;
  Link tmpLink;
  if (adjacentConstructed == true)
    return;
  adjs = new Vector[switchVec.size()];
  edge = new Link[switchVec.size()][switchVec.size()];
  for (i = 0; i < switchVec.size(); i++)
    adjs[i] = new Vector();
  for (i = 0; i < links.size(); i++) {
    tmpLink = (Link)linkVec.elementAt(i);
    l = switchVec.lastIndexOf( tmpLink.l );
    r = switchVec.lastIndexOf( tmpLink.r );

    // every link corresponds to two edges
    edge[l][r] = tmpLink;
    edge[r][l] = tmpLink;
    adjs[l].addElement(new Integer(r));
    adjs[r].addElement(new Integer(l));
  }
  adjacentConstructed = true;
}

//****************************************
// called only by getAllPairsShortestPathes(),
// predecessor[][] should already be declared
// initialize predecessor[][] and selected[]
private boolean initializeSingleSource(int s, boolean[] selected) {
  if (predecessor.length < s+1)
    return false;
  if (predecessor[s].length < switchVec.size())
    return false;
  for (int i = 0; i < switchVec.size(); i++) {
    predecessor[s][i] = -1;
    selected[i] = false;
  }
  return true;
}

//****************************************
private void getAllPairsShortestPathes() {
  predecessor = new int[switchVec.size()][switchVec.size()];
  dist = new double[switchVec.size()][switchVec.size()];
  int i, j, index = 0;
  for (i = 0; i < switchVec.size(); i++)
    for (j = 0; j < switchVec.size(); j++)
      dist[i][j] = Double.MAX_VALUE;

  double min;
  boolean[] selected = new boolean[switchVec.size()];
  constructAdjacentAndEdge();
  for (int src = 0; src < switchVec.size(); src++) {
    initializeSingleSource(src, selected);
    dist[src][src] = 0;


    for (int count = 0; count < switchVec.size(); count++) {
      // extract min dist from the src
      min = Double.MAX_VALUE;
      for (i = 0; i < switchVec.size(); i++) {
	if (selected[i] == false && dist[src][i] < min) {
	  min = dist[src][i];
	  index = i;
	}
      }
      selected[index] = true;
      for (Enumeration e = adjs[index].elements(); e.hasMoreElements();) {
	j = ((Integer)e.nextElement()).intValue();
	// do relax on all switches adjacent to the selected one
	if (edge[index][j] != null &&
	    dist[src][j] > dist[src][index] + edge[index][j].length) {
	  dist[src][j] = dist[src][index] + edge[index][j].length;
	  predecessor[src][j] = index;
	}
      }
    }
  } // end of for (int src ... )

  // print out dist and predecessor. Just for debug
  System.out.println("dist = ");
  for (i = 0; i < switchVec.size(); i++) {
    for (j = 0; j < switchVec.size(); j++)
      System.out.print(dist[i][j] + " ");
    System.out.println();
  }
  System.out.println("predecessor = ");
  for (i = 0; i < switchVec.size(); i++) {
    for (j = 0; j < switchVec.size(); j++)
      System.out.print(predecessor[i][j] + " ");
    System.out.println();
  }
      
} // end of getAllPairsShortestPathes()

//**********************************************
// set reference path on links on the path from switch i to switch j
// take care of the directions. every reference is a switch pair.
private void setRefPaths(int i, int j) {
  SwitchPair sp1, sp2; 
  if ( i == j ) return;
  // a path from sp.l to sp.r will pass the link from left to right
  sp1 = new SwitchPair( (Switch)switchVec.elementAt(i),
		       (Switch)switchVec.elementAt(j) );
  sp2 = new SwitchPair( (Switch)switchVec.elementAt(j), 
		       (Switch)switchVec.elementAt(i) );
  int src = i;
  int dst = j;
  int pred;
  while ( (pred = predecessor[src][dst]) != -1 ) {
    if (edge[pred][dst].l.equals(switchVec.elementAt(pred)))
      edge[pred][dst].refPath.addElement(sp1);
    else
      edge[pred][dst].refPath.addElement(sp2);
    dst = pred;
  }
} // end of setRefPaths()

//********************************************
// clear all reference path on all links. called by dimensioningLinks()
//
private void clearAllRefPaths() {
  for(int i = 0; i < linkVec.size(); i++) {
    ((Link)linkVec.elementAt(i)).refPath.removeAllElements();
  }
}

solve lpProblem;
lprec lpRec;

private void clearArrayOfDouble( double[] x ) {
  for (int i = 0; i < x.length; i++)
    x[i] = 0;
}

//********************************************
// set constraint for lp_solve
//
private void setConstraint() {
  lpProblem = new solve();
  lpRec = new lprec(0, switchVec.size()*switchVec.size());
  double coef1[], coef2[];
  int src, dst;
  coef1 = new double[switchVec.size()*switchVec.size()+1];
  coef2 = new double[switchVec.size()*switchVec.size()+1];

  int i, j, k1, k2;

  lpProblem.set_maxim(lpRec);
  clearArrayOfDouble(coef1);

  // should set_obj_fn() before add any constraint
  // the actual objective function will be set later
  lpProblem.set_obj_fn(lpRec, coef1);
  // lpProblem.print_lp(lpRec);

  // add constraints from alpha and omega
  for (src = 0; src < switchVec.size(); src++) {
    clearArrayOfDouble(coef1);
    clearArrayOfDouble(coef2);
    for (dst = 0; dst < switchVec.size(); dst++) {
      if (dst != src) {
	k1 = src*switchVec.size() + dst + 1;
	k2 = dst*switchVec.size() + src + 1;
	coef1[k1] = 1;
	coef2[k2] = 1;
      }
    }
    lpProblem.add_constraint( lpRec, coef1, constant.LE,
			     ((Switch)switchVec.elementAt(src)).getAlpha() );
    lpProblem.add_constraint( lpRec, coef2, constant.LE,
			     ((Switch)switchVec.elementAt(src)).getOmega() );
  }    

  // now add link constraints
  SetPairConstraint spc;
  double rhs1, rhs2;
  for (Enumeration e = constraints.elements();
       e.hasMoreElements(); ) {
    spc = (SetPairConstraint)e.nextElement();
    rhs1 = spc.out;
    rhs2 = spc.in;
    clearArrayOfDouble(coef1);
    clearArrayOfDouble(coef2);

    Enumeration sA = spc.a.elements(); // switches on side A
    for (; sA.hasMoreElements();) {
      src = switchVec.indexOf((Switch)sA.nextElement());
      // System.out.print("src = " + src);
      Enumeration sB = spc.b.elements(); // switches on side B
      for (; sB.hasMoreElements();) {
	dst = switchVec.indexOf((Switch)sB.nextElement());
	// System.out.print(" dst = " + dst);
	// coef1, rhs1, k1: flow from side A to side B
	// ocef2, rhs2, k2: flow from side B to side A
	k1 = src*switchVec.size() + dst + 1;
	k2 = dst*switchVec.size() + src + 1;
	coef1[k1] = 1;
	coef2[k2] = 1;
      }
    }
    lpProblem.add_constraint(lpRec, coef1, constant.LE, rhs1);
    lpProblem.add_constraint(lpRec, coef2, constant.LE, rhs2);
  }
  /*
  System.out.println("lp problem constructed in setConstraint");
  lpProblem.print_lp(lpRec);
  */
}      

// should get all pairs shortest paths first.
private void dimensioningLinks() {
  int i, j, k1, k2, src, dst;
  Switch sw;
  Link curLink;
  SetPairConstraint spc;
  solve linkDimension1, linkDimension2;
  double[] coef1, coef2;
  this.cost = 0;
  for (i = 0; i < switchVec.size(); i++) {
    for (j = i+1; j < switchVec.size(); j++) {
      setRefPaths(i,j);
    }
  }
  setConstraint();
  for (i = 0; i < links.size(); i++) {
    curLink = (Link)linkVec.elementAt(i);
    coef1 = new double[switchVec.size()*switchVec.size()+1];
    coef2 = new double[switchVec.size()*switchVec.size()+1];
    
    // set objective function
    for (j = 0; j < coef1.length; j++) {
      coef1[j] = 0;
      coef2[j] = 0;
    }
    for (j = 0; j < curLink.refPath.size(); j++) {
      src = switchVec.indexOf(((SwitchPair)curLink.refPath.elementAt(j)).l);
      dst = switchVec.indexOf(((SwitchPair)curLink.refPath.elementAt(j)).r);
      // System.out.println("src = " + src + "dst = " + dst);
      k1 = src*switchVec.size() + dst + 1;
      k2 = dst*switchVec.size() + src + 1;
      coef1[k1] = 1;
      coef2[k2] = 1;
    }
    lpProblem.set_obj_fn(lpRec, coef1);
    // lpProblem.print_lp(lpRec);

    if (lpProblem.solve(lpRec) != constant.OPTIMAL)
      System.err.println("no optimal result from lpsolve");
    curLink.capL2R = lpRec.getBestSolution(0);
    lpProblem.set_obj_fn(lpRec, coef2);

    // lpProblem.print_lp(lpRec);

    if (lpProblem.solve(lpRec) != constant.OPTIMAL)
      System.err.println("no optimal result from lpsolve");
    curLink.capR2L = lpRec.getBestSolution(0);
    cost += (curLink.capR2L + curLink.capL2R)*curLink.length;
    System.out.println(curLink.toString());
  }
  System.out.println("the cost is " + cost);
} // end of dimensioningLinks()

// get all pairs shortest pathes should be called first
private double calculateLowerBound() {
  double[] coef;
  int src, dst;
  coef = new double[switchVec.size()*switchVec.size()+1];
  solve lowerBound = new solve();
  int i, j, k1, k2;
  for (i = 0; i < switchVec.size(); i++) {
    for (j = 0; j < switchVec.size(); j++) {
      coef[i*switchVec.size()+j+1] = dist[i][j];
    }
  }
  lpProblem.set_obj_fn(lpRec, coef);
  // lpProblem.print_lp(lpRec);
  if (lpProblem.solve(lpRec) != constant.OPTIMAL)
     System.err.println("no optimal result in lpsolve");
  // lpProblem.print_solution(lpRec);
  return  lpRec.getBestSolution(0);
}      


} // end of class Network
//////////////////////////////////////////////////













