<commit_before>// @(#)root/graf:$Name:  $:$Id: TMultiGraph.cxx,v 1.5 2002/01/23 17:52:49 rdm Exp $
// Author: Rene Brun   12/10/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "TMultiGraph.h"
#include "TGraph.h"
#include "TH1.h"
#include "TVirtualPad.h"
#include "Riostream.h"

#include <ctype.h>

ClassImp(TMultiGraph)

//______________________________________________________________________________
//
//   A TMultiGraph is a collection of TGraph (or derived) objects
//   Use TMultiGraph::Add to add a new graph to the list.
//   The TMultiGraph owns the objects in the list.
//   Drawing options are the same as for TGraph
//   Example;
//     TGraph *gr1 = new TGraph(...
//     TGraphErrors *gr2 = new TGraphErrors(...
//     TMultiGraph *mg = new TMultiGraph();
//     mg->Add(gr1);
//     mg->Add(gr2);
//     mg->Draw("alp");

//______________________________________________________________________________
TMultiGraph::TMultiGraph(): TNamed()
{
// TMultiGraph default constructor

   fGraphs    = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
TMultiGraph::TMultiGraph(const char *name, const char *title)
       : TNamed(name,title)
{
// constructor with name and title
   fGraphs    = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
TMultiGraph::~TMultiGraph()
{
// TMultiGraph destructor

   if (!fGraphs) return;
   fGraphs->Delete();
   delete fGraphs;
   fGraphs = 0;
   delete fHistogram;
   fHistogram = 0;
}

//______________________________________________________________________________
void TMultiGraph::Add(TGraph *graph)
{
   // add a new graph to the list of graphs

   if (!fGraphs) fGraphs = new TList();
   fGraphs->Add(graph);
}

//______________________________________________________________________________
void TMultiGraph::Browse(TBrowser *)
{
    Draw("alp");
    gPad->Update();
}

//______________________________________________________________________________
Int_t TMultiGraph::DistancetoPrimitive(Int_t px, Int_t py)
{
// Compute distance from point px,py to each graph
//

//*-*- Are we on the axis?
   const Int_t kMaxDiff = 10;
   Int_t distance = 9999;
   if (fHistogram) {
      distance = fHistogram->DistancetoPrimitive(px,py);
      if (distance <= 0) return distance;
   }

//*-*- Loop on the list of graphs
   if (!fGraphs) return distance;
   TGraph *g;
   TIter   next(fGraphs);
   while ((g = (TGraph*) next())) {
      Int_t dist = g->DistancetoPrimitive(px,py);
      if (dist < kMaxDiff) {gPad->SetSelected(g); return dist;}
   }
   return distance;
}

//______________________________________________________________________________
void TMultiGraph::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this multigraph with its current attributes*-*-*-*-*-*-*
//*-*                  ==========================================
//
//   Options to draw a graph are described in TGraph::PainGraph

  AppendPad(option);
}

//______________________________________________________________________________
TH1F *TMultiGraph::GetHistogram() const
{
//    Returns a pointer to the histogram used to draw the axis
//    Takes into account the two following cases.
//       1- option 'A' was specified in TMultiGraph::Draw. Return fHistogram
//       2- user had called TPad::DrawFrame. return pointer to hframe histogram

   if (fHistogram) return fHistogram;
   if (!gPad) return 0;
   gPad->Modified();
   gPad->Update();
   if (fHistogram) return fHistogram;
   TH1F *h1 = (TH1F*)gPad->FindObject("hframe");
   return h1;
}

//______________________________________________________________________________
TAxis *TMultiGraph::GetXaxis() const
{
   // Get x axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetXaxis();
}

//______________________________________________________________________________
TAxis *TMultiGraph::GetYaxis() const
{
   // Get y axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetYaxis();
}

//______________________________________________________________________________
void TMultiGraph::Paint(Option_t *option)
{
// paint all the graphs of this multigraph

  char *l;
  static char chopt[33];
  Int_t nch = strlen(option);
  Int_t i;
  for (i=0;i<nch;i++) chopt[i] = toupper(option[i]);
  chopt[nch] = 0;
  Double_t *x, *y;
  TGraph *g;

  l = strstr(chopt,"A");
  if (l) {
     *l = ' ';
     TIter   next(fGraphs);
     Int_t npt = 100;
     Double_t maximum, minimum, rwxmin, rwxmax, rwymin, rwymax, uxmin, uxmax, dx, dy;
     rwxmin    = gPad->GetUxmin();
     rwxmax    = gPad->GetUxmax();
     rwymin    = gPad->GetUymin();
     rwymax    = gPad->GetUymax();
     if (fHistogram) {
        //cleanup in case of a previous unzoom
        if (fHistogram->GetMinimum() >= fHistogram->GetMaximum()) {
           delete fHistogram;
           fHistogram = 0;
        }
     }
     if (fHistogram) {
        minimum = fHistogram->GetYaxis()->GetXmin();
        maximum = fHistogram->GetYaxis()->GetXmax();
        uxmin   = gPad->PadtoX(rwxmin);
        uxmax   = gPad->PadtoX(rwxmax);
     } else {
        rwxmin = 1e100;
        rwxmax = -rwxmin;
        rwymin = rwxmin;
        rwymax = -rwymin;
        while ((g = (TGraph*) next())) {
           Int_t npoints = g->GetN();
           x = g->GetX();
           y = g->GetY();
           for (i=0;i<npoints;i++) {
              if (x[i] < rwxmin) rwxmin = x[i];
              if (x[i] > rwxmax) rwxmax = x[i];
              if (y[i] < rwymin) rwymin = y[i];
              if (y[i] > rwymax) rwymax = y[i];
           }
           g->ComputeRange(rwxmin, rwymin, rwxmax, rwymax);
           if (g->GetN() > npt) npt = g->GetN();
        }
        if (rwxmin == rwxmax) rwxmax += 1.;
        if (rwymin == rwymax) rwymax += 1.;
        dx = 0.05*(rwxmax-rwxmin);
        dy = 0.05*(rwymax-rwymin);
        uxmin    = rwxmin - dx;
        uxmax    = rwxmax + dx;
        minimum  = rwymin - dy;
        maximum  = rwymax + dy;
     }

     if (fMinimum != -1111) rwymin = minimum = fMinimum;
     if (fMaximum != -1111) rwymax = maximum = fMaximum;
     if (uxmin < 0 && rwxmin >= 0) {
        if (gPad->GetLogx()) uxmin = 0.9*rwxmin;
        //else                 uxmin = 0;
     }
     if (uxmax > 0 && rwxmax <= 0) {
        if (gPad->GetLogx()) uxmax = 1.1*rwxmax;
        //else                 uxmax = 0;
     }
     if (minimum < 0 && rwymin >= 0) {
        if(gPad->GetLogy()) minimum = 0.9*rwymin;
        //else                minimum = 0;
     }
     if (maximum > 0 && rwymax <= 0) {
        if(gPad->GetLogy()) maximum = 1.1*rwymax;
        //else                maximum = 0;
     }
     if (minimum <= 0 && gPad->GetLogy()) minimum = 0.001*maximum;
     if (uxmin <= 0 && gPad->GetLogx()) {
        if (uxmax > 1000) uxmin = 1;
        else              uxmin = 0.001*uxmax;
     }
     rwymin = minimum;
     rwymax = maximum;
     if (fHistogram) {
        fHistogram->GetYaxis()->SetLimits(rwymin,rwymax);
     }

//*-*-  Create a temporary histogram to draw the axis
     if (!fHistogram) {
        // the graph is created with at least as many channels as there are points
        // to permit zooming on the full range
        rwxmin = uxmin;
        rwxmax = uxmax;
        fHistogram = new TH1F(GetName(),GetTitle(),npt,rwxmin,rwxmax);
        if (!fHistogram) return;
        fHistogram->SetMinimum(rwymin);
        fHistogram->SetBit(TH1::kNoStats);
        fHistogram->SetMaximum(rwymax);
        fHistogram->GetYaxis()->SetLimits(rwymin,rwymax);
        fHistogram->SetDirectory(0);
     }
     fHistogram->Paint();
   }

   if (fGraphs) {
     TIter   next(fGraphs);
     while ((g = (TGraph*) next())) {
       g->Paint(chopt);
     }
   }
}

//______________________________________________________________________________
void TMultiGraph::Print(Option_t *option) const
{
// Print the list of graphs

   TGraph *g;
   if (fGraphs) {
     TIter   next(fGraphs);
     while ((g = (TGraph*) next())) {
       g->Print(option);
     }
   }
}

//______________________________________________________________________________
void TMultiGraph::SavePrimitive(ofstream &out, Option_t *option)
{
    // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out<<"   "<<endl;
   if (gROOT->ClassSaved(TMultiGraph::Class())) {
       out<<"   ";
   } else {
       out<<"   TMultiGraph *";
   }
   out<<"multigraph = new TMultiGraph();"<<endl;
   out<<"   multigraph->SetName("<<quote<<GetName()<<quote<<");"<<endl;
   out<<"   multigraph->SetTitle("<<quote<<GetTitle()<<quote<<");"<<endl;

   TGraph *g;
   if (fGraphs) {
     TIter   next(fGraphs);
     while ((g = (TGraph*) next())) {
       g->SavePrimitive(out,"multigraph");
     }
   }
   out<<"   multigraph->Draw("
      <<quote<<option<<quote<<");"<<endl;
}

//______________________________________________________________________________
void TMultiGraph::SetMaximum(Double_t maximum)
{
   fMaximum = maximum;
   if (fHistogram)  fHistogram->SetMaximum(maximum);
}

//______________________________________________________________________________
void TMultiGraph::SetMinimum(Double_t minimum)
{
   fMinimum = minimum;
   if (fHistogram) fHistogram->SetMinimum(minimum);
}
<commit_msg>Fix a problem in TMultiGraph::Paint following the unzoom of the Y axis when the Y axis title was non null<commit_after>// @(#)root/graf:$Name:  $:$Id: TMultiGraph.cxx,v 1.6 2002/01/24 11:39:28 rdm Exp $
// Author: Rene Brun   12/10/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "TMultiGraph.h"
#include "TGraph.h"
#include "TH1.h"
#include "TVirtualPad.h"
#include "Riostream.h"

#include <ctype.h>

ClassImp(TMultiGraph)

//______________________________________________________________________________
//
//   A TMultiGraph is a collection of TGraph (or derived) objects
//   Use TMultiGraph::Add to add a new graph to the list.
//   The TMultiGraph owns the objects in the list.
//   Drawing options are the same as for TGraph
//   Example;
//     TGraph *gr1 = new TGraph(...
//     TGraphErrors *gr2 = new TGraphErrors(...
//     TMultiGraph *mg = new TMultiGraph();
//     mg->Add(gr1);
//     mg->Add(gr2);
//     mg->Draw("alp");

//______________________________________________________________________________
TMultiGraph::TMultiGraph(): TNamed()
{
// TMultiGraph default constructor

   fGraphs    = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
TMultiGraph::TMultiGraph(const char *name, const char *title)
       : TNamed(name,title)
{
// constructor with name and title
   fGraphs    = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
TMultiGraph::~TMultiGraph()
{
// TMultiGraph destructor

   if (!fGraphs) return;
   fGraphs->Delete();
   delete fGraphs;
   fGraphs = 0;
   delete fHistogram;
   fHistogram = 0;
}

//______________________________________________________________________________
void TMultiGraph::Add(TGraph *graph)
{
   // add a new graph to the list of graphs

   if (!fGraphs) fGraphs = new TList();
   fGraphs->Add(graph);
}

//______________________________________________________________________________
void TMultiGraph::Browse(TBrowser *)
{
    Draw("alp");
    gPad->Update();
}

//______________________________________________________________________________
Int_t TMultiGraph::DistancetoPrimitive(Int_t px, Int_t py)
{
// Compute distance from point px,py to each graph
//

//*-*- Are we on the axis?
   const Int_t kMaxDiff = 10;
   Int_t distance = 9999;
   if (fHistogram) {
      distance = fHistogram->DistancetoPrimitive(px,py);
      if (distance <= 0) return distance;
   }

//*-*- Loop on the list of graphs
   if (!fGraphs) return distance;
   TGraph *g;
   TIter   next(fGraphs);
   while ((g = (TGraph*) next())) {
      Int_t dist = g->DistancetoPrimitive(px,py);
      if (dist < kMaxDiff) {gPad->SetSelected(g); return dist;}
   }
   return distance;
}

//______________________________________________________________________________
void TMultiGraph::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this multigraph with its current attributes*-*-*-*-*-*-*
//*-*                  ==========================================
//
//   Options to draw a graph are described in TGraph::PainGraph

  AppendPad(option);
}

//______________________________________________________________________________
TH1F *TMultiGraph::GetHistogram() const
{
//    Returns a pointer to the histogram used to draw the axis
//    Takes into account the two following cases.
//       1- option 'A' was specified in TMultiGraph::Draw. Return fHistogram
//       2- user had called TPad::DrawFrame. return pointer to hframe histogram

   if (fHistogram) return fHistogram;
   if (!gPad) return 0;
   gPad->Modified();
   gPad->Update();
   if (fHistogram) return fHistogram;
   TH1F *h1 = (TH1F*)gPad->FindObject("hframe");
   return h1;
}

//______________________________________________________________________________
TAxis *TMultiGraph::GetXaxis() const
{
   // Get x axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetXaxis();
}

//______________________________________________________________________________
TAxis *TMultiGraph::GetYaxis() const
{
   // Get y axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetYaxis();
}

//______________________________________________________________________________
void TMultiGraph::Paint(Option_t *option)
{
// paint all the graphs of this multigraph

  char *l;
  static char chopt[33];
  Int_t nch = strlen(option);
  Int_t i;
  for (i=0;i<nch;i++) chopt[i] = toupper(option[i]);
  chopt[nch] = 0;
  Double_t *x, *y;
  TGraph *g;

  l = strstr(chopt,"A");
  if (l) {
     *l = ' ';
     TIter   next(fGraphs);
     Int_t npt = 100;
     Double_t maximum, minimum, rwxmin, rwxmax, rwymin, rwymax, uxmin, uxmax, dx, dy;
     rwxmin    = gPad->GetUxmin();
     rwxmax    = gPad->GetUxmax();
     rwymin    = gPad->GetUymin();
     rwymax    = gPad->GetUymax();
     char *xtitle = 0;
     char *ytitle = 0;
     Int_t firstx = 0;
     Int_t lastx  = 0;

     if (fHistogram) {
        //cleanup in case of a previous unzoom
        if (fHistogram->GetMinimum() >= fHistogram->GetMaximum()) {
           Int_t nch = strlen(fHistogram->GetXaxis()->GetTitle());
           firstx = fHistogram->GetXaxis()->GetFirst();
           lastx  = fHistogram->GetXaxis()->GetLast();
           if (nch) {
              xtitle = new char[nch+1];
              strcpy(xtitle,fHistogram->GetXaxis()->GetTitle());
           }
           nch = strlen(fHistogram->GetYaxis()->GetTitle());
           if (nch) {
              ytitle = new char[nch+1];
              strcpy(ytitle,fHistogram->GetYaxis()->GetTitle());
           }
           delete fHistogram;
           fHistogram = 0;
        }
     }
     if (fHistogram) {
        minimum = fHistogram->GetYaxis()->GetXmin();
        maximum = fHistogram->GetYaxis()->GetXmax();
        uxmin   = gPad->PadtoX(rwxmin);
        uxmax   = gPad->PadtoX(rwxmax);
     } else {
        rwxmin = 1e100;
        rwxmax = -rwxmin;
        rwymin = rwxmin;
        rwymax = -rwymin;
        while ((g = (TGraph*) next())) {
           Int_t npoints = g->GetN();
           x = g->GetX();
           y = g->GetY();
           for (i=0;i<npoints;i++) {
              if (x[i] < rwxmin) rwxmin = x[i];
              if (x[i] > rwxmax) rwxmax = x[i];
              if (y[i] < rwymin) rwymin = y[i];
              if (y[i] > rwymax) rwymax = y[i];
           }
           g->ComputeRange(rwxmin, rwymin, rwxmax, rwymax);
           if (g->GetN() > npt) npt = g->GetN();
        }
        if (rwxmin == rwxmax) rwxmax += 1.;
        if (rwymin == rwymax) rwymax += 1.;
        dx = 0.05*(rwxmax-rwxmin);
        dy = 0.05*(rwymax-rwymin);
        uxmin    = rwxmin - dx;
        uxmax    = rwxmax + dx;
        minimum  = rwymin - dy;
        maximum  = rwymax + dy;
     }

     if (fMinimum != -1111) rwymin = minimum = fMinimum;
     if (fMaximum != -1111) rwymax = maximum = fMaximum;
     if (uxmin < 0 && rwxmin >= 0) {
        if (gPad->GetLogx()) uxmin = 0.9*rwxmin;
        //else                 uxmin = 0;
     }
     if (uxmax > 0 && rwxmax <= 0) {
        if (gPad->GetLogx()) uxmax = 1.1*rwxmax;
        //else                 uxmax = 0;
     }
     if (minimum < 0 && rwymin >= 0) {
        if(gPad->GetLogy()) minimum = 0.9*rwymin;
        //else                minimum = 0;
     }
     if (maximum > 0 && rwymax <= 0) {
        if(gPad->GetLogy()) maximum = 1.1*rwymax;
        //else                maximum = 0;
     }
     if (minimum <= 0 && gPad->GetLogy()) minimum = 0.001*maximum;
     if (uxmin <= 0 && gPad->GetLogx()) {
        if (uxmax > 1000) uxmin = 1;
        else              uxmin = 0.001*uxmax;
     }
     rwymin = minimum;
     rwymax = maximum;
     if (fHistogram) {
        fHistogram->GetYaxis()->SetLimits(rwymin,rwymax);
     }

//*-*-  Create a temporary histogram to draw the axis
     if (!fHistogram) {
        // the graph is created with at least as many channels as there are points
        // to permit zooming on the full range
        rwxmin = uxmin;
        rwxmax = uxmax;
        fHistogram = new TH1F(GetName(),GetTitle(),npt,rwxmin,rwxmax);
        if (!fHistogram) return;
        fHistogram->SetMinimum(rwymin);
        fHistogram->SetBit(TH1::kNoStats);
        fHistogram->SetMaximum(rwymax);
        fHistogram->GetYaxis()->SetLimits(rwymin,rwymax);
        fHistogram->SetDirectory(0);
        if (xtitle) {fHistogram->GetXaxis()->SetTitle(xtitle); delete [] xtitle;}
        if (ytitle) {fHistogram->GetYaxis()->SetTitle(ytitle); delete [] ytitle;}
        if (firstx != lastx) fHistogram->GetXaxis()->SetRange(firstx,lastx);
     }
     fHistogram->Paint();
   }

   if (fGraphs) {
     TIter   next(fGraphs);
     while ((g = (TGraph*) next())) {
       g->Paint(chopt);
     }
   }
}

//______________________________________________________________________________
void TMultiGraph::Print(Option_t *option) const
{
// Print the list of graphs

   TGraph *g;
   if (fGraphs) {
     TIter   next(fGraphs);
     while ((g = (TGraph*) next())) {
       g->Print(option);
     }
   }
}

//______________________________________________________________________________
void TMultiGraph::SavePrimitive(ofstream &out, Option_t *option)
{
    // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out<<"   "<<endl;
   if (gROOT->ClassSaved(TMultiGraph::Class())) {
       out<<"   ";
   } else {
       out<<"   TMultiGraph *";
   }
   out<<"multigraph = new TMultiGraph();"<<endl;
   out<<"   multigraph->SetName("<<quote<<GetName()<<quote<<");"<<endl;
   out<<"   multigraph->SetTitle("<<quote<<GetTitle()<<quote<<");"<<endl;

   TGraph *g;
   if (fGraphs) {
     TIter   next(fGraphs);
     while ((g = (TGraph*) next())) {
       g->SavePrimitive(out,"multigraph");
     }
   }
   out<<"   multigraph->Draw("
      <<quote<<option<<quote<<");"<<endl;
}

//______________________________________________________________________________
void TMultiGraph::SetMaximum(Double_t maximum)
{
   fMaximum = maximum;
   if (fHistogram)  fHistogram->SetMaximum(maximum);
}

//______________________________________________________________________________
void TMultiGraph::SetMinimum(Double_t minimum)
{
   fMinimum = minimum;
   if (fHistogram) fHistogram->SetMinimum(minimum);
}
<|endoftext|>


<commit_before>#include <gflags/gflags.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "ncode_common/src/common.h"
#include "ncode_common/src/thread_runner.h"
#include "ncode_common/src/file.h"
#include "ncode_common/src/logging.h"
#include "ncode_common/src/lp/demand_matrix.h"
#include "ncode_common/src/map_util.h"
#include "ncode_common/src/net/net_common.h"
#include "ncode_common/src/net/net_gen.h"
#include "ncode_common/src/perfect_hash.h"
#include "demand_matrix_input.h"
#include "common.h"
#include "metrics/metrics.h"
#include "opt/ctr.h"
#include "opt/opt.h"
#include "opt/oversubscription_model.h"
#include "opt/path_provider.h"

using namespace std::chrono;

DEFINE_bool(scale_to_make_b4_fit, true,
            "If true will always scale down the TM to make B4 fit before "
            "running the rest of the optimizers.");
DEFINE_uint64(threads, 4, "Number of parallel threads to run");

static auto* aggregate_sp_delay_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string>(
            "aggregate_sp_delay_ms", "Delay of each aggregate's shortest path",
            "Topology", "Traffic matrix");

static auto* aggregate_rate_Mbps =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string>(
            "aggregate_rate_Mbps", "Rate of each aggregate", "Topology",
            "Traffic matrix");

static auto* aggregate_path_count =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string, std::string>(
            "opt_path_count", "Number of paths in each aggregate", "Topology",
            "Traffic matrix", "Optimizer");

static auto* path_delay_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string, std::string>(
            "opt_path_delay_ms", "Delay of each path", "Topology",
            "Traffic matrix", "Optimizer");

static auto* path_flow_count =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string, std::string>(
            "opt_path_flow_count", "Number of flows on each path", "Topology",
            "Traffic matrix", "Optimizer");

static auto* path_unmet_demand =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint64_t, std::string, std::string, std::string>(
            "opt_path_unmet_demand_bps",
            "How many bps of a single flow's demand are not satisfied",
            "Topology", "Traffic matrix", "Optimizer");

static auto* ctr_runtime_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint64_t, std::string, std::string>(
            "ctr_runtime_ms", "How long it took CTR to run", "Topology",
            "Traffic matrix");

static auto* ctr_runtime_cached_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint64_t, std::string, std::string>(
            "ctr_runtime_cached_ms", "How long it took CTR to run (cached)",
            "Topology", "Traffic matrix");

static auto* tm_scale_factor =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string>(
            "tm_scale_factor",
            "By how much the TM had to be scaled to make B4 fit", "Topology",
            "Traffic matrix");

static auto* total_delay_fraction =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string>(
            "total_delay_fraction", "Fraction of total delay at no headroom",
            "Topology", "Traffic matrix");

static auto* link_utilization =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string, std::string>(
            "opt_link_utilization", "Per-link utilization", "Topology",
            "Traffic matrix", "Optimizer");

namespace ctr {

static constexpr double kHeadroomStrideSize = 0.02;

static void RecordHeadroomVsDelay(const std::string& top_file,
                                  const std::string& tm_file,
                                  const TrafficMatrix& tm) {
  using namespace ctr;
  using namespace std::chrono;
  const nc::net::GraphStorage* graph = tm.graph();

  std::vector<double> values;
  for (double link_multiplier = 1.0; link_multiplier > 0.0;
       link_multiplier -= kHeadroomStrideSize) {
    if (!tm.ToDemandMatrix()->IsFeasible({}, link_multiplier)) {
      break;
    }

    PathProvider path_provider(graph);
    CTROptimizer ctr_optimizer(&path_provider, link_multiplier, false, false);
    std::unique_ptr<RoutingConfiguration> routing = ctr_optimizer.Optimize(tm);

    double max_utilization = routing->MaxLinkUtilization();
    if (max_utilization > link_multiplier + 0.001) {
      break;
    }

    double value = duration_cast<seconds>(routing->TotalPerFlowDelay()).count();
    values.emplace_back(value);
  }

  // The lowest delay is achieved at link_multiplier=1.0. Will normalize
  // everything by that.
  CHECK(!values.empty());
  double lowest_delay = values.front();
  auto* metric_handle = total_delay_fraction->GetHandle(top_file, tm_file);
  for (auto value : values) {
    metric_handle->AddValue(value / lowest_delay);
  }
}

static void RecordTrafficMatrixStats(const std::string& topology,
                                     const std::string& tm,
                                     const TrafficMatrix& traffic_matrix) {
  const nc::net::GraphStorage* graph = traffic_matrix.graph();
  auto* sp_delay_handle = aggregate_sp_delay_ms->GetHandle(topology, tm);
  auto* rate_handle = aggregate_rate_Mbps->GetHandle(topology, tm);
  for (const auto& aggregate_and_demand : traffic_matrix.demands()) {
    const AggregateId& aggregate_id = aggregate_and_demand.first;
    const DemandAndFlowCount& demand_and_flow_count =
        aggregate_and_demand.second;

    microseconds shortest_path_delay = aggregate_id.GetSPDelay(*graph);
    milliseconds sp_delay_ms = duration_cast<milliseconds>(shortest_path_delay);

    // Will limit the delay at 1ms.
    sp_delay_ms = std::max(sp_delay_ms, milliseconds(1));
    sp_delay_handle->AddValue(sp_delay_ms.count());
    rate_handle->AddValue(demand_and_flow_count.first.Mbps());
  }
}

static void RecordRoutingConfig(const std::string& topology,
                                const std::string& tm, const std::string& opt,
                                const RoutingConfiguration& routing) {
  using namespace std::chrono;
  const nc::net::GraphStorage* graph = routing.graph();

  // A map from a link to the total load over the link.
  std::map<nc::net::GraphLinkIndex, nc::net::Bandwidth> link_to_total_load;

  OverSubModel model(routing);
  const std::map<const nc::net::Walk*, nc::net::Bandwidth>& per_flow_rates =
      model.per_flow_bandwidth_map();

  auto* path_flow_count_handle = path_flow_count->GetHandle(topology, tm, opt);
  auto* unmet_demand_handle = path_unmet_demand->GetHandle(topology, tm, opt);
  auto* path_count_handle = aggregate_path_count->GetHandle(topology, tm, opt);
  auto* path_delay = path_delay_ms->GetHandle(topology, tm, opt);

  for (const auto& aggregate_and_aggregate_output : routing.routes()) {
    const AggregateId& aggregate_id = aggregate_and_aggregate_output.first;
    const std::vector<RouteAndFraction>& routes =
        aggregate_and_aggregate_output.second;
    const DemandAndFlowCount& demand_and_flow_count =
        nc::FindOrDieNoPrint(routing.demands(), aggregate_id);

    size_t total_num_flows = demand_and_flow_count.second;
    nc::net::Bandwidth total_aggregate_demand = demand_and_flow_count.first;
    nc::net::Bandwidth required_per_flow =
        total_aggregate_demand / total_num_flows;

    for (const auto& route : routes) {
      const nc::net::Walk* path = route.first;
      double fraction = route.second;
      CHECK(fraction > 0);

      microseconds delay = path->delay();
      milliseconds delay_ms = duration_cast<milliseconds>(delay);
      delay_ms = std::max(delay_ms, milliseconds(1));
      path_delay->AddValue(delay_ms.count());

      nc::net::Bandwidth per_flow_rate =
          nc::FindOrDieNoPrint(per_flow_rates, path);
      nc::net::Bandwidth unmet = std::max(nc::net::Bandwidth::Zero(),
                                          required_per_flow - per_flow_rate);

      path_flow_count_handle->AddValue(fraction * total_num_flows);
      unmet_demand_handle->AddValue(unmet.bps());

      for (nc::net::GraphLinkIndex link : path->links()) {
        link_to_total_load[link] += total_aggregate_demand * fraction;
      }
    }

    path_count_handle->AddValue(routes.size());
  }

  auto* link_load_handle = link_utilization->GetHandle(topology, tm, opt);
  nc::net::GraphLinkSet links_seen;
  for (const auto& link_and_total_load : link_to_total_load) {
    nc::net::GraphLinkIndex link_index = link_and_total_load.first;
    links_seen.Insert(link_index);
    const nc::net::GraphLink* link = graph->GetLink(link_index);

    nc::net::Bandwidth total_load = link_and_total_load.second;
    link_load_handle->AddValue(total_load / link->bandwidth());
  }

  for (nc::net::GraphLinkIndex link_index : graph->AllLinks()) {
    if (!links_seen.Contains(link_index)) {
      link_load_handle->AddValue(0);
    }
  }
}

static bool Fits(const ctr::RoutingConfiguration& routing) {
  const std::set<ctr::AggregateId>& aggregates_no_fit =
      ctr::OverSubModel(routing).aggregates_no_fit();
  return aggregates_no_fit.empty();
}

// Runs B4. If B4 is unable to fit the traffic will scale the matrix down to the
// point where it can.
static std::unique_ptr<ctr::RoutingConfiguration> RunB4(
    const ctr::TrafficMatrix& tm, const std::string& topology_string,
    const std::string& tm_string, ctr::PathProvider* path_provider) {
  ctr::B4Optimizer b4_optimizer(path_provider, false, 1.0);
  double scale = 1.01;
  while (scale > 0) {
    // Will scale it down by 1%.
    scale -= 0.01;

    auto scaled_tm = tm.ScaleDemands(scale, {});
    // B4 should run fine on both the scaled and the randomized TMs.
    auto routing = b4_optimizer.Optimize(*scaled_tm);
    if (FLAGS_scale_to_make_b4_fit && !Fits(*routing)) {
      continue;
    }

    tm_scale_factor->GetHandle(topology_string, tm_string)->AddValue(scale);
    return routing;
  }

  LOG(FATAL) << "Should not happen";
  return {};
}

static void RunOptimizers(const DemandMatrixAndFilename& input) {
  const std::string& top_file = input.topology_file;
  const std::string& tm_file = input.file;
  const nc::net::GraphStorage* graph = input.demand_matrix->graph();
  LOG(ERROR) << "Running " << top_file << " " << tm_file;

  // A separate PathProvider instance for B4. Want to run CTR with a fresh
  // PathProvider, but have to run B4 first.
  PathProvider b4_path_provider(graph);

  std::unique_ptr<TrafficMatrix> tm =
      TrafficMatrix::ProportionalFromDemandMatrix(*input.demand_matrix);
  std::unique_ptr<RoutingConfiguration> routing;
  routing = RunB4(*tm, top_file, tm_file, &b4_path_provider);

  RecordTrafficMatrixStats(top_file, tm_file, *tm);
  RecordHeadroomVsDelay(top_file, tm_file, *tm);
  RecordRoutingConfig(top_file, tm_file, "B4", *routing);

  PathProvider path_provider(graph);
  CTROptimizer ctr_optimizer(&path_provider, 1.0, false, false);
  CTROptimizer ctr_optimizer_no_flow_counts(&path_provider, 1.0, false, true);
  MinMaxOptimizer minmax_optimizer(&path_provider, 1.0, false);
  MinMaxOptimizer minmax_low_delay_optimizer(&path_provider, 1.0, true);
  MinMaxPathBasedOptimizer minmax_ksp_optimizer(&path_provider, 1.0, true, 10);
  B4Optimizer b4_flow_count_optimizer(&path_provider, true, 1.0);

  auto ctr_start = high_resolution_clock::now();
  routing = ctr_optimizer.Optimize(*tm);
  auto ctr_duration = high_resolution_clock::now() - ctr_start;

  RecordRoutingConfig(top_file, tm_file, "CTR", *routing);

  ctr_start = high_resolution_clock::now();
  ctr_optimizer.Optimize(*tm);
  auto ctr_cached_duration = high_resolution_clock::now() - ctr_start;

  routing = ctr_optimizer_no_flow_counts.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "CTRNFC", *routing);

  routing = minmax_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "MinMax", *routing);

  routing = minmax_low_delay_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "MinMaxLD", *routing);

  routing = minmax_ksp_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "MinMaxK10", *routing);

  routing = b4_flow_count_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "B4FC", *routing);

  auto* handle = ctr_runtime_ms->GetHandle(top_file, tm_file);
  handle->AddValue(duration_cast<milliseconds>(ctr_duration).count());
  handle = ctr_runtime_cached_ms->GetHandle(top_file, tm_file);
  handle->AddValue(duration_cast<milliseconds>(ctr_cached_duration).count());
}

}  // namespace ctr

using TopologyAndMatrix = std::tuple<std::string, std::string, double>;
int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  nc::metrics::InitMetrics();

  // Will switch off timestamps.
  auto timestamp_provider =
      ::nc::make_unique<nc::metrics::NullTimestampProvider>();
  nc::metrics::DefaultMetricManager()->set_timestamp_provider(
      std::move(timestamp_provider));

  std::vector<ctr::TopologyAndFilename> topologies;
  std::vector<ctr::DemandMatrixAndFilename> to_process;
  std::tie(topologies, to_process) = ctr::GetDemandMatrixInputs();

  nc::RunInParallel<ctr::DemandMatrixAndFilename>(
      to_process, [](const ctr::DemandMatrixAndFilename& input) {
        ctr::RunOptimizers(input);
      }, FLAGS_threads);
}
<commit_msg>performance updates in opt_eval<commit_after>#include <gflags/gflags.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "ncode_common/src/common.h"
#include "ncode_common/src/thread_runner.h"
#include "ncode_common/src/file.h"
#include "ncode_common/src/logging.h"
#include "ncode_common/src/lp/demand_matrix.h"
#include "ncode_common/src/map_util.h"
#include "ncode_common/src/net/net_common.h"
#include "ncode_common/src/net/net_gen.h"
#include "ncode_common/src/perfect_hash.h"
#include "demand_matrix_input.h"
#include "common.h"
#include "metrics/metrics.h"
#include "opt/ctr.h"
#include "opt/opt.h"
#include "opt/oversubscription_model.h"
#include "opt/path_provider.h"

using namespace std::chrono;

DEFINE_bool(scale_to_make_b4_fit, true,
            "If true will always scale down the TM to make B4 fit before "
            "running the rest of the optimizers.");
DEFINE_uint64(threads, 4, "Number of parallel threads to run");

static auto* aggregate_sp_delay_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string>(
            "aggregate_sp_delay_ms", "Delay of each aggregate's shortest path",
            "Topology", "Traffic matrix");

static auto* aggregate_rate_Mbps =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string>(
            "aggregate_rate_Mbps", "Rate of each aggregate", "Topology",
            "Traffic matrix");

static auto* aggregate_path_count =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string, std::string>(
            "opt_path_count", "Number of paths in each aggregate", "Topology",
            "Traffic matrix", "Optimizer");

static auto* path_delay_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string, std::string>(
            "opt_path_delay_ms", "Delay of each path", "Topology",
            "Traffic matrix", "Optimizer");

static auto* path_flow_count =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint32_t, std::string, std::string, std::string>(
            "opt_path_flow_count", "Number of flows on each path", "Topology",
            "Traffic matrix", "Optimizer");

static auto* path_unmet_demand =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint64_t, std::string, std::string, std::string>(
            "opt_path_unmet_demand_bps",
            "How many bps of a single flow's demand are not satisfied",
            "Topology", "Traffic matrix", "Optimizer");

static auto* ctr_runtime_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint64_t, std::string, std::string>(
            "ctr_runtime_ms", "How long it took CTR to run", "Topology",
            "Traffic matrix");

static auto* ctr_runtime_cached_ms =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<uint64_t, std::string, std::string>(
            "ctr_runtime_cached_ms", "How long it took CTR to run (cached)",
            "Topology", "Traffic matrix");

static auto* tm_scale_factor =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string>(
            "tm_scale_factor",
            "By how much the TM had to be scaled to make B4 fit", "Topology",
            "Traffic matrix");

static auto* total_delay_fraction =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string>(
            "total_delay_fraction", "Fraction of total delay at no headroom",
            "Topology", "Traffic matrix");

static auto* link_utilization =
    nc::metrics::DefaultMetricManager()
        -> GetThreadSafeMetric<double, std::string, std::string, std::string>(
            "opt_link_utilization", "Per-link utilization", "Topology",
            "Traffic matrix", "Optimizer");

namespace ctr {

static constexpr double kHeadroomStrideSize = 0.02;

static void RecordHeadroomVsDelay(const std::string& top_file,
                                  const std::string& tm_file,
                                  const TrafficMatrix& tm) {
  using namespace ctr;
  using namespace std::chrono;
  const nc::net::GraphStorage* graph = tm.graph();
  PathProvider path_provider(graph);

  std::vector<double> values;
  for (double link_multiplier = 1.0; link_multiplier > 0.0;
       link_multiplier -= kHeadroomStrideSize) {
    if (!tm.ToDemandMatrix()->IsFeasible({}, link_multiplier)) {
      break;
    }

    CTROptimizer ctr_optimizer(&path_provider, link_multiplier, false, false);
    std::unique_ptr<RoutingConfiguration> routing = ctr_optimizer.Optimize(tm);

    double max_utilization = routing->MaxLinkUtilization();
    if (max_utilization > link_multiplier + 0.001) {
      break;
    }

    double value = duration_cast<seconds>(routing->TotalPerFlowDelay()).count();
    values.emplace_back(value);
  }

  // The lowest delay is achieved at link_multiplier=1.0. Will normalize
  // everything by that.
  CHECK(!values.empty());
  double lowest_delay = values.front();
  auto* metric_handle = total_delay_fraction->GetHandle(top_file, tm_file);
  for (auto value : values) {
    metric_handle->AddValue(value / lowest_delay);
  }
}

static void RecordTrafficMatrixStats(const std::string& topology,
                                     const std::string& tm,
                                     const TrafficMatrix& traffic_matrix) {
  const nc::net::GraphStorage* graph = traffic_matrix.graph();
  auto* sp_delay_handle = aggregate_sp_delay_ms->GetHandle(topology, tm);
  auto* rate_handle = aggregate_rate_Mbps->GetHandle(topology, tm);
  for (const auto& aggregate_and_demand : traffic_matrix.demands()) {
    const AggregateId& aggregate_id = aggregate_and_demand.first;
    const DemandAndFlowCount& demand_and_flow_count =
        aggregate_and_demand.second;

    microseconds shortest_path_delay = aggregate_id.GetSPDelay(*graph);
    milliseconds sp_delay_ms = duration_cast<milliseconds>(shortest_path_delay);

    // Will limit the delay at 1ms.
    sp_delay_ms = std::max(sp_delay_ms, milliseconds(1));
    sp_delay_handle->AddValue(sp_delay_ms.count());
    rate_handle->AddValue(demand_and_flow_count.first.Mbps());
  }
}

static void RecordRoutingConfig(const std::string& topology,
                                const std::string& tm, const std::string& opt,
                                const RoutingConfiguration& routing) {
  using namespace std::chrono;
  const nc::net::GraphStorage* graph = routing.graph();

  // A map from a link to the total load over the link.
  std::map<nc::net::GraphLinkIndex, nc::net::Bandwidth> link_to_total_load;

  OverSubModel model(routing);
  const std::map<const nc::net::Walk*, nc::net::Bandwidth>& per_flow_rates =
      model.per_flow_bandwidth_map();

  auto* path_flow_count_handle = path_flow_count->GetHandle(topology, tm, opt);
  auto* unmet_demand_handle = path_unmet_demand->GetHandle(topology, tm, opt);
  auto* path_count_handle = aggregate_path_count->GetHandle(topology, tm, opt);
  auto* path_delay = path_delay_ms->GetHandle(topology, tm, opt);

  for (const auto& aggregate_and_aggregate_output : routing.routes()) {
    const AggregateId& aggregate_id = aggregate_and_aggregate_output.first;
    const std::vector<RouteAndFraction>& routes =
        aggregate_and_aggregate_output.second;
    const DemandAndFlowCount& demand_and_flow_count =
        nc::FindOrDieNoPrint(routing.demands(), aggregate_id);

    size_t total_num_flows = demand_and_flow_count.second;
    nc::net::Bandwidth total_aggregate_demand = demand_and_flow_count.first;
    nc::net::Bandwidth required_per_flow =
        total_aggregate_demand / total_num_flows;

    for (const auto& route : routes) {
      const nc::net::Walk* path = route.first;
      double fraction = route.second;
      CHECK(fraction > 0);

      microseconds delay = path->delay();
      milliseconds delay_ms = duration_cast<milliseconds>(delay);
      delay_ms = std::max(delay_ms, milliseconds(1));
      path_delay->AddValue(delay_ms.count());

      nc::net::Bandwidth per_flow_rate =
          nc::FindOrDieNoPrint(per_flow_rates, path);
      nc::net::Bandwidth unmet = std::max(nc::net::Bandwidth::Zero(),
                                          required_per_flow - per_flow_rate);

      path_flow_count_handle->AddValue(fraction * total_num_flows);
      unmet_demand_handle->AddValue(unmet.bps());

      for (nc::net::GraphLinkIndex link : path->links()) {
        link_to_total_load[link] += total_aggregate_demand * fraction;
      }
    }

    path_count_handle->AddValue(routes.size());
  }

  auto* link_load_handle = link_utilization->GetHandle(topology, tm, opt);
  nc::net::GraphLinkSet links_seen;
  for (const auto& link_and_total_load : link_to_total_load) {
    nc::net::GraphLinkIndex link_index = link_and_total_load.first;
    links_seen.Insert(link_index);
    const nc::net::GraphLink* link = graph->GetLink(link_index);

    nc::net::Bandwidth total_load = link_and_total_load.second;
    link_load_handle->AddValue(total_load / link->bandwidth());
  }

  for (nc::net::GraphLinkIndex link_index : graph->AllLinks()) {
    if (!links_seen.Contains(link_index)) {
      link_load_handle->AddValue(0);
    }
  }
}

static bool Fits(const ctr::RoutingConfiguration& routing) {
  const std::set<ctr::AggregateId>& aggregates_no_fit =
      ctr::OverSubModel(routing).aggregates_no_fit();
  return aggregates_no_fit.empty();
}

// Runs B4. If B4 is unable to fit the traffic will scale the matrix down to the
// point where it can.
static std::unique_ptr<ctr::RoutingConfiguration> RunB4(
    const ctr::TrafficMatrix& tm, const std::string& topology_string,
    const std::string& tm_string, ctr::PathProvider* path_provider) {
  ctr::B4Optimizer b4_optimizer(path_provider, false, 1.0);
  double scale = 1.01;
  while (scale > 0) {
    // Will scale it down by 1%.
    scale -= 0.01;

    auto scaled_tm = tm.ScaleDemands(scale, {});
    // B4 should run fine on both the scaled and the randomized TMs.
    auto routing = b4_optimizer.Optimize(*scaled_tm);
    if (FLAGS_scale_to_make_b4_fit && !Fits(*routing)) {
      continue;
    }

    tm_scale_factor->GetHandle(topology_string, tm_string)->AddValue(scale);
    return routing;
  }

  LOG(FATAL) << "Should not happen";
  return {};
}

static void RunOptimizers(const DemandMatrixAndFilename& input) {
  const std::string& top_file = input.topology_file;
  const std::string& tm_file = input.file;
  const nc::net::GraphStorage* graph = input.demand_matrix->graph();
  LOG(ERROR) << "Running " << top_file << " " << tm_file;

  // A separate PathProvider instance for B4. Want to run CTR with a fresh
  // PathProvider, but have to run B4 first.
  PathProvider b4_path_provider(graph);

  std::unique_ptr<TrafficMatrix> tm =
      TrafficMatrix::ProportionalFromDemandMatrix(*input.demand_matrix);
  std::unique_ptr<RoutingConfiguration> routing;
  routing = RunB4(*tm, top_file, tm_file, &b4_path_provider);

  RecordTrafficMatrixStats(top_file, tm_file, *tm);
  RecordHeadroomVsDelay(top_file, tm_file, *tm);
  RecordRoutingConfig(top_file, tm_file, "B4", *routing);

  PathProvider path_provider(graph);
  CTROptimizer ctr_optimizer(&path_provider, 1.0, false, false);
  CTROptimizer ctr_optimizer_no_flow_counts(&path_provider, 1.0, false, true);
  MinMaxOptimizer minmax_optimizer(&path_provider, 1.0, false);
  MinMaxOptimizer minmax_low_delay_optimizer(&path_provider, 1.0, true);
  MinMaxPathBasedOptimizer minmax_ksp_optimizer(&path_provider, 1.0, true, 10);
  B4Optimizer b4_flow_count_optimizer(&path_provider, true, 1.0);

  auto ctr_start = high_resolution_clock::now();
  routing = ctr_optimizer.Optimize(*tm);
  auto ctr_duration = high_resolution_clock::now() - ctr_start;

  RecordRoutingConfig(top_file, tm_file, "CTR", *routing);

  ctr_start = high_resolution_clock::now();
  ctr_optimizer.Optimize(*tm);
  auto ctr_cached_duration = high_resolution_clock::now() - ctr_start;

  routing = ctr_optimizer_no_flow_counts.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "CTRNFC", *routing);

  routing = minmax_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "MinMax", *routing);

  routing = minmax_low_delay_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "MinMaxLD", *routing);

  routing = minmax_ksp_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "MinMaxK10", *routing);

  routing = b4_flow_count_optimizer.Optimize(*tm);
  RecordRoutingConfig(top_file, tm_file, "B4FC", *routing);

  auto* handle = ctr_runtime_ms->GetHandle(top_file, tm_file);
  handle->AddValue(duration_cast<milliseconds>(ctr_duration).count());
  handle = ctr_runtime_cached_ms->GetHandle(top_file, tm_file);
  handle->AddValue(duration_cast<milliseconds>(ctr_cached_duration).count());
}

}  // namespace ctr

using TopologyAndMatrix = std::tuple<std::string, std::string, double>;
int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  nc::metrics::InitMetrics();

  // Will switch off timestamps.
  auto timestamp_provider =
      ::nc::make_unique<nc::metrics::NullTimestampProvider>();
  nc::metrics::DefaultMetricManager()->set_timestamp_provider(
      std::move(timestamp_provider));

  std::vector<ctr::TopologyAndFilename> topologies;
  std::vector<ctr::DemandMatrixAndFilename> to_process;
  std::tie(topologies, to_process) = ctr::GetDemandMatrixInputs();

  nc::RunInParallel<ctr::DemandMatrixAndFilename>(
      to_process, [](const ctr::DemandMatrixAndFilename& input) {
        ctr::RunOptimizers(input);
      }, FLAGS_threads);
}
<|endoftext|>


<commit_before><commit_msg>VS名称変更対処<commit_after><|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __STOUT_ABORT_HPP__
#define __STOUT_ABORT_HPP__

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __WINDOWS__
#include <stout/windows.hpp>
#else
#include <unistd.h>
#endif // __WINDOWS__

#include <string>

#include <stout/attributes.hpp>

// Signal safe abort which prints a message.
#define __STRINGIZE(x) #x
#define _STRINGIZE(x) __STRINGIZE(x)
#define _ABORT_PREFIX "ABORT: (" __FILE__ ":" _STRINGIZE(__LINE__) "): "

#define ABORT(...) _Abort(_ABORT_PREFIX, __VA_ARGS__)

inline NORETURN void _Abort(const char* prefix, const char* message)
{
  // Write the failure message in an async-signal safe manner,
  // assuming strlen is async-signal safe or optimized out.
  // In fact, it is highly unlikely that strlen would be
  // implemented in an unsafe manner:
  // http://austingroupbugs.net/view.php?id=692
  while (::write(STDERR_FILENO, prefix, strlen(prefix)) == -1 &&
         errno == EINTR);
  while (message != nullptr &&
         ::write(STDERR_FILENO, message, strlen(message)) == -1 &&
         errno == EINTR);

  // NOTE: Since `1` can be interpreted as either an `unsigned int` or a
  // `size_t`, removing the `static_cast` here makes this call ambiguous
  // between the `write` in windows.hpp and the (deprecated) `write` in the
  // Windows CRT headers.
  while (::write(STDERR_FILENO, "\n", static_cast<size_t>(1)) == -1 &&
         errno == EINTR);
  abort();
}

inline NORETURN void _Abort(const char* prefix, const std::string& message)
{
  _Abort(prefix, message.c_str());
}

#endif // __STOUT_ABORT_HPP__
<commit_msg>Windows: Removed macro redefinition.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __STOUT_ABORT_HPP__
#define __STOUT_ABORT_HPP__

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __WINDOWS__
#include <stout/windows.hpp>
#else
#include <unistd.h>
#endif // __WINDOWS__

#include <string>

#include <stout/attributes.hpp>

// NOTE: These macros are already defined in Visual Studio (Windows) headers.
#ifndef __WINDOWS__
#define __STRINGIZE(x) #x
#define _STRINGIZE(x) __STRINGIZE(x)
#endif // __WINDOWS__

// Signal safe abort which prints a message.
#define _ABORT_PREFIX "ABORT: (" __FILE__ ":" _STRINGIZE(__LINE__) "): "

#define ABORT(...) _Abort(_ABORT_PREFIX, __VA_ARGS__)

inline NORETURN void _Abort(const char* prefix, const char* message)
{
  // Write the failure message in an async-signal safe manner,
  // assuming strlen is async-signal safe or optimized out.
  // In fact, it is highly unlikely that strlen would be
  // implemented in an unsafe manner:
  // http://austingroupbugs.net/view.php?id=692
  while (::write(STDERR_FILENO, prefix, strlen(prefix)) == -1 &&
         errno == EINTR);
  while (message != nullptr &&
         ::write(STDERR_FILENO, message, strlen(message)) == -1 &&
         errno == EINTR);

  // NOTE: Since `1` can be interpreted as either an `unsigned int` or a
  // `size_t`, removing the `static_cast` here makes this call ambiguous
  // between the `write` in windows.hpp and the (deprecated) `write` in the
  // Windows CRT headers.
  while (::write(STDERR_FILENO, "\n", static_cast<size_t>(1)) == -1 &&
         errno == EINTR);
  abort();
}

inline NORETURN void _Abort(const char* prefix, const std::string& message)
{
  _Abort(prefix, message.c_str());
}

#endif // __STOUT_ABORT_HPP__
<|endoftext|>


<commit_before><commit_msg>[Gui] Edit Menu Remove Duplicate Shift+E...<commit_after><|endoftext|>


<commit_before>//
//  EEJniUtils.cpp
//  ee-library
//
//  Created by enrevol on 10/31/15.
//
//

#include <cassert>
#include <codecvt>
#include <locale>
#include <pthread.h>

#include "ee/core/JniUtils.hpp"
#include "ee/core/Logger.hpp"
#include "ee/core/internal/JniMethodInfo.hpp"
#include "ee/core/internal/JniString.hpp"

namespace ee {
namespace core {
namespace {
pthread_key_t key_value;
} // namespace

std::thread::id JniUtils::cocosThreadId_;
bool JniUtils::isCocosThreadMarked_ = false;
JavaVM* JniUtils::vm_ = nullptr;

void JniUtils::setVm(JavaVM* vm) {
    vm_ = vm;
    pthread_key_create(&key_value, &JniUtils::detachCurrentThread);
}

void JniUtils::markCocosThread() noexcept {
    isCocosThreadMarked_ = true;
    cocosThreadId_ = std::this_thread::get_id();
}

JNIEnv* JniUtils::getEnv() {
    // Retrieve the thread local JNIEnv pointer.
    JNIEnv* env = static_cast<JNIEnv*>(pthread_getspecific(key_value));

    if (env == nullptr) {
        // The JNIEnv pointer has not been created.
        // Attempt to create it.
        env = cacheEnv();
    }

    // Check Cocos thread.
    if (isCocosThreadMarked_ && cocosThreadId_ != std::this_thread::get_id()) {
        Logger::getSystemLogger().error(
            "%s: current thread is not cocos2d-x thread!", __PRETTY_FUNCTION__);
    }

    return env;
}

JNIEnv* JniUtils::cacheEnv() {
    if (vm_ == nullptr) {
        // JavaVM has not been set.
        throw std::runtime_error{
            "java vm has not been set, call setVm in main.cpp first!"};
    }

    JNIEnv* env = nullptr;
    jint result = vm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);

    switch (result) {
    case JNI_OK: {
        // Succeed.
        pthread_setspecific(key_value, static_cast<const void*>(env));
        return env;
    }

    case JNI_EDETACHED: {
        // Thread detached.
        // Attempt to reattach.
        auto status = vm_->AttachCurrentThread(&env, nullptr);
        if (status < 0) {
            Logger::getSystemLogger().error(
                "%s: failed to get the environment using "
                "AttachCurrentThread!",
                __PRETTY_FUNCTION__);
            return nullptr;
        }

        pthread_setspecific(key_value, static_cast<const void*>(env));
        return env;
    }

    case JNI_EVERSION: {
        Logger::getSystemLogger().error(
            "%s: JNI interface version 1.4 not supported!",
            __PRETTY_FUNCTION__);
        return nullptr;
    }

    default: {
        Logger::getSystemLogger().error(
            "%s: failed to get the environment using GetEnv!",
            __PRETTY_FUNCTION__);
        return nullptr;
    }
    }
}

void JniUtils::detachCurrentThread(void*) {
    vm_->DetachCurrentThread();
}

void JniUtils::checkException() {
    JNIEnv* env = getEnv();
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
}

std::string JniUtils::toString(jstring str) {
    if (str == nullptr) {
        return "";
    }

    JNIEnv* env = getEnv();
    jboolean isCopy;
    const char* chars = env->GetStringUTFChars(str, &isCopy);
    std::string result{chars};
    env->ReleaseStringUTFChars(str, chars);
    checkException();
    return result;
}

std::unique_ptr<JniString> JniUtils::toJavaString(const std::string& str) {
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
    auto u16str = converter.from_bytes(str);
    return toJavaString(u16str);
}

std::unique_ptr<JniString> JniUtils::toJavaString(const std::u16string& str) {
    return JniString::create(getEnv(), str);
}

std::unique_ptr<JniMethodInfo>
JniUtils::getStaticMethodInfo(const char* className, const char* methodName,
                              const char* signature) {
    JNIEnv* env = getEnv();

    jclass clazz = env->FindClass(className);
    checkException();

    if (clazz == nullptr) {
        Logger::getSystemLogger().error("%s: can not find class %s",
                                        __PRETTY_FUNCTION__, className);
        return nullptr;
    }

    jmethodID methodId = env->GetStaticMethodID(clazz, methodName, signature);
    checkException();

    if (methodId == nullptr) {
        Logger::getSystemLogger().error(
            "%s: can not find static method %s in %s with signature %s",
            __PRETTY_FUNCTION__, methodName, className, signature);
        return nullptr;
    }

    return JniMethodInfo::create(env, clazz, methodId);
}
} // namespace core
} // namespace ee
<commit_msg>- Remove these because of wrong warning<commit_after>//
//  EEJniUtils.cpp
//  ee-library
//
//  Created by enrevol on 10/31/15.
//
//

#include <cassert>
#include <codecvt>
#include <locale>
#include <pthread.h>

#include "ee/core/JniUtils.hpp"
#include "ee/core/Logger.hpp"
#include "ee/core/internal/JniMethodInfo.hpp"
#include "ee/core/internal/JniString.hpp"
#include "ee/core/Utils.hpp"

namespace ee {
namespace core {
namespace {
pthread_key_t key_value;
} // namespace

std::thread::id JniUtils::cocosThreadId_;
bool JniUtils::isCocosThreadMarked_ = false;
JavaVM* JniUtils::vm_ = nullptr;

void JniUtils::setVm(JavaVM* vm) {
    vm_ = vm;
    pthread_key_create(&key_value, &JniUtils::detachCurrentThread);
}

void JniUtils::markCocosThread() noexcept {
    isCocosThreadMarked_ = true;
    cocosThreadId_ = std::this_thread::get_id();
}

JNIEnv* JniUtils::getEnv() {
    // Retrieve the thread local JNIEnv pointer.
    JNIEnv* env = static_cast<JNIEnv*>(pthread_getspecific(key_value));

    if (env == nullptr) {
        // The JNIEnv pointer has not been created.
        // Attempt to create it.
        env = cacheEnv();
    }

    // Check Cocos thread.
//    if (isCocosThreadMarked_ && cocosThreadId_ != std::this_thread::get_id()) {
//        Logger::getSystemLogger().error(
//            "%s: current thread is not cocos2d-x thread!", __PRETTY_FUNCTION__);
//        Logger::getSystemLogger().warn("Backtrace: %s", dumpBacktrace(30).c_str());
//    }

    return env;
}

JNIEnv* JniUtils::cacheEnv() {
    if (vm_ == nullptr) {
        // JavaVM has not been set.
        throw std::runtime_error{
            "java vm has not been set, call setVm in main.cpp first!"};
    }

    JNIEnv* env = nullptr;
    jint result = vm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);

    switch (result) {
    case JNI_OK: {
        // Succeed.
        pthread_setspecific(key_value, static_cast<const void*>(env));
        return env;
    }

    case JNI_EDETACHED: {
        // Thread detached.
        // Attempt to reattach.
        auto status = vm_->AttachCurrentThread(&env, nullptr);
        if (status < 0) {
            Logger::getSystemLogger().error(
                "%s: failed to get the environment using "
                "AttachCurrentThread!",
                __PRETTY_FUNCTION__);
            return nullptr;
        }

        pthread_setspecific(key_value, static_cast<const void*>(env));
        return env;
    }

    case JNI_EVERSION: {
        Logger::getSystemLogger().error(
            "%s: JNI interface version 1.4 not supported!",
            __PRETTY_FUNCTION__);
        return nullptr;
    }

    default: {
        Logger::getSystemLogger().error(
            "%s: failed to get the environment using GetEnv!",
            __PRETTY_FUNCTION__);
        return nullptr;
    }
    }
}

void JniUtils::detachCurrentThread(void*) {
    vm_->DetachCurrentThread();
}

void JniUtils::checkException() {
    JNIEnv* env = getEnv();
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
}

std::string JniUtils::toString(jstring str) {
    if (str == nullptr) {
        return "";
    }

    JNIEnv* env = getEnv();
    jboolean isCopy;
    const char* chars = env->GetStringUTFChars(str, &isCopy);
    std::string result{chars};
    env->ReleaseStringUTFChars(str, chars);
    checkException();
    return result;
}

std::unique_ptr<JniString> JniUtils::toJavaString(const std::string& str) {
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
    auto u16str = converter.from_bytes(str);
    return toJavaString(u16str);
}

std::unique_ptr<JniString> JniUtils::toJavaString(const std::u16string& str) {
    return JniString::create(getEnv(), str);
}

std::unique_ptr<JniMethodInfo>
JniUtils::getStaticMethodInfo(const char* className, const char* methodName,
                              const char* signature) {
    JNIEnv* env = getEnv();

    jclass clazz = env->FindClass(className);
    checkException();

    if (clazz == nullptr) {
        Logger::getSystemLogger().error("%s: can not find class %s",
                                        __PRETTY_FUNCTION__, className);
        return nullptr;
    }

    jmethodID methodId = env->GetStaticMethodID(clazz, methodName, signature);
    checkException();

    if (methodId == nullptr) {
        Logger::getSystemLogger().error(
            "%s: can not find static method %s in %s with signature %s",
            __PRETTY_FUNCTION__, methodName, className, signature);
        return nullptr;
    }

    return JniMethodInfo::create(env, clazz, methodId);
}
} // namespace core
} // namespace ee
<|endoftext|>


<commit_before>/*
 * Win32OutputCapture.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/OutputCapture.hpp>

#include <windows.h>

#include <stdio.h>
#include <fcntl.h>

#include <core/Log.hpp>
#include <core/Error.hpp>
#include <core/BoostThread.hpp>
#include <core/BoostErrors.hpp>

namespace rstudio {
namespace core {
namespace system {

namespace {

void standardStreamCaptureThread(
       int readFd,
       const boost::function<void(const std::string&)>& outputHandler)
{
   try
   {
      while(true)
      {
         const int kBufferSize = 512;
         char buffer[kBufferSize];
         // read from the descriptor; this descriptor is attached to a pipe,
         // and this _read call blocks until we have some bytes or until the
         // descriptor is closed
         DWORD bytesRead = ::_read(readFd, &buffer, kBufferSize);
         if (bytesRead > 0)
         {
            // if we got some bytes, invoke the output handler
            outputHandler(std::string(buffer, bytesRead));
         }
         else if (bytesRead == 0)
         {
            // reading 0 bytes indicates that we've reached EOF, so we can
            // quit capturing (we don't expect this to happen)
            LOG_WARNING_MESSAGE("Reached end of input on standard stream");
            break;
         }
         else if (bytesRead < 0)
         {
            // we don't expect errors to ever occur (since the standard
            // streams are never closed) so log any that do and continue
            LOG_ERROR(systemError(::GetLastError(), ERROR_LOCATION));
         }
      }
   }
   CATCH_UNEXPECTED_EXCEPTION
}

Error ioError(const std::string& description, const ErrorLocation& location)
{
   boost::system::error_code ec(boost::system::errc::io_error,
                                boost::system::get_system_category());
   Error error(ec, location);
   error.addProperty("description", description);
   return error;
}

Error redirectToPipe(DWORD stdHandle,
                     FILE* fpStdFile,
                     int* pReadFd)
{
   HANDLE hWritePipe;

   // Create pipe--this returns two file descriptors corresponding to the
   // read and write ends of the pipe, respectively. Note that we formerly used
   // CreatePipe here; for reasons that are unclear, we couldn't reassign
   // the descriptor (i.e. the _dup2 call below) for pipe handles created
   // this way when more than one user has RStudio open (see case 4230).
   int pdfs[2];
   if (!::_pipe(pdfs, 4096, O_TEXT))
      return systemError(::GetLastError(), ERROR_LOCATION);

   // reset win32 standard handle
   hWritePipe = reinterpret_cast<HANDLE>(::_get_osfhandle(pdfs[1]));
   if (hWritePipe == INVALID_HANDLE_VALUE)
      return systemError(errno, ERROR_LOCATION);
   if (!::SetStdHandle(stdHandle, hWritePipe))
      return systemError(::GetLastError(), ERROR_LOCATION);

   // reassign the standard output/error file descriptor to the write end of
   // the pipe
   if (::_dup2(pdfs[1], _fileno(fpStdFile)) != 0)
      return systemError(errno, ERROR_LOCATION);

   // turn off buffering
   if (::setvbuf(fpStdFile, NULL, _IONBF, 0) != 0)
      return ioError("setvbuf", ERROR_LOCATION);

   // sync c++ std streams
   std::ios::sync_with_stdio();

   // return read descriptor
   *pReadFd = pdfs[0];
   return Success();
}

} // anonymous namespace

Error captureStandardStreams(
            const boost::function<void(const std::string&)>& stdoutHandler,
            const boost::function<void(const std::string&)>& stderrHandler)
{
   try
   {
      // redirect stdout
      int stdoutFd = 0;
      Error error = redirectToPipe(STD_OUTPUT_HANDLE, stdout, &stdoutFd);
      if (error)
         return error;

      // capture stdout
      boost::thread stdoutThread(boost::bind(standardStreamCaptureThread,
                                             stdoutFd,
                                             stdoutHandler));

      // optionally redirect stderror if handler was provided
      int stderrFd = 0;
      if (stderrHandler)
      {
         // redirect stderr
         error = redirectToPipe(STD_ERROR_HANDLE, stderr, &stderrFd);
         if (error)
            return error;

         // capture stderr
         boost::thread stderrThread(boost::bind(standardStreamCaptureThread,
                                                stderrFd,
                                                stderrHandler));
      }

      return Success();
   }
   catch(const boost::thread_resource_error& e)
   {
      return Error(boost::thread_error::ec_from_exception(e), ERROR_LOCATION);
   }
}

} // namespace system
} // namespace core
} // namespace rstudio

<commit_msg>Revert "fix ERROR_INVALID_BLOCK with multiple users on Windows"<commit_after>/*
 * Win32OutputCapture.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/OutputCapture.hpp>

#include <windows.h>

#include <stdio.h>
#include <fcntl.h>

#include <core/Log.hpp>
#include <core/Error.hpp>
#include <core/BoostThread.hpp>
#include <core/BoostErrors.hpp>

namespace rstudio {
namespace core {
namespace system {

namespace {

void standardStreamCaptureThread(
       HANDLE hReadPipe,
       const boost::function<void(const std::string&)>& outputHandler)
{
   try
   {
      while(true)
      {
         const int kBufferSize = 512;
         char buffer[kBufferSize];
         DWORD bytesRead = 0;
         if (::ReadFile(hReadPipe, &buffer, kBufferSize, &bytesRead, NULL))
         {
            if (bytesRead > 0)
               outputHandler(std::string(buffer, bytesRead));
         }
         else
         {
            // we don't expect errors to ever occur (since the standard
            // streams are never closed) so log any that do and continue
            LOG_ERROR(systemError(::GetLastError(), ERROR_LOCATION));
         }
      }
   }
   CATCH_UNEXPECTED_EXCEPTION
}

Error ioError(const std::string& description, const ErrorLocation& location)
{
   boost::system::error_code ec(boost::system::errc::io_error,
                                boost::system::get_system_category());
   Error error(ec, location);
   error.addProperty("description", description);
   return error;
}

Error redirectToPipe(DWORD stdHandle,
                     FILE* fpStdFile,
                     HANDLE* phReadPipe)
{
   // create pipe
   HANDLE hWritePipe;
   if (!::CreatePipe(phReadPipe, &hWritePipe, NULL, 0))
      return systemError(::GetLastError(), ERROR_LOCATION);

   // reset win32 standard handle
   if (!::SetStdHandle(stdHandle, hWritePipe))
      return systemError(::GetLastError(), ERROR_LOCATION);

   // reset c runtime library handle
   int fd = ::_open_osfhandle((intptr_t)hWritePipe, _O_TEXT);
   if (fd == -1)
      return ioError("_open_osfhandle", ERROR_LOCATION);
   if (::_dup2(fd, _fileno(fpStdFile)) != 0)
      return systemError(errno, ERROR_LOCATION);

   // turn off buffering
   if (::setvbuf(fpStdFile, NULL, _IONBF, 0) != 0)
      return ioError("setvbuf", ERROR_LOCATION);

   // sync c++ std streams
   std::ios::sync_with_stdio();

   return Success();
}

} // anonymous namespace

Error captureStandardStreams(
            const boost::function<void(const std::string&)>& stdoutHandler,
            const boost::function<void(const std::string&)>& stderrHandler)
{
   try
   {
      // redirect stdout
      HANDLE hReadStdoutPipe = NULL;
      Error error = redirectToPipe(STD_OUTPUT_HANDLE, stdout, &hReadStdoutPipe);
      if (error)
         return error;

      // capture stdout
      boost::thread stdoutThread(boost::bind(standardStreamCaptureThread,
                                             hReadStdoutPipe,
                                             stdoutHandler));

      // optionally redirect stderror if handler was provided
      HANDLE hReadStderrPipe = NULL;
      if (stderrHandler)
      {
         // redirect stderr
         error = redirectToPipe(STD_ERROR_HANDLE, stderr, &hReadStderrPipe);
         if (error)
            return error;

         // capture stderr
         boost::thread stderrThread(boost::bind(standardStreamCaptureThread,
                                                hReadStderrPipe,
                                                stderrHandler));
      }

      return Success();
   }
   catch(const boost::thread_resource_error& e)
   {
      return Error(boost::thread_error::ec_from_exception(e), ERROR_LOCATION);
   }
}

} // namespace system
} // namespace core
} // namespace rstudio

<|endoftext|>


<commit_before>/* HSacquire.cc *************************************************-*-c++-*-
**									**
**	                      G A M M A 				**
**								 	**
**	Hilbert Space Acquisitions		   Implementation	**
**								 	**
**	Copyright (c) 1990, 1991, 1992			 		**
**	Tilo Levante, Scott Smith			 		**
**	Eidgenoessische Technische Hochschule	 			**
**	Labor fuer physikalische Chemie			 		**
**	8092 Zurich / Switzerland		 			**
**						 			**
**      $Header: $
**								 	**
*************************************************************************/

/*************************************************************************
**								 	**
** Description							 	**
**								 	**
** The GAMMA Platform Provides Functions for Simulation	of Magnetic	**
** Resonance Experiments and Other Associated 	Mathematical		**
** Capabilities.  The Set of Functions Herein Allow for the Simulation	**
** of Free Induction Decays(FID's) in Spin Hilbert Space & Adds 	**
** Abilities Related To Simulated Data Acquistion.			**
**								 	**
*************************************************************************/

#ifndef   HSacquire_cc_			// Is file already included?
#  define HSacquire_cc_ 1		// If no, then remember it
#  if defined(GAMPRAGMA)		// Using the GNU compiler?
#    pragma implementation		// This is the implementation
#  endif

#include <HSLib/HSacquire.h>		// Include the file header
#include <Matrix/row_vector.h>		// Knowledge of row vectors
#include <HSLib/GenOp.h>		// Knowledge of operators
//#include <HSLib/HSprop.h>		// Knowledge of nmr evolutions
#include <Basics/Gconstants.h>		// Knowledge of PI

// ____________________________________________________________________________
// A		         Generic Free Induction Decays
// ____________________________________________________________________________

/* These functions fill up a row vector with a Free Induction Decay (FID) based
   upon an initial density operator representing the initial state of the spin
   system evolving under a static Hamiltonian. The user specifies the property
   detected (usually transverse magnetization) as well as the time between FID
   points (dwell time). Note that the acquire1D class will also generate FID's
   (see the Level 1 Module in GAMMA) but is much more flexible. Also note that
   if one intends to apply a Fourier transform to the generated FID it should
   have a point size that is base 2 (e.g. 2048, 4096, .....)

	Input		sig0  : Operator propagated (initial dens. op.)
			D     : Detection operator in trace computation
	 		H     : Hamiltonian for propagation (in Hertz)
			U     : Propagator for one increment
	 		td    : Dwell time (seconds, per point)
	 		N     : Number of FID points generated
			fid   :	Data vector containing the result
	Output		      : None, FID data vector filled
	Note		      : Assumed fid is at least as large as N
	Note		      : Propagator is unitless, so 2*PI factor
				used to get radians in exponent
        Note		      : If no block size is specified it will
                                be taken as the vector size
        Note		      : If no vector is specified on will be
                                generated and returned                      */

void acquire(gen_op& S, gen_op& D, gen_op& H, double T, int N, row_vector& F, double CO)
  { FID(S,D,H,T,N,F,CO); }
void FID(gen_op& sig0, gen_op& D, gen_op& H, double td, int N, row_vector& fid, double CO)
  {
  if(fid.size() < N) fid=row_vector(N);	// Insure block is large enough
  H.set_EBR();				// First put H into its eigenbase
  sig0.Op_base(H);			// Next put sig0 into eigenbase of H
  D.Op_base(H);				// Put detection op. to eigenbase of H
  complex z(0,-PIx2*td);		// Exponential factor for H -> U
  gen_op U;				// Propagator for evolution
  if(td) U = (z*H).exp();		// Set the td evolution propagator
  else   U = H;				// If td = 0, assume U was input
  int hs = dim(H);			// Hilbert space dimension
  int ls = hs*hs;			// Liouville space dimension
  complex *A = new complex[ls];		// Array for A(p)
  complex *B = new complex[ls];		// Array for B(p)

  int i,j,pos;
  for(pos=0,i=0; i<hs; i++)		// Generate the A & B arrays
    for(j=0; j<hs; j++)			// We'll only count non-zero
      {					// contributors to acquisition
      A[pos] = D(i,j)*sig0(j,i);
      B[pos] = conj(U(i,i), U(j,j));
      if(square_norm(A[pos])>CO) 	// Use elements if trace contribution
	pos ++;
      }

  for(int k=0; k<N; k++)		// Loop over desired points (& times)
    {
    z = 0;				//   Begin with zero point
    for(int p=0; p<pos; p++)		//   Loop over point contributors
      {
      z += A[p];			//      Add contribution from p
      A[p] *= B[p];			//	                          k+1
      }					//      Adjust A so its really A*B
    fid.put(z,k);			//   Set point, move to next k (time)
    }
  delete [] A;				// Delete complex array A
  delete [] B;				// Delete complex array B
  }

void acquire(gen_op& sig0 , gen_op& D, gen_op& U, int N, row_vector& fid, double CO)
  { FID(sig0, D, U, 0, N, fid, CO); }
void FID(gen_op& sig0 , gen_op& D, gen_op& U, int N, row_vector& fid, double CO)
  { FID(sig0, D, U, 0, N, fid, CO); }
void FID(gen_op& sig0 , gen_op& D, HSprop& U, int N, row_vector& fid, double CO)
  { gen_op UOp = U.Op(); FID(sig0, D, UOp, 0, N, fid, CO); }

row_vector acquire(gen_op& sig0 , gen_op& D, gen_op& H, double td, int N, double CO)
  { row_vector data(N); FID(sig0,D,H,td,N,data,CO); return data; }
row_vector FID(gen_op& sig0 , gen_op& D, gen_op& H, double td, int N, double CO)
  { row_vector data(N); FID(sig0,D,H,td,N,data,CO); return data; }

row_vector acquire(gen_op& sig0 , gen_op& D, gen_op& U, int N, double CO)
  { row_vector data(N); FID(sig0,D,U,0,N,data,CO); return data; }
row_vector FID(gen_op& sig0 , gen_op& D, gen_op& U, int N, double CO)
  { row_vector data(N); FID(sig0,D,U,0,N,data,CO); return data; }
row_vector FID(gen_op& sig0 , gen_op& D, HSprop& U, int N, double CO)
  { row_vector data(N); gen_op UOp=U.Op(); FID(sig0,D,UOp,0,N,data,CO); return data; }

// ____________________________________________________________________________
// B		   Acquisiton Generation Output Functions
// ____________________________________________________________________________

/* This functions exist primarly to check the acquisition functions found
   earlier in this file. They will simply print output aspects of the
   calculation used for the specified input parameters.                      */

// ____________________________________________________________________________
// S                         PyGAMMA Code (Non-Member)
// ____________________________________________________________________________

/* Every function in this module uses preset values in the function calls. This
   forces us to declare overloads for each function.... ouch. However, the
   above functions also double up on the names "acquire" and "FID". That is,
   each acquire function has the same function defined with the name FID.
   Since we can rename the functions in Boost.Python, we will only expand on the
   overloads of the FID function then rename them to acquire functions too.
   Lastly, to handle the overloads cleanly, we can use the Boost.Python defined
   ones, but then we must have distinguishable functions too.                */

#ifdef PYGAMMA					// Begin PyGAMMA code block

#include <boost/python/def.hpp>
#include <boost/python/overloads.hpp>

using boost::python::def;

void FID1(gen_op& sig0,gen_op& D,gen_op& H,double td,int N,row_vector& fid,double CO) { FID(sig0,D,H,td,N,fid,CO); }
void FID2(gen_op& sig0,gen_op& D,gen_op& U,          int N,row_vector& fid,double CO) { FID(sig0,D,U,   N,fid,CO); }
void FID3(gen_op& sig0,gen_op& D,HSprop& U,          int N,row_vector& fid,double CO) { FID(sig0,D,U,   N,fid,CO); }

row_vector FID4(gen_op& sig0, gen_op& D, gen_op& H, double td, int N, double CO) { return FID(sig0,D,H,td,N,CO); }
row_vector FID5(gen_op& sig0, gen_op& D, gen_op& U,            int N, double CO) { return FID(sig0,D,U   ,N,CO); }
row_vector FID6(gen_op& sig0, gen_op& D, HSprop& U,            int N, double CO) { return FID(sig0,D,U   ,N,CO); }

BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID1, FID1, 6, 7)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID2, FID2, 5, 6)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID3, FID3, 5, 6)

BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID4, FID4, 5, 6)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID5, FID5, 4, 5)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID6, FID6, 4, 5)

void PyHSAcquire()
  {
  def("acquire", (void(*)(gen_op&, gen_op&, gen_op&, double, int, row_vector&, double))0, hslib_FID1());
  def("acquire", (void(*)(gen_op&, gen_op&, gen_op&,         int, row_vector&, double))0, hslib_FID2());
  def("acquire", (void(*)(gen_op&, gen_op&, HSprop&,         int, row_vector&, double))0, hslib_FID3());
  def("FID",     (void(*)(gen_op&, gen_op&, gen_op&, double, int, row_vector&, double))0, hslib_FID1());
  def("FID",     (void(*)(gen_op&, gen_op&, gen_op&,         int, row_vector&, double))0, hslib_FID2());
  def("FID",     (void(*)(gen_op&, gen_op&, HSprop&,         int, row_vector&, double))0, hslib_FID3());

  def("acquire", (row_vector(*)(gen_op&, gen_op&, gen_op&, double, int, double))0, hslib_FID4());
  def("acquire", (row_vector(*)(gen_op&, gen_op&, gen_op&,         int, double))0, hslib_FID5());
  def("acquire", (row_vector(*)(gen_op&, gen_op&, HSprop&,         int, double))0, hslib_FID6());
  def("FID",     (row_vector(*)(gen_op&, gen_op&, gen_op&, double, int, double))0, hslib_FID4());
  def("FID",     (row_vector(*)(gen_op&, gen_op&, gen_op&,         int, double))0, hslib_FID5());
  def("FID",     (row_vector(*)(gen_op&, gen_op&, HSprop&,         int, double))0, hslib_FID6());
  }

#endif						// End of PyGAMMA code block

// ____________________________________________________________________________
// Z		      Free Induction Decay Applied Theory
// ____________________________________________________________________________

/* We will work in the eigenbasis of the propergator U, where U is generated
   from the static Hamiltonian H as

                                      -2*pi*i*H*td
                                 U = e

   Both U and H are represented by diagonal matrices in this eigenbasis and
   since H is Hermtitian, U will be unitary (adjoint == inverse).  An
   acquisition point k, which corresponds to time t = k*td, is given by

   fid(k) = Trace { D * sigma(t) }

                         k                        k
          = Trace { D * U (td)  * sig0 * adjoint[U (td)] }

                                 k                            k
          = Sum i,j { <i|D|j><j|U (td)|j>*<j|sig0|i>*conj(<i|U (td)|i>) }

                                                                 k
          = Sum i,j { <i|D|j><j|sig0|i> * [<j|U|j>*conj(<i|U|i>)]  }

                                     k                        k
          = Sum i,j { A(i,j) * B(i,j) }    =  Sum p { A(p) * B (p) }

   The FID functions all implement the last form for generating a series
   of expectation values evenly incremented in time.  The routines will
   immediately generate the arrays A and B then quicky do the sum. The
   points are repeatly generated by taking powers of B elements.             */

#endif 							// HSacquire.cc
<commit_msg>Rearranged functions so it is more clear where I  will be adding new code - shortly.<commit_after>/* HSacquire.cc *************************************************-*-c++-*-
**									**
**	                      G A M M A 				**
**								 	**
**	Hilbert Space Acquisitions		   Implementation	**
**								 	**
**	Copyright (c) 1990, 1991, 1992			 		**
**	Tilo Levante, Scott Smith			 		**
**	Eidgenoessische Technische Hochschule	 			**
**	Labor fuer physikalische Chemie			 		**
**	8092 Zurich / Switzerland		 			**
**						 			**
**      $Header: $
**								 	**
*************************************************************************/

/*************************************************************************
**								 	**
** Description							 	**
**								 	**
** The GAMMA Platform Provides Functions for Simulation	of Magnetic	**
** Resonance Experiments and Other Associated 	Mathematical		**
** Capabilities.  The Set of Functions Herein Allow for the Simulation	**
** of Free Induction Decays(FID's) in Spin Hilbert Space & Adds 	**
** Abilities Related To Simulated Data Acquistion.			**
**								 	**
*************************************************************************/

#ifndef   HSacquire_cc_			// Is file already included?
#  define HSacquire_cc_ 1		// If no, then remember it
#  if defined(GAMPRAGMA)		// Using the GNU compiler?
#    pragma implementation		// This is the implementation
#  endif

#include <HSLib/HSacquire.h>		// Include the file header
#include <Matrix/row_vector.h>		// Knowledge of row vectors
#include <HSLib/GenOp.h>		// Knowledge of operators
//#include <HSLib/HSprop.h>		// Knowledge of nmr evolutions
#include <Basics/Gconstants.h>		// Knowledge of PI

// ____________________________________________________________________________
// A		         Generic Free Induction Decays
// ____________________________________________________________________________

/* These functions fill up a row vector with a Free Induction Decay (FID) based
   upon an initial density operator representing the initial state of the spin
   system evolving under a static Hamiltonian. The user specifies the property
   detected (usually transverse magnetization) as well as the time between FID
   points (dwell time). Note that the acquire1D class will also generate FID's
   (see the Level 1 Module in GAMMA) but is much more flexible. Also note that
   if one intends to apply a Fourier transform to the generated FID it should
   have a point size that is base 2 (e.g. 2048, 4096, .....)

	Input		sig0  : Operator propagated (initial dens. op.)
			D     : Detection operator in trace computation
	 		H     : Hamiltonian for propagation (in Hertz)
			U     : Propagator for one increment
	 		td    : Dwell time (seconds, per point)
	 		N     : Number of FID points generated
			fid   :	Data vector containing the result
	Output		      : None, FID data vector filled
	Note		      : Assumed fid is at least as large as N
	Note		      : Propagator is unitless, so 2*PI factor
				used to get radians in exponent
        Note		      : If no block size is specified it will
                                be taken as the vector size
        Note		      : If no vector is specified on will be
                                generated and returned                      */

void acquire(gen_op& S, gen_op& D, gen_op& H, double T, int N, row_vector& F, double CO)
  { FID(S,D,H,T,N,F,CO); }

void acquire(gen_op& sig0 , gen_op& D, gen_op& U, int N, row_vector& fid, double CO)
  { FID(sig0, D, U, 0, N, fid, CO); }

void FID(gen_op& sig0, gen_op& D, gen_op& H, double td, int N, row_vector& fid, double CO)
  {
  if(fid.size() < N) fid=row_vector(N);	// Insure block is large enough
  H.set_EBR();				// First put H into its eigenbase
  sig0.Op_base(H);			// Next put sig0 into eigenbase of H
  D.Op_base(H);				// Put detection op. to eigenbase of H
  complex z(0,-PIx2*td);		// Exponential factor for H -> U
  gen_op U;				// Propagator for evolution
  if(td) U = (z*H).exp();		// Set the td evolution propagator
  else   U = H;				// If td = 0, assume U was input
  int hs = dim(H);			// Hilbert space dimension
  int ls = hs*hs;			// Liouville space dimension
  complex *A = new complex[ls];		// Array for A(p)
  complex *B = new complex[ls];		// Array for B(p)

  int i,j,pos;
  for(pos=0,i=0; i<hs; i++)		// Generate the A & B arrays
    for(j=0; j<hs; j++)			// We'll only count non-zero
      {					// contributors to acquisition
      A[pos] = D(i,j)*sig0(j,i);
      B[pos] = conj(U(i,i), U(j,j));
      if(square_norm(A[pos])>CO) 	// Use elements if trace contribution
	pos ++;
      }

  for(int k=0; k<N; k++)		// Loop over desired points (& times)
    {
    z = 0;				//   Begin with zero point
    for(int p=0; p<pos; p++)		//   Loop over point contributors
      {
      z += A[p];			//      Add contribution from p
      A[p] *= B[p];			//	                          k+1
      }					//      Adjust A so its really A*B
    fid.put(z,k);			//   Set point, move to next k (time)
    }
  delete [] A;				// Delete complex array A
  delete [] B;				// Delete complex array B
  }

void FID(gen_op& sig0 , gen_op& D, gen_op& U, int N, row_vector& fid, double CO)
  { FID(sig0, D, U, 0, N, fid, CO); }

void FID(gen_op& sig0 , gen_op& D, HSprop& U, int N, row_vector& fid, double CO)
  { gen_op UOp = U.Op(); FID(sig0, D, UOp, 0, N, fid, CO); }

row_vector acquire(gen_op& sig0 , gen_op& D, gen_op& H, double td, int N, double CO)
  { row_vector data(N); FID(sig0,D,H,td,N,data,CO); return data; }

row_vector acquire(gen_op& sig0 , gen_op& D, gen_op& U, int N, double CO)
  { row_vector data(N); FID(sig0,D,U,0,N,data,CO); return data; }

row_vector FID(gen_op& sig0 , gen_op& D, gen_op& H, double td, int N, double CO)
  { row_vector data(N); FID(sig0,D,H,td,N,data,CO); return data; }

row_vector FID(gen_op& sig0 , gen_op& D, gen_op& U, int N, double CO)
  { row_vector data(N); FID(sig0,D,U,0,N,data,CO); return data; }

row_vector FID(gen_op& sig0 , gen_op& D, HSprop& U, int N, double CO)
  { row_vector data(N); gen_op UOp=U.Op(); FID(sig0,D,UOp,0,N,data,CO); return data; }

// ____________________________________________________________________________
// B		   Acquisiton Generation Output Functions
// ____________________________________________________________________________

/* This functions exist primarly to check the acquisition functions found
   earlier in this file. They will simply print output aspects of the
   calculation used for the specified input parameters.                      */

// ____________________________________________________________________________
// S                         PyGAMMA Code (Non-Member)
// ____________________________________________________________________________

/* Every function in this module uses preset values in the function calls. This
   forces us to declare overloads for each function.... ouch. However, the
   above functions also double up on the names "acquire" and "FID". That is,
   each acquire function has the same function defined with the name FID.
   Since we can rename the functions in Boost.Python, we will only expand on the
   overloads of the FID function then rename them to acquire functions too.
   Lastly, to handle the overloads cleanly, we can use the Boost.Python defined
   ones, but then we must have distinguishable functions too.                */

#ifdef PYGAMMA					// Begin PyGAMMA code block

#include <boost/python/def.hpp>
#include <boost/python/overloads.hpp>

using boost::python::def;

void FID1(gen_op& sig0,gen_op& D,gen_op& H,double td,int N,row_vector& fid,double CO) { FID(sig0,D,H,td,N,fid,CO); }
void FID2(gen_op& sig0,gen_op& D,gen_op& U,          int N,row_vector& fid,double CO) { FID(sig0,D,U,   N,fid,CO); }
void FID3(gen_op& sig0,gen_op& D,HSprop& U,          int N,row_vector& fid,double CO) { FID(sig0,D,U,   N,fid,CO); }

row_vector FID4(gen_op& sig0, gen_op& D, gen_op& H, double td, int N, double CO) { return FID(sig0,D,H,td,N,CO); }
row_vector FID5(gen_op& sig0, gen_op& D, gen_op& U,            int N, double CO) { return FID(sig0,D,U   ,N,CO); }
row_vector FID6(gen_op& sig0, gen_op& D, HSprop& U,            int N, double CO) { return FID(sig0,D,U   ,N,CO); }

BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID1, FID1, 6, 7)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID2, FID2, 5, 6)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID3, FID3, 5, 6)

BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID4, FID4, 5, 6)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID5, FID5, 4, 5)
BOOST_PYTHON_FUNCTION_OVERLOADS(hslib_FID6, FID6, 4, 5)

void PyHSAcquire()
  {
  def("acquire", (void(*)(gen_op&, gen_op&, gen_op&, double, int, row_vector&, double))0, hslib_FID1());
  def("acquire", (void(*)(gen_op&, gen_op&, gen_op&,         int, row_vector&, double))0, hslib_FID2());
  def("acquire", (void(*)(gen_op&, gen_op&, HSprop&,         int, row_vector&, double))0, hslib_FID3());
  def("FID",     (void(*)(gen_op&, gen_op&, gen_op&, double, int, row_vector&, double))0, hslib_FID1());
  def("FID",     (void(*)(gen_op&, gen_op&, gen_op&,         int, row_vector&, double))0, hslib_FID2());
  def("FID",     (void(*)(gen_op&, gen_op&, HSprop&,         int, row_vector&, double))0, hslib_FID3());

  def("acquire", (row_vector(*)(gen_op&, gen_op&, gen_op&, double, int, double))0, hslib_FID4());
  def("acquire", (row_vector(*)(gen_op&, gen_op&, gen_op&,         int, double))0, hslib_FID5());
  def("acquire", (row_vector(*)(gen_op&, gen_op&, HSprop&,         int, double))0, hslib_FID6());
  def("FID",     (row_vector(*)(gen_op&, gen_op&, gen_op&, double, int, double))0, hslib_FID4());
  def("FID",     (row_vector(*)(gen_op&, gen_op&, gen_op&,         int, double))0, hslib_FID5());
  def("FID",     (row_vector(*)(gen_op&, gen_op&, HSprop&,         int, double))0, hslib_FID6());
  }

#endif						// End of PyGAMMA code block

// ____________________________________________________________________________
// Z		      Free Induction Decay Applied Theory
// ____________________________________________________________________________

/* We will work in the eigenbasis of the propergator U, where U is generated
   from the static Hamiltonian H as

                                      -2*pi*i*H*td
                                 U = e

   Both U and H are represented by diagonal matrices in this eigenbasis and
   since H is Hermtitian, U will be unitary (adjoint == inverse).  An
   acquisition point k, which corresponds to time t = k*td, is given by

   fid(k) = Trace { D * sigma(t) }

                         k                        k
          = Trace { D * U (td)  * sig0 * adjoint[U (td)] }

                                 k                            k
          = Sum i,j { <i|D|j><j|U (td)|j>*<j|sig0|i>*conj(<i|U (td)|i>) }

                                                                 k
          = Sum i,j { <i|D|j><j|sig0|i> * [<j|U|j>*conj(<i|U|i>)]  }

                                     k                        k
          = Sum i,j { A(i,j) * B(i,j) }    =  Sum p { A(p) * B (p) }

   The FID functions all implement the last form for generating a series
   of expectation values evenly incremented in time.  The routines will
   immediately generate the arrays A and B then quicky do the sum. The
   points are repeatly generated by taking powers of B elements.             */

#endif 							// HSacquire.cc
<|endoftext|>