www.pudn.com > query_cycle_simulator.rar > QueryCycleManagerImpl.java


/* ====================================================================
 * The Stanford P2P Sociology Project Software License, Version 1.0
 *
 * Copyright (c) 2003 The Stanford P2P Sociology Project.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Stanford P2P Sociology Project(http://p2p.stanford.edu/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * For more
 * information on the Stanford P2P Sociology Project,
 * see .
 *
 */

package qcsim.impl;

import java.io.*;
import java.util.*;

import qcsim.*;
import qcsim.util.*;
import qcsim.peer.*;
import qcsim.peer.impl.PeerManagerRTR;
import qcsim.peer.content.*;
import qcsim.peer.content.impl.*;
import qcsim.net.*;

 /*
  * Title: Query Cycle Simulator
  * Description: P2P file sharing network simulator
  * Copyright: Copyright (c) 2002
  * Company:
  */

 /**
  * Creates and initializes system components.
  *
  * @author unascribed
  * @version 1.0
  */

public class QueryCycleManagerImpl implements QueryCycleManager, Externalizable
{
  /**
   * The resource directory
   */
  private String resource_;

  /**
   * The current cycle.
   */
  private int cycle_;

  private int simulatedCycles_;

  /**
   * The peer manager
   */
  private PeerManager peerManager_;

  /**
   * The network.
   */
  private NetworkManager networkManager_;

  /**
   * The peer content manager
   */
  private PeerContentManager contentManager_;

  private FileOutputStream rtrOut_;

  private Plot uploadsPath_;
  private Plot uploadsConnections_;
  private Plot shortestPath_;
  private Plot pathToMalicious_;
  private Plot linkProbability_;
  private Plot linkTrust_;
  private Plot linkVolume_;
  private Plot messages_;
  private Plot authenticResponses_;
  private Plot goodResponsesRatio_;
  private Plot goodResponsesGoodUploads_;
  private Plot goodDownloads_;
  private Plot voidDownloads_;
  private Plot averageScore_;
  private Plot averageExact_;
  private Plot badDownloads_;
  private Plot maliciousResponses_;
  private Plot maliciousConnections_;
  private Plot globalTrust_;
  private Plot clusterCoefficient_;
  private Plot charPathLength_;
  private Plot charPathLengthGP_;
  private Plot charPathLengthMP_;
  private Plot maliciousPeerAuthenticUploadRatio_;


  public static void main(String [] argv)
  {
    String resource = argv[0];

    QueryCycleScriptParser parser  = new QueryCycleScriptParser(resource);
    QueryCycleManager      manager = parser.parse(); 

    try {
      for (int i = 0; i < parser.cycles(); i++)
      {
        manager.cycle( i );
        System.runFinalization();
        System.gc();
        manager.execPlots();
      }
      manager.flushPlots();
    } catch (Exception e) {
      System.err.println(e);
      e.printStackTrace();
    }

    try { 
       System.out.print("Save Simulation? Enter a description " +
                        "(if not just return): "); 
       BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
       String fdesc = br.readLine().trim(); 
       if (fdesc.equals("")) return;

       System.out.print("Enter filename: "); 
       br = new BufferedReader(new InputStreamReader(System.in)); 
       String fname = br.readLine().trim();

       manager.save(fname, fdesc);
    } catch (Exception ioe) { 
       System.out.println("IO error trying to save simulation! " + ioe); 
    } 
  }

  /**
   * Constructor
   */
  public QueryCycleManagerImpl() 
  { 
    resource_        = null;
    cycle_           = 0;
    simulatedCycles_ = -1;
    initPlots();
  }

  /**
   * Constructor
   */
  public QueryCycleManagerImpl(String resource) 
  { 
    this();
    resource_ = resource;
    rtrOut_   = null;
    initPlots();
  }

  public void writeExternal(ObjectOutput out) 
              throws IOException
  {
    out.writeInt( simulatedCycles_ );
    out.writeObject( peerManager_ );
    out.writeObject( networkManager_ );
  }

  public void readExternal(ObjectInput in)
              throws IOException, ClassNotFoundException
  {
    simulatedCycles_= in.readInt();
    peerManager_    = (PeerManager) in.readObject();
    networkManager_ = (NetworkManager) in.readObject();

    cycle_ = 0;
  }

  /**
   * Set the current cycle
   * @param cycle the cycle.
   */
  public void cycle(int cycle)
  {
    cycle_ = cycle;

    System.err.println("EXECUTE CYCLE: "+cycle);

    // Check if cycle has already been executed.
    if (simulatedCycles_ < cycle_)
    {
      simulatedCycles_ = cycle;
      peerManager_.execCycle();

      if (peerManager_ instanceof PeerManagerRTR)
      {
        try {
          if (rtrOut_ == null)
            rtrOut_ = new FileOutputStream(resource_ + "/graphDat/rtrStatistics.dat");
          ((PeerManagerRTR)peerManager_).outputStats(rtrOut_);
        } catch (Exception e) {
          // Ignore, perhaps we're in an applet...
        }
      }
    }
  }

  /**
   * The current cycle the simulator is in.
   * @return The current cycle.
   */
  public int cycle()
  {
    return cycle_;
  }

  /**
   * Get the number of cycles executed
   * @return The number of simulated cycles.
   */
  public int simulatedCycles()
  {
    return simulatedCycles_;
  }

  /**
   * The network manager used to send messages.
   * @return the network manager.
   */
  public NetworkManager networkManager()
  {
    return networkManager_;
  }

  /**
   * The peer manager.
   * @return The peer Manager.
   */
  public PeerManager peerManager()
  {
    return peerManager_;
  }

  /**
   * Get the peer content manager
   * @return the content manager.
   */
  public PeerContentManager contentManager()
  {
    return contentManager_;
  }
  
  /**
   * Save the current simulation
   * @param filename file name to save simulation under
   */
  public void save(String fname, String fdesc)
  {
    String dir = resource_ + "/simulations/";

    fname += ".sim";
    try
    {
      RandomAccessFile   descriptions = null;
      FileOutputStream   ostream      = new FileOutputStream( dir + fname );
      ObjectOutputStream objstream    = new ObjectOutputStream( ostream );

      objstream.writeObject( this );
      objstream.flush();
      ostream.close();

      String desc = fdesc + ":" + fname + "\n";

      descriptions = new RandomAccessFile(dir + "sims", "rw");
      descriptions.seek(descriptions.length());
      descriptions.write(desc.getBytes()); 
      descriptions.close();
    } catch (SecurityException e) {
      System.err.println("Security exception: " + e.getMessage());
    } catch (FileNotFoundException e) {
      System.err.println("File Not Found exception: " + e.getMessage());
    } catch (NotSerializableException e) {
      System.err.println("Not serializable exception: " + e.getMessage());
    } catch (Exception e) {
      System.err.println("Simulation save exception: " + e.getMessage());
    }
  }

  /**
   * Reset the simulation.
   * @return A new manager that will replay the current simulation.
   */
  public void reset()
  {
    cycle_ = 0;
  }

//===============================================================

  /**
   * This function will setup the number of desired peers in the system.
   * @param gp The number of good peers.
   * @param gpn The number of neighbors each good peer should have.
   * @param mp The number of malicious peers.
   * @param mpn The number of neighbors each malicious peer should have.
   * @param htp The number of highly trusted peers.
   * @param htpn The number of neighbors each highly trusted peers should have.
   */
  public void peers(int gp, int gpn, int mp, int mpn, int htp, int htpn)
  {
    // @@@
    peerManager_    = new qcsim.peer.impl.PeerManagerImpl( this );
    networkManager_ = new qcsim.net.impl.PowerLawNetworkImpl( this );

    networkManager_.goodPeers(gp, gpn);
    networkManager_.highlyTrustedPeers(htp, htpn);
    networkManager_.maliciousPeers(mp, mpn);

    if (contentManager_ != null)
      peerManager_.contentManager(contentManager_);
  }

  public void rtrPeers(int peers, int neighbors)
  {
    peerManager_ = new qcsim.peer.impl.PeerManagerRTR( this );
	networkManager_ = new qcsim.net.impl.PowerLawNetworkImpl( this );

    networkManager_.goodPeers(peers, neighbors);

    if (contentManager_ != null)
      peerManager_.contentManager(contentManager_);
  }

  /**
   * This is used to establish the desired content parameters.
   * @param categories The total number of categories in the system.
   * @param minCategories Each peer will maintain at least this number of categories.
   * @param distribution Specifies how files are distributed among peers.
   */
  public void content(int categories, int minCategories, int distribution)
  {
    contentManager_ = 
      new PeerContentManagerImpl(categories, minCategories, distribution);

    if (peerManager_ != null && peerManager_.peers() > 0)
      peerManager_.contentManager(contentManager_);

  }

  /**
   * This method will setup malicious peers to have extra category preference.
   * For example if you call this with argument Content.TOP_CATEGORY, 
   * then each malicious peer will choose from the top 1/3 most 
   * popular categories during content initialization.
   * @param pref The type of preference
   */
  public void maliciousPeerCategoryPref(int pref)
  {
    if (peerManager_ == null) return;

    for (int i = 0; i < peerManager_.peers(); i++)
    {
      Peer p = peerManager_.peer(i);
      if (p.behavior().type() > PeerBehavior.HIGHLY_TRUSTED_PEER) 
        p.behavior().categoryPreference(pref);
    }
  }

  /**
   * This method will setup highly trusted peers to have extra category 
   * preference.
   * For example if you call this with argument 
   * PeerContentManager.TOP_CATEGORY, then each highly trusted peer 
   * will choose from the top 1/3 most popular categories during 
   * content initialization.
   * @param pref The type of preference
   */
  public void highTrustPeerCategoryPref(int pref)
  {
    if (peerManager_ == null) return;

    for (int i = 0; i < peerManager_.peers(); i++)
    {
      Peer p = peerManager_.peer(i);
      if (p.behavior().type() == PeerBehavior.HIGHLY_TRUSTED_PEER) 
        p.behavior().categoryPreference(pref);
    }
  }

  /**
   * This method will setup the method of choosing which responses
   * each good peer chooses to download. 
   * For example A peer will send a query for a particular file and receive
   * a number of responses.  Setting this method to PeerBehavior.RPB_RANDOM
   * will cause the peer to choose responses in random order.
   * @param selector response selector (see PeerBehavior.RPB_*).
   */
  public void goodPeerResponseSelector(int selector)
  {
    if (peerManager_ == null) return;

    for (int i = 0; i < peerManager_.peers(); i++)
    {
      Peer p = peerManager_.peer(i);
      if (p.behavior().type() < PeerBehavior.MALICIOUS_PEER) 
        p.behavior().responseSelector(selector);
      else
        p.behavior().responseSelector(PeerBehavior.RPB_RANDOM);
    }
  }

  public void goodPeerTTL(int ttl)
  {
    if (peerManager_ == null) return;

    for (int i = 0; i < peerManager_.peers(); i++)
    {
      Peer p = peerManager_.peer(i);
      if (p.behavior().type() < PeerBehavior.MALICIOUS_PEER) 
        p.ttl(ttl);
    }
  }

  public void freeriderFraction(double freeriders)
  {
    if (peerManager_ == null) return;

    peerManager_.freeRiders( freeriders );
  }

  /**
   * This will setup the upload error fraction for a given type of peer.
   * @param error The fraction of time a peer makes a mistake.
   * @param type The type of peer that has this error fraction.
   */
  public void errorFraction(double error, int type)
  {
    if (peerManager_ == null) return;

    for (int i = 0; i < peerManager_.peers(); i++)
    {
      Peer p = peerManager_.peer(i);
      if (p.behavior().type() == type) 
        p.behavior().errorFraction(error);
      else if (type >= PeerBehavior.MALICIOUS_PEER &&
               p.behavior().type() >= PeerBehavior.MALICIOUS_PEER)
        p.behavior().errorFraction(error);
    }
  }

  /**
   * This will setup the peer's activity during the simulation. See
   * PeerBehavior.ACTIVITY_* for more information.
   * @param peers A vector of peers to initialize.
   * @param activity The activity model the peers will follow.
   */
  public void setPeerActivity(Vector peers, int activity)
  {
    if (peerManager_ == null) return;

    for (Enumeration enum = peers.elements(); enum.hasMoreElements(); )
    {
      int id = ((Integer)enum.nextElement()).intValue();
      peerManager_.peer(id).behavior().activity(activity);
    }
  }

  /**
   * This method is used to establish malicious collectives.  The vector
   * of peers should be only malicious peers.  Passing in good or highly
   * trusted peers will be ignored.  
   * @param peers The peers that will be apart of the collective.
   * @param collective The colletive type.
   * @param type The type of configuration.
   */
  public void establishCollective(Vector peers, int collective, int type)
  {
    if (peerManager_ == null) return;
    System.err.println("ESTABLISH COLLECTIVE");
    for (Enumeration enum = peers.elements(); enum.hasMoreElements(); )
      System.err.println("PEER: "+((Integer)enum.nextElement()));

    peerManager_.collective(peers, collective, type);
  }

//======================================================
// Graph plot interface

  public Plot plot(int type)
  {
    switch (type)
    {
      case UPLOADS_PATH:     return uploadsPath_;
      case SHORTEST_PATH:    return shortestPath_;
      case LINK_PROBABILITY: return linkProbability_;
      case LINK_TRUST:       return linkTrust_;
      case LINK_VOLUME:      return linkVolume_;
      case MESSAGES:         return messages_;
      case GOOD_RESPONSES:   return authenticResponses_;
      case BAD_RESPONSES:    return maliciousResponses_;
      case MALICIOUS_CONNECTIONS: return maliciousConnections_;
    }
    return null;
  }

  public void execPlots()
  {
      //plotPathLengths();
      //plotLinkProbabilities();
    plotNetworkTraffic();
    //plotGlobalTrust();
    //plotSmallWorldNetworkValues();
  }

  public void flushPlots()
  {
      peerManager_.outputStats();
    uploadsPath_.flush("uploads_path.dat");
    uploadsConnections_.flush("uploads_connections.dat");
    shortestPath_.flush("shortest_path.dat");
    pathToMalicious_.flush("pathToMalicious.dat");
    linkProbability_.flush("link_probability.dat");
    linkTrust_.flush("link_trust.dat");
    linkVolume_.flush("link_volume.dat");
    messages_.flush("messages.dat");
    authenticResponses_.flush("good_responses.dat");
    goodResponsesRatio_.flush("good_responses_ratio.dat");
    goodResponsesGoodUploads_.flush("good_responses_good_uploads.dat");
    goodDownloads_.flush("good_downloads.dat");
    voidDownloads_.flush("void_downloads.dat");
    averageScore_.flush("average_score.dat");
    averageExact_.flush("average_exact.dat");
    badDownloads_.flush("bad_downloads.dat");
    maliciousResponses_.flush("malicious_responses.dat");
    maliciousConnections_.flush("malicious_connections.dat");
    globalTrust_.flush("global_trust.dat");
    clusterCoefficient_.flush("clusterCoefficient.dat");
    charPathLength_.flush("charPathLength.dat");
    charPathLengthGP_.flush("charPathLengthGP.dat");
    charPathLengthMP_.flush("charPathLengthMP.dat");
    maliciousPeerAuthenticUploadRatio_.flush("maliciousAuthenticRatio.dat");
  }

  private void initPlots()
  {
    uploadsPath_ = 
      new Plot(resource_,"Number of Good Uploads", "Avg. Shortest Path Length");
    uploadsConnections_ = 
      new Plot(resource_,"Number of Good Uploads", "Number of Connections");
    shortestPath_ = 
      new Plot(resource_, "Peer", "Avg. Shortest Path Length");
    pathToMalicious_ = 
      new Plot(resource_, "Cycle", "Avg. Path Length to Malicious Peer");
    linkProbability_ = 
      new Plot(resource_, "Content Similarity", "Link Probability");
    linkTrust_  = 
      new Plot(resource_, "Local Trust Value", "Link Probability");
    linkVolume_ = 
      new Plot(resource_, "Number of Connections", "Shared Volume");
    messages_   = 
      new Plot(resource_, "Cycle", "Total Messages");
    authenticResponses_ = 
      new Plot(resource_, "Cycle", "Good Query Responses");
    goodResponsesRatio_ = 
      new Plot(resource_, "Authentic Uploads", "Good Query Response Ratio");
    goodResponsesGoodUploads_ = 
      new Plot(resource_, "Authentic Uploads", "Good Query Responses");
    goodDownloads_ = 
      new Plot(resource_, "Cycle", "Number of Authentic Downloads");
    voidDownloads_ = 
      new Plot(resource_, "Cycle", "Number of Queries With No Responses");
    averageScore_ = 
      new Plot(resource_, "Cycle", "Average Total Score of Responses");
    averageExact_ = 
      new Plot(resource_, "Cycle", "Average Number of Exact Matches");
    badDownloads_ = 
      new Plot(resource_, "Cycle", "Number of Inauthentic Downloads");
    maliciousResponses_ = 
      new Plot(resource_, "Cycle", "Malicious Query Responses");
    maliciousConnections_ = 
      new Plot(resource_, "Cycle", "Malicious Connections");
    globalTrust_ = 
      new Plot(resource_, "Peer ID", "Global Trust Value");
    clusterCoefficient_ =
      new Plot(resource_, "Cycle", "Global Cluster Coefficient");
    charPathLength_ =
      new Plot(resource_, "Cycle", "Characteristic Path Length");
    charPathLengthGP_ =
      new Plot(resource_, "Cycle", "Characteristic Path Length to Good Peer");
    charPathLengthMP_ =
      new Plot(resource_, "Cycle", "Characteristic Path Length to Malicious Peer");
    maliciousPeerAuthenticUploadRatio_ =
      new Plot(resource_, "Cycle", "Malicious Peer Authentic Uploads Ratio");
  }

  private void plotPathLengths()
  {
    ArrayList paths              = null;
    double    avgPathToMalicious = 0;
    double[]  avgPathLength      = new double[peerManager().peers()];
    double    maxPathLength      = 0.0;
    double    numPaths           = 0;

    for (int i = 0; i < peerManager().peers(); i++)
    {
      int length = 0;

      paths            = peerManager().peer(i).shortestPaths();
      avgPathLength[i] = 0.0;
      numPaths         = 0;
      for (int j = 0; j < paths.size(); j++)
      {
        if (i == j) 
          continue;
        else if (peerManager().peer(j).behavior().type() >= 
                 PeerBehavior.MALICIOUS_PEER)
          continue; 

        length = ((Integer)paths.get(j)).intValue(); // Path length: i --> j

        if (length != Peer.INF)
          avgPathLength[i] += (double)length;
        else
          avgPathLength[i] += (double) peerManager().diameter() + 1;
        numPaths++;
      }
      if (numPaths > 0) 
      {
        avgPathLength[i] = avgPathLength[i] / numPaths;
        maxPathLength = (maxPathLength < avgPathLength[i]) ? 
                         avgPathLength[i] : maxPathLength;
      }
    }

    Vector uploadPaths       = new Vector();
    Vector uploadConnections = new Vector();
    for (int i = 0; i < peerManager().peers(); i++)
    {
      int gUploads = peerManager().peer(i).totalGoodUploads();
      while (uploadPaths.size() <= gUploads) 
      {
        uploadPaths.addElement(new Vector());
        uploadConnections.addElement(new Vector());
      }

      Vector val = (Vector) uploadPaths.get( gUploads );
      val.addElement( new Double(avgPathLength[i]) );

      val = (Vector) uploadConnections.get( gUploads );
      val.addElement( new Double(peerManager().peer(i).neighbors()) );
    }

    uploadsPath_.clear();
    uploadsConnections_.clear();
    for (int i = 0; i < uploadPaths.size(); i++)
    {
      Vector upld = (Vector) uploadPaths.get(i);
      if (upld.size() > 0)
      { 
        double pathLength = 0.0;
        for (int p = 0; p < upld.size(); p++)
          pathLength += ((Double)upld.get(p)).doubleValue();
        pathLength /= (double)upld.size();
        uploadsPath_.plot(i, pathLength);
      }

      upld = (Vector) uploadConnections.get(i);
      if (upld.size() > 0)
      {
        double connections = 0.0;
        for (int p = 0; p < upld.size(); p++)
          connections += ((Double)upld.get(p)).doubleValue();
        connections /= (double)upld.size();
        uploadsConnections_.plot(i, connections);
      }
    } 

    shortestPath_.clear();
    double pathCount = 0;
    for (int i = 0; i < peerManager().peers(); i++)
    {
      double pathLength    = avgPathLength[i];
      shortestPath_.plot((double)i, pathLength);

      if (peerManager().peer(i).behavior().type() < PeerBehavior.MALICIOUS_PEER)
      {
        double maliciousPath = peerManager().peer(i).pathLengthToMalicious();
        if (maliciousPath == Peer.INF)
          avgPathToMalicious += peerManager().diameter();
        else
          avgPathToMalicious += maliciousPath;
        pathCount++;
      }
    }
    avgPathToMalicious /= pathCount;
    if (avgPathToMalicious == peerManager().diameter()) 
      avgPathToMalicious = peerManager().peers();
    pathToMalicious_.plot(cycle(), avgPathToMalicious);
  }

  private void plotLinkProbabilities()
  {
    // Draw Graph Link Probability as a function of Peer Content.
    int[]        links   = new int[10];
    int[]        norm    = new int[10];

    for (int i = 0; i < 10; i++) 
    {
      links[i] = 0;
      norm[i]  = 0;
    }

    for (int i = 0; i < peerManager().peers(); i++)
    {
      if (peerManager().peer(i).behavior().type() >= 
          PeerBehavior.MALICIOUS_PEER)
        break;

      double[] cd = peerManager().peer(i).content().contentDistribution();
      for (int j = 0; j < peerManager().peers() && j < i; j++)
      {
        double[] cdn = peerManager().peer(j).content().contentDistribution();

        double  n = l1Norm(cd, cdn); 
        int index = (int) Math.floor(9.0*(1.0 - n/2.0));

        norm[index]++;
        if (peerManager().peer(i).isNeighbor(j) != null)
          links[index]++;
      }
    }

    linkProbability_.clear();
    for (int i = 1; i <= links.length; i++)
    {
      double linkProb = 0.0;
      if (links[i-1] != 0 && norm[i-1] != 0)
        linkProb = (double) links[i-1] / (double) norm[i-1];
      else continue; 

      linkProbability_.plot( ((double)i/(double)links.length), linkProb); 
    }
    linkProbability_.maxX(1.0);
    linkProbability_.maxY(1.0);

    // Links as a function of Local Trust
    Vector linkTrust = new Vector();
    Vector ltNorm    = new Vector();

    for (int i = 0; i < peerManager().peers(); i++)
    {
      Peer p1 = peerManager().peer(i);
      for (int j = 0; j < peerManager().peers(); j++)
      {
        if (i == j) continue;

        Peer p2 = peerManager().peer(j);

        double trust = p1.localTrust(p2.peerID());

        if (trust > 0.0)
        {
          while (linkTrust.size() <= (int) trust)
          {
            linkTrust.addElement(new Double(0.0));
            ltNorm.addElement(new Double(0.0));
          }

          Double val = (Double) ltNorm.get((int)trust);
          ltNorm.set((int)trust, new Double(val.doubleValue() + 1.0));

          if (p1.isNeighbor(p2.peerID()) != null)
          {
            val = (Double) linkTrust.get((int) trust);
            linkTrust.set((int)trust, new Double(val.doubleValue() + 1.0));
          }
        } 
      }
    }

    linkTrust_.clear();
    int step = (int) Math.ceil((double)linkTrust.size() / 10.0);
    for (int i = 1; i <= 10; i++)
    {
      double lt     = 0.0;
      double ltnorm = 0.0;
      for (int j = step*(i-1); j < step*i && j < linkTrust.size(); j++)
      {
        lt     += ((Double)linkTrust.get(j)).doubleValue();
        ltnorm += ((Double)ltNorm.get(j)).doubleValue();
      }
      if (lt == 0.0) continue;

      linkTrust_.plot((double)(step*i), lt / ltnorm); 
    }
    linkTrust_.maxY(1.0);

    // Number of Links as a function of Data Volume.

    linkVolume_.clear();
    for (int i = 0; i < peerManager().peers(); i++)
    {
      Peer peer = peerManager().peer(i);

      if (peer.behavior().type() >= PeerBehavior.MALICIOUS_PEER)
        break;

      linkVolume_.plot(peer.content().totalVolume(), peer.neighbors());
    }
  } 

  private double l1Norm(double [] d1, double [] d2)
  {
    if (d1.length != d2.length)
    {
      System.err.println("L1 Norm error: length "+d1.length+" != "+d2.length);
      System.exit(1);
    }

    double norm = 0.0;
    for (int i = 0; i < d1.length; i++)
    {
      norm += (d1[i] <= d2[i]) ? d2[i] - d1[i] : d1[i] - d2[i];
    }
    if (norm > 2.0) norm = 2.0;
    return norm;
  }

  private void plotNetworkTraffic()
  {
    for (int cycle = messages_.plots(); cycle <= cycle(); cycle++)
    {
      messages_.plot(cycle, 
        networkManager().messages(cycle));
      maliciousResponses_.plot(cycle, 
        networkManager().maliciousResponses(cycle));
      maliciousConnections_.plot(cycle,
        peerManager().connectionTypes(PeerBehavior.MALICIOUS_PEER));
      badDownloads_.plot(cycle, 
        peerManager().badDownloads()); 
      authenticResponses_.plot(cycle, 
        networkManager().goodResponses(cycle));

      int numGoodDownloads = peerManager().goodDownloads();
      goodDownloads_.plot(cycle, 
	numGoodDownloads);
      voidDownloads_.plot(cycle, 
        peerManager().voidDownloads());
      averageScore_.plot(cycle, 
        peerManager().totalScore() / numGoodDownloads);
      averageExact_.plot(cycle,
        peerManager().totalExact() / numGoodDownloads);
      maliciousPeerAuthenticUploadRatio_.plot(cycle, 
        peerManager().goodUploadRatio(PeerBehavior.MALICIOUS_PEER));
    }

    if (cycle_ < 5) return;

    double[] responses = new double[peerManager().peers()-peerManager().maliciousPeers()];
    double[] totalResp = new double[peerManager().peers()-peerManager().maliciousPeers()];
    double[] uploads = new double[peerManager().peers()-peerManager().maliciousPeers()];

    for (int i = 0; i < responses.length; i++)
    {
      responses[0] = 0;
      totalResp[0] = 0;
      uploads[0]   = 0;
    }

    int currentCycle = cycle();
    for (cycle_ = 0; cycle_ <= currentCycle; cycle_++)
    {
      for (int i = 0; i < responses.length; i++)
      {
        uploads[i]   += peerManager().peer(i).goodUploads();
        if (currentCycle - 5 < cycle_)
        {
          responses[i] += peerManager().peer(i).authenticResponses();
          totalResp[i] += peerManager().peer(i).totalResponses();
        }
      }
    }

    cycle_--;

    goodResponsesGoodUploads_.clear();

    double arps  = 0;
    double total = 0;
    for (int i = 0; i < uploads.length; i++)
    {
      arps  += responses[i];
      total += totalResp[i];
    }
    if (total > 0)
      goodResponsesRatio_.plot(cycle(), arps / total);
    else
      goodResponsesRatio_.plot(cycle(), 0);

    while (true)
    {
      double min = -1;
      double avg = 0;
      double num = 0;

      for (int i = 0; i < uploads.length; i++)
      {
        if (uploads[i] == -1)
          continue;
        else if (min < 0 || uploads[i] < min)
        {
          min = uploads[i];
          if (totalResp[i] > 0)
            avg = responses[i] / totalResp[i];
          else avg = 0;
          num = 1;
        }
        else if (uploads[i] == min)
        {
          if (totalResp[i] > 0)
            avg += responses[i] / totalResp[i];
          else avg = 0;
          num++;
        }
      }

      if (min == -1) break;  // DONE

      for (int i = 0; i < uploads.length; i++)
        if (uploads[i] == min)
          uploads[i] = -1;

      goodResponsesGoodUploads_.plot(min, avg / num);
    }
    goodResponsesGoodUploads_.flush("good_responses_good_uploads.dat");
  }

  private void plotSmallWorldNetworkValues()
  {
    for (int cycle = clusterCoefficient_.plots(); cycle <= cycle(); cycle++)
    {
      clusterCoefficient_.plot(cycle, peerManager().avgClusterCoefficient());
      charPathLength_.plot(cycle, peerManager().characteristicPathLength(-1));
      charPathLengthGP_.plot(cycle, peerManager().characteristicPathLength(PeerBehavior.GOOD_PEER));
      charPathLengthMP_.plot(cycle, peerManager().characteristicPathLength(PeerBehavior.MALICIOUS_PEER));
    }
  }

  private void plotGlobalTrust()
  {
    globalTrust_.clear();
    for (int i = 0; i < peerManager().peers(); i++)
    {
      globalTrust_.plot(i, peerManager().peer(i).globalTrust());
    } 
  }

}