////////////////////////////////////////////////////////////////////////////////
// 
// Graphics.cc
//
//    produced: 14 Jul 2021 jr
// last change: 14 Jul 2021 jr
//
////////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <thread>
#include <cstdlib>

#include "Graphics.hh"

namespace topcom {

  std::fstream Graphics::_asy_stream;
  parameter_type Graphics::_no;
  parameter_type Graphics::_rank;

  void Graphics::init_asy(const char* asy_file) {
    std::cerr << "initializing graphics for asymptote ..." << std::endl;

    std::cerr << "... output file: " << CommandlineOptions::asy_file() << " ..." << std::endl;
    Graphics::asy_stream().open(CommandlineOptions::asy_file(), std::ios::out | std::ios::trunc);
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// graphics command file for asymptote (automatically generated by TOPCOM)" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::header_to_asy(const parameter_type no, const parameter_type rank) {
    _no = no;
    _rank = rank;
    std::cerr << "writing header section to asymptote ..." << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "import Combinatorial_Geometry;" << std::endl;
    Graphics::asy_stream() << "import palette;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "usepackage(\"amsmath\");" << std::endl;
    Graphics::asy_stream() << "usepackage(\"amsthm\");" << std::endl;
    Graphics::asy_stream() << "usepackage(\"bclogo\");" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "locale(\"C\");" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "string filename_postfix = \"_\";" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "node_type[][][] tree_nodes;" << std::endl;
    Graphics::asy_stream() << "int[][][][]   tree_arcs;" << std::endl;
    Graphics::asy_stream() << "int[][][]     deadend_nodes;" << std::endl;
    Graphics::asy_stream() << "int[][][]     earlydeadend_nodes;" << std::endl;
    Graphics::asy_stream() << "int[][][]     veryearlydeadend_nodes;" << std::endl;
    Graphics::asy_stream() << "int[][][]     missingvolume_nodes;" << std::endl;
    Graphics::asy_stream() << "int[][][]     notnew_nodes;" << std::endl;
    Graphics::asy_stream() << "int[][][]     solution_nodes;" << std::endl;
    Graphics::asy_stream() << "bool draw_graphics = false;" << std::endl;
    Graphics::asy_stream() << "real size_x = 10;" << std::endl;
    Graphics::asy_stream() << "real size_y = 10;" << std::endl;
    Graphics::asy_stream() << "real center_x = 0;" << std::endl;
    Graphics::asy_stream() << "real center_y = 0;" << std::endl;
    Graphics::asy_stream() << "real scale_symbols = size_x / (18pt);" << std::endl;    
    Graphics::asy_stream() << "real thicklinewidth = size_x * 0.05pt;" << std::endl;    
    Graphics::asy_stream() << "real thinlinewidth = size_x * 0.02pt;" << std::endl;    
    Graphics::asy_stream() << std::endl;
    std::cerr << "... done." << std::endl;
  }
  void Graphics::nodesize_for_pointsgraphics_to_asy() {
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of size correction if points are drawn as nodes:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "size_y = scale_pointconf * coord_size_y;" << std::endl;
    Graphics::asy_stream() << "/////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of size correction if points are drawn as nodes." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
  }

  void Graphics::vertices_to_asy(const Vertices& verts) {
    std::cerr << "writing vertices section to asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of vertices section (indices of vertices go here):" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "int[] A_extremepoints = " << (vertices_data)verts << ";" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "/////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of vertices section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::points_to_asy(const PointConfiguration& pc) { 
    std::cerr << "writing points section to asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of points section (coordinates of points go here):" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;

    // check how the point configuration was homogenized:
    bool z_all_ones = true;
    for (parameter_type i = 0; i < pc.size(); ++i) {
      if (pc[i][2] != 1) {
	z_all_ones = false;
	break;
      }
    }

    if (z_all_ones) {

      // ignore the z-coordinate:
      Graphics::asy_stream() << "pair[] point_coords = {";
      for (parameter_type i = 0; i < pc.no(); ++i) {
	Graphics::asy_stream() << "(" <<  pc[i][0] << ", " << pc[i][1]  << ")";
	if (i < pc.no() - 1) {
	  Graphics::asy_stream() << ", ";
	}
      }      
    }
    else {

      // assume the plane with coordinate sum equal to one:
      Graphics::asy_stream() << "pair[] point_coords = {";
      for (parameter_type i = 0; i < pc.no(); ++i) {
	Graphics::asy_stream() << "(" <<  -pc[i][0] / 2 + pc[i][1] / 2 << ", " << -sqrt(3) * pc[i][0] / 6 - sqrt(3) * pc[i][1] / 6 + sqrt(3) * pc[i][2] / 3 << ")";
	if (i < pc.no() - 1) {
	  Graphics::asy_stream() << ", ";
	}
      }
    }
    Graphics::asy_stream() << "};" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "real max_x = point_coords[0].x;" << std::endl;
    Graphics::asy_stream() << "real min_x = point_coords[0].x;" << std::endl;
    Graphics::asy_stream() << "real max_y = point_coords[0].y;" << std::endl;
    Graphics::asy_stream() << "real min_y = point_coords[0].y;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int i = 1; i < point_coords.length; ++i) {" << std::endl;
    Graphics::asy_stream() << "  if (point_coords[i].x > max_x) {" << std::endl;
    Graphics::asy_stream() << "    max_x = point_coords[i].x;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  if (point_coords[i].x < min_x) {" << std::endl;
    Graphics::asy_stream() << "    min_x = point_coords[i].x;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  if (point_coords[i].y > max_y) {" << std::endl;
    Graphics::asy_stream() << "    max_y = point_coords[i].y;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  if (point_coords[i].y < min_y) {" << std::endl;
    Graphics::asy_stream() << "    min_y = point_coords[i].y;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "real coord_size_x = (max_x - min_x);" << std::endl;
    Graphics::asy_stream() << "real coord_size_y = (max_y - min_y);" << std::endl;
    Graphics::asy_stream() << "real scale_pointconf = size_x / coord_size_x;" << std::endl;
    Graphics::asy_stream() << "center_x = scale_pointconf * ((max_x + min_x) / 2);" << std::endl;
    Graphics::asy_stream() << "center_y = scale_pointconf * ((max_y + min_y) / 2);" << std::endl;
    Graphics::asy_stream() << "scale_symbols = size_x / (18pt);" << std::endl;    
    Graphics::asy_stream() << "thicklinewidth = size_x * 0.05pt;" << std::endl;    
    Graphics::asy_stream() << "thinlinewidth = size_x * 0.02pt;" << std::endl;    
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "default_pointconf_pen = default_pointconf_pen + linewidth(thicklinewidth);" << std::endl;
    Graphics::asy_stream() << "secondary_pointconf_pen = secondary_pointconf_pen + linewidth(thinlinewidth);" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "pointconf A = shift(-center_x, -center_y) * scale(scale_pointconf) * pointconf(L=Label(\"\", align=S), coords=point_coords, extremepoints=A_extremepoints, start_label=0);" << std::endl;
    Graphics::asy_stream() << "pointconf A_scaled = scale(10) * pointconf(A, copy=true);" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "picture pointconf_pic;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "A_scaled.draw(pic=pointconf_pic);" << std::endl;
    Graphics::asy_stream() << "shipout(\"TOPCOM\" + filename_postfix + \"points\", pointconf_pic);" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of points section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::typedef_for_labelset_to_asy() {
    std::cerr << "generating data structures for new worker for asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin node type section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "struct node_type {" << std::endl;
    Graphics::asy_stream() << "  int[] labelset;" << std::endl;
    Graphics::asy_stream() << "  void operator init(int[] init_labelset) {" << std::endl;
    Graphics::asy_stream() << "    labelset = copy(init_labelset);" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  int length() {" << std::endl;
    Graphics::asy_stream() << "    return labelset.length;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "};" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end node type section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
  }

  void Graphics::typedef_for_partialtriang_to_asy() {
    std::cerr << "generating data structures for new worker for asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin node type section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "struct node_type {" << std::endl;
    Graphics::asy_stream() << "  int[]   labelset;" << std::endl;
    Graphics::asy_stream() << "  int[][] partialtriang;" << std::endl;
    Graphics::asy_stream() << "  void operator init(int[] init_labelset, int[][] init_partialtriang) {" << std::endl;
    Graphics::asy_stream() << "    labelset      = copy(init_labelset) ;" << std::endl;
    Graphics::asy_stream() << "    partialtriang = copy(init_partialtriang);" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  int length() {" << std::endl;
    Graphics::asy_stream() << "    return labelset.length;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "};" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end node type section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::typedef_for_matrix_to_asy() {
    std::cerr << "generating data structures for new worker for asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin node type section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "struct node_type {" << std::endl;
    Graphics::asy_stream() << "  int[]    labelset;" << std::endl;
    Graphics::asy_stream() << "  real[][] matrix;" << std::endl;
    Graphics::asy_stream() << "  void operator init(int[] init_labelset, real[][] init_matrix) {" << std::endl;
    Graphics::asy_stream() << "    labelset = copy(init_labelset);" << std::endl;
    Graphics::asy_stream() << "    matrix   = copy(init_matrix);" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  int length() {" << std::endl;
    Graphics::asy_stream() << "    return labelset.length;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "};" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end node type section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
  }

  void Graphics::worker_to_asy() {
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    std::cerr << "generating data structures for new worker for asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// new worker:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "tree_nodes.push(new node_type[][]);" << std::endl;
    Graphics::asy_stream() << "tree_arcs.push(new int[][][]);" << std::endl;
    Graphics::asy_stream() << "deadend_nodes.push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "earlydeadend_nodes.push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "veryearlydeadend_nodes.push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "missingvolume_nodes.push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "notnew_nodes.push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "solution_nodes.push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end new worker." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    std::cerr << "... done." << std::endl;
  }

  void Graphics::run_to_asy(const int workerID) {
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    std::cerr << "generating data structures for new run for worker " << workerID << " for asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// new run for worker " << workerID << ":" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "tree_nodes[" << workerID << "].push(new node_type[]);" << std::endl;
    Graphics::asy_stream() << "tree_arcs[" << workerID << "].push(new int[][]);" << std::endl;
    Graphics::asy_stream() << "deadend_nodes[" << workerID << "].push(new int[]);" << std::endl;
    Graphics::asy_stream() << "earlydeadend_nodes[" << workerID << "].push(new int[]);" << std::endl;
    Graphics::asy_stream() << "veryearlydeadend_nodes[" << workerID << "].push(new int[]);" << std::endl;
    Graphics::asy_stream() << "missingvolume_nodes[" << workerID << "].push(new int[]);" << std::endl;
    Graphics::asy_stream() << "notnew_nodes[" << workerID << "].push(new int[]);" << std::endl;
    Graphics::asy_stream() << "solution_nodes[" << workerID << "].push(new int[]);" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end new run for worker " << workerID << "." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::labelset_to_asy(const int workerID, const size_type runID, const LabelSet& l) {

    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new label set node:" << std::endl;
    Graphics::asy_stream() << "tree_nodes[" << workerID << "][" << runID << "].push(node_type(new int[] "
			   << l
			   << "));" << std::endl;
    Graphics::asy_stream() << "// end new label set node." << std::endl;
  }

  void Graphics::partialtriang_to_asy(const int workerID, const size_type runID, const IntegerSet& l, const SimplicialComplex& t) {

    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new partial triangulation node:" << std::endl;
    Graphics::asy_stream() << "tree_nodes[" << workerID << "][" << runID << "].push(node_type(new int[] "
			   << l
			   << ", "
			   << "new int[][] "
			   << t
			   << "));" << std::endl;
    Graphics::asy_stream() << "// end new partial triangulation node." << std::endl;
  }

  void Graphics::matrix_to_asy(const int workerID, const size_type runID, const LabelSet& l, const StairCaseMatrix& m) {

    static int cnt = 0;
    
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new staircase matrix:" << std::endl;
    Graphics::asy_stream() << "int rowdim_" << cnt << " = " << m.rowdim() << ";" << std::endl;
    Graphics::asy_stream() << "int coldim_" << cnt << " = " << m.coldim() << ";" << std::endl;
    Graphics::asy_stream() << "real[][] new_matrix_" << cnt <<  " = new real[coldim_" << cnt << "][rowdim_" << cnt << "];" << std::endl;
    const parameter_type rowdim = m.rowdim();
    const parameter_type coldim = m.coldim();
    for (parameter_type col = 0; col < coldim; ++col) {
      for (parameter_type row = 0; row < rowdim; ++row) {
	Graphics::asy_stream() << "new_matrix_" << cnt << "[" << col << "][" << row << "] = " << m(row, col) << ";" << std::endl;
      }
    }
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new label set:" << std::endl;
    Graphics::asy_stream() << "int[] new_labelset_" << cnt << " = new int[] " << l << ";" << std::endl;
    Graphics::asy_stream() << "// end new label set." << std::endl;
    Graphics::asy_stream() << std::endl;
   
    Graphics::asy_stream() << "// begin new node:" << std::endl;
    Graphics::asy_stream() << "tree_nodes[" << workerID << "][" << runID << "].push(node_type("
			   <<  "new_labelset_" << cnt
			   << ", new_matrix_" << cnt << "));" << std::endl;
    Graphics::asy_stream() << "// end new node." << std::endl;
    ++cnt;
  }

  void Graphics::arc_to_asy(const int workerID, const size_type runID, const size_type nodeID1, const size_type nodeID2) {	

    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new extension arc:" << std::endl;
    Graphics::asy_stream() << "tree_arcs[" << workerID << "][" << runID << "].push(new int[] {"
	      << nodeID1 << ", "
	      << nodeID2 << "});" << std::endl;
    Graphics::asy_stream() << "// end new extension arc." << std::endl;
  }

  void Graphics::deadend_to_asy(const int workerID, const size_type runID, const size_type nodeID) {
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new deadend node:" << std::endl;
    Graphics::asy_stream() << "deadend_nodes[" << workerID << "][" << runID << "].push(" << nodeID << ");" << std::endl;
    Graphics::asy_stream() << "// end new deadend node." << std::endl;
  }
  
  void Graphics::earlydeadend_to_asy(const int workerID, const size_type runID, const size_type nodeID) {
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new earlydeadend node:" << std::endl;
    Graphics::asy_stream() << "earlydeadend_nodes[" << workerID << "][" << runID << "].push(" << nodeID << ");" << std::endl;
    Graphics::asy_stream() << "// end new earlydeadend node." << std::endl;
  }
  
  void Graphics::veryearlydeadend_to_asy(const int workerID, const size_type runID, const size_type nodeID) {
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new veryearlydeadend node:" << std::endl;
    Graphics::asy_stream() << "veryearlydeadend_nodes[" << workerID << "][" << runID << "].push(" << nodeID << ");" << std::endl;
    Graphics::asy_stream() << "// end new veryearlydeadend node." << std::endl;
  }
   
  void Graphics::missingvolume_to_asy(const int workerID, const size_type runID, const size_type nodeID) {
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new not-enough-volume node:" << std::endl;
    Graphics::asy_stream() << "missingvolume_nodes[" << workerID << "][" << runID << "].push(" << nodeID << ");" << std::endl;
    Graphics::asy_stream() << "// end new not-enough-volume node." << std::endl;
  }
  
  void Graphics::notnew_to_asy(const int workerID, const size_type runID, const size_type nodeID) {
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new not-new node:" << std::endl;
    Graphics::asy_stream() << "notnew_nodes[" << workerID << "][" << runID << "].push(" << nodeID << ");" << std::endl;
    Graphics::asy_stream() << "// end new not-new node." << std::endl;
  }
  
  void Graphics::solution_to_asy(const int workerID, const size_type runID, const size_type nodeID) {
    // no message here because these calls are tight during the enumeration:
    std::lock_guard<std::mutex> lock(IO_sync::mutex);
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// begin new solution node:" << std::endl;
    Graphics::asy_stream() << "solution_nodes[" << workerID << "][" << runID << "].push(" << nodeID << ");" << std::endl;
    Graphics::asy_stream() << "// end new solution node." << std::endl;
  }

  void Graphics::nodepos_to_asy() {
    std::cerr << "writing drawing parameters to asymptote ..." << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of drawing parameters section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "picture tree_pic;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "real x_pos = 0;" << std::endl;
    Graphics::asy_stream() << "real y_pos = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "pair[][][] node_pos;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "real maxelmno = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < tree_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < tree_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int nodeID = 0; nodeID < tree_nodes[workerID][runID].length; ++nodeID) {" << std::endl;
    Graphics::asy_stream() << "      if (tree_nodes[workerID][runID][nodeID].length() > maxelmno) {" << std::endl;    
    Graphics::asy_stream() << "        maxelmno = tree_nodes[workerID][runID][nodeID].length();" << std::endl;
    Graphics::asy_stream() << "      }" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < tree_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  node_pos.push(new pair[][]);" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < tree_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    node_pos[workerID].push(new pair[]);" << std::endl;
    Graphics::asy_stream() << "    for (int nodeID = 0; nodeID < tree_nodes[workerID][runID].length; ++nodeID) {" << std::endl;
    Graphics::asy_stream() << "      y_pos = 2 * size_y * tree_nodes[workerID][runID][nodeID].length() - workerID * (maxelmno + 2) * 2 * size_y;" << std::endl;
    Graphics::asy_stream() << "      x_pos = x_pos + 2 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (x_pos, y_pos);" << std::endl;
    Graphics::asy_stream() << "      node_pos[workerID][runID].push(new_pos);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "    x_pos = x_pos + 2 * size_x;" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  x_pos = node_pos[0][0][tree_nodes[0][0].length - 1].x  + 2 * size_x;" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of drawing parameters section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
  }
  
  void Graphics::define_draw_node_for_labelset_to_asy() {
    std::cerr << "writing node-drawing definition for label sets to asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of drawing definitions section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "void draw_node(picture pic, int workerID, int runID, int nodeID) {" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = node_pos[workerID][runID][nodeID];" << std::endl;
    Graphics::asy_stream() << "  int[] labelset = tree_nodes[workerID][runID][nodeID].labelset;" << std::endl;
    Graphics::asy_stream() << "  string labelsetstring = \"\\(\\{\";" << std::endl;
    Graphics::asy_stream() << "  for (int i = 0; i < labelset.length - 1; ++i) {;" << std::endl;
    Graphics::asy_stream() << "    labelsetstring += format(\"%d\", labelset[i]) + \",\";" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  if (labelset.length > 0) {" << std::endl;
    Graphics::asy_stream() << "    labelsetstring += format(\"%d\", labelset[labelset.length - 1]);" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  labelsetstring += \"\\}\\)\";" << std::endl;
    Graphics::asy_stream() << "  filldraw(pic=tree_pic, shift(new_pos.x - size_x, new_pos.y - size_y/2) * scale(2 * size_x, size_y) * unitsquare, fillpen=white, drawpen=linewidth(thinlinewidth));" << std::endl;
    Graphics::asy_stream() << "  label(pic=tree_pic, L=minipage(labelsetstring, width=2*size_x), position=new_pos, align=Center, p=fontsize(1.5 * size_x/(labelset.length + 2)));" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of drawing definitions section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::define_draw_node_for_partialtriang_to_asy() {
    std::cerr << "writing node-drawing definition for partial triangulations to asymptote ..." << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of drawing definitions section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "void draw_node(picture pic, int workerID, int runID, int nodeID) {" << std::endl;
    if (_rank == 3) {
      Graphics::asy_stream() << "  pair new_pos = node_pos[workerID][runID][nodeID];" << std::endl;
      Graphics::asy_stream() << "  int[][] partialtriang = tree_nodes[workerID][runID][nodeID].partialtriang;" << std::endl;
      Graphics::asy_stream() << "  pointconf A_shifted = pointconf(A, copy=true);" << std::endl;
      Graphics::asy_stream() << "  A_shifted = shift(new_pos) * A_shifted;" << std::endl;
      Graphics::asy_stream() << "  A_shifted.draw_polygon(pic=tree_pic, pointconf_fillpen=default_pointconf_fillpen + opacity(0.95));" << std::endl;
      Graphics::asy_stream() << "  for (int[] simplex : partialtriang) {" << std::endl;
      Graphics::asy_stream() << "    pointconf pt = pointconf(A_shifted, cell=simplex, extremepoints=simplex);" << std::endl;
      Graphics::asy_stream() << "    pt.draw_polygon(pic=tree_pic," << std::endl;
      Graphics::asy_stream() << "	             pointconf_pen=secondary_pointconf_pen," << std::endl;
      Graphics::asy_stream() << "                    pointconf_fillpen=secondary_pointconf_fillpen + opacity(1));" << std::endl;
      Graphics::asy_stream() << "  }" << std::endl;
    }
    else {
      Graphics::asy_stream() << "  pair new_pos = node_pos[workerID][runID][nodeID];" << std::endl;
      Graphics::asy_stream() << "  int[][] partialtriang = tree_nodes[workerID][runID][nodeID].partialtriang;" << std::endl;
      Graphics::asy_stream() << "  string partialtriangstring = \"\\centering\";" << std::endl;
      Graphics::asy_stream() << "  if (partialtriang.length > 0) {" << std::endl;
      Graphics::asy_stream() << "    for (int i = 0; i < partialtriang.length - 1; ++i) {;" << std::endl;
      Graphics::asy_stream() << "      partialtriangstring += \"\\(\";" << std::endl;
      Graphics::asy_stream() << "      partialtriangstring += \"\\{\";" << std::endl;
      Graphics::asy_stream() << "      for (int j = 0; j < partialtriang[i].length - 1; ++j) {;" << std::endl;
      Graphics::asy_stream() << "        partialtriangstring += format(\"%d\", partialtriang[i][j]) + \",\";" << std::endl;
      Graphics::asy_stream() << "      }" << std::endl;
      Graphics::asy_stream() << "      partialtriangstring += format(\"%d\", partialtriang[i][partialtriang[i].length - 1]);" << std::endl;
      Graphics::asy_stream() << "      partialtriangstring += \"\\}\\), \";" << std::endl;
      Graphics::asy_stream() << "    }" << std::endl;
      Graphics::asy_stream() << "    partialtriangstring += \"\\(\\{\";" << std::endl;
      Graphics::asy_stream() << "    for (int j = 0; j < partialtriang[partialtriang.length - 1].length - 1; ++j) {;" << std::endl;
      Graphics::asy_stream() << "      partialtriangstring += format(\"%d\", partialtriang[partialtriang.length - 1][j]) + \",\";" << std::endl;
      Graphics::asy_stream() << "    }" << std::endl;
      Graphics::asy_stream() << "    partialtriangstring += format(\"%d\", partialtriang[partialtriang.length - 1][partialtriang[partialtriang.length - 1].length - 1]);" << std::endl;
      Graphics::asy_stream() << "    partialtriangstring += \"\\}\\)\";" << std::endl;
      Graphics::asy_stream() << "  }" << std::endl;
      Graphics::asy_stream() << "  label(pic=tree_pic, L=minipage(partialtriangstring, width=2*size_x), position=new_pos, align=Center, p=fontsize(1.5*size_y/(maxelmno + 2)));" << std::endl;
      Graphics::asy_stream() << "  filldraw(pic=tree_pic, shift(new_pos.x - size_x, new_pos.y - size_y/2) * scale(2 * size_x, size_y) * unitsquare, fillpen=white, drawpen=linewidth(thinlinewidth));" << std::endl;
    }
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of drawing definitions section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::define_draw_node_for_matrix_to_asy() {
    std::cerr << "writing node-drawing definition for stair case matrices to asymptote ..." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of drawing definitions section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "void draw_node(picture pic, int workerID, int runID, int nodeID) {" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = node_pos[workerID][runID][nodeID];" << std::endl;
    Graphics::asy_stream() << "  pair new_pos_matrix = shift(0, -0.25 * size_y) * new_pos;" << std::endl;
    Graphics::asy_stream() << "  real[][] matrix = tree_nodes[workerID][runID][nodeID].matrix;" << std::endl;
    Graphics::asy_stream() << "  int matrix_coldim = matrix.length;" << std::endl;
    Graphics::asy_stream() << "  if (matrix_coldim > 0) {" << std::endl;
    Graphics::asy_stream() << "    int matrix_rowdim = matrix[0].length;" << std::endl;
    Graphics::asy_stream() << "    string matrixstring = \"\\(\\setcounter{MaxMatrixCols}{\" +  format(\"%d\", matrix_coldim) + \"}\";" << std::endl;
    Graphics::asy_stream() << "    matrixstring += \"\\setlength{\\arraycolsep}{\"+ format(\"%f\", size_y/(5 * matrix_rowdim)) + \"bp}\\begin{matrix}\";" << std::endl;
    Graphics::asy_stream() << "    if (matrix_rowdim > 0) {" << std::endl;
    Graphics::asy_stream() << "      for (int row = 0; row < matrix_rowdim - 1; ++row) {;" << std::endl;
    Graphics::asy_stream() << "        for (int col = 0; col < matrix_coldim - 1; ++col) {;" << std::endl;
    Graphics::asy_stream() << "          matrixstring += format(\"%.2f\", matrix[col][row]) + \" & \";" << std::endl;
    Graphics::asy_stream() << "        }" << std::endl;
    Graphics::asy_stream() << "        matrixstring += format(\"%.2f\", matrix[matrix_coldim - 1][row]) + \"\\\\\";" << std::endl;
    Graphics::asy_stream() << "      }" << std::endl;
    Graphics::asy_stream() << "      for (int col = 0; col < matrix_coldim - 1; ++col) {" << std::endl;
    Graphics::asy_stream() << "        matrixstring += format(\"%.2f\", matrix[col][matrix_rowdim - 1]) + \" & \";" << std::endl;
    Graphics::asy_stream() << "      }" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "    matrixstring += format(\"%.2f\", matrix[matrix_coldim - 1][matrix_rowdim - 1]);" << std::endl;
    Graphics::asy_stream() << "    matrixstring += \"\\end{matrix}\\)\";" << std::endl;
    Graphics::asy_stream() << "    label(pic=tree_pic, L=matrixstring, position=new_pos_matrix, align=N, p=fontsize(2 * min(size_y/(3 * (matrix_rowdim + 2)), size_x/(2 * matrix_coldim))));" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  pair new_pos_labelset = shift(0, -0.3 * size_y) * new_pos;" << std::endl;
    Graphics::asy_stream() << "  int[] labelset = tree_nodes[workerID][runID][nodeID].labelset;" << std::endl;
    Graphics::asy_stream() << "  string labelsetstring = \"\\(\\{\";" << std::endl;
    Graphics::asy_stream() << "  for (int i = 0; i < labelset.length - 1; ++i) {;" << std::endl;
    Graphics::asy_stream() << "    labelsetstring += format(\"%d\", labelset[i]) + \",\";" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  if (labelset.length > 0) {" << std::endl;
    Graphics::asy_stream() << "    labelsetstring += format(\"%d\", labelset[labelset.length - 1]);" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "  labelsetstring += \"\\}\\)\";" << std::endl;
    Graphics::asy_stream() << "  filldraw(pic=tree_pic, shift(new_pos.x, new_pos.y) * scale(2 * size_x, size_y) * shift(-0.5, -0.5) * unitsquare, fillpen=white, drawpen=linewidth(thinlinewidth));" << std::endl;
    Graphics::asy_stream() << "  label(pic=tree_pic, L=labelsetstring, position=new_pos_labelset, align=S, p=fontsize(2 * size_x/(2 * (maxelmno + 2))));" << std::endl;    
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of drawing definitions section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    std::cerr << "... done." << std::endl;
  }
  
  void Graphics::drawings_to_asy() {
    std::cerr << "writing drawings section to asymptote ..." << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// begin of drawings section:" << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < tree_arcs.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < tree_arcs[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int[] arc : tree_arcs[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      draw(pic=tree_pic," << std::endl;
    Graphics::asy_stream() << "	          shift(0, size_y/2) * node_pos[workerID][runID][arc[0]]--shift(0, -size_y/2) * node_pos[workerID][runID][arc[1]]," << std::endl;
    Graphics::asy_stream() << "	          p=heavygray + linewidth(thinlinewidth));" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < tree_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < tree_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int nodeID = 0; nodeID < tree_nodes[workerID][runID].length; ++nodeID) {" << std::endl;
    Graphics::asy_stream() << "      draw_node(pic=tree_pic, workerID=workerID, runID=runID, nodeID=nodeID);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < deadend_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < deadend_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int deadend_index : deadend_nodes[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = shift(0, 0.5 * size_y) * node_pos[workerID][runID][deadend_index];" << std::endl;
    Graphics::asy_stream() << "      label(pic=tree_pic, L=scale(scale_symbols) * \"\\bcinterdit\", position=new_pos, align=N/10);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < earlydeadend_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < earlydeadend_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int early_index : earlydeadend_nodes[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = shift(0, 0.5 * size_y) * node_pos[workerID][runID][early_index];" << std::endl;
    Graphics::asy_stream() << "      label(pic=tree_pic, L=scale(scale_symbols) * \"\\bclampe\", position=new_pos, align=N/10);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < veryearlydeadend_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < veryearlydeadend_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int veryearly_index : veryearlydeadend_nodes[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = shift(0, 0.5 * size_y) * node_pos[workerID][runID][veryearly_index];" << std::endl;
    Graphics::asy_stream() << "      label(pic=tree_pic, L=scale(scale_symbols) * \"\\bcdanger\", position=new_pos, align=N/10);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < missingvolume_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < missingvolume_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int missingvolume_index : missingvolume_nodes[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = shift(0, 0.5 * size_y) * node_pos[workerID][runID][missingvolume_index];" << std::endl;
    Graphics::asy_stream() << "      label(pic=tree_pic, L=scale(scale_symbols) * \"\\bctetraedre\", position=new_pos, align=N/10);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < notnew_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < notnew_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int notnew_index : notnew_nodes[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = shift(0, 0.5 * size_y) * node_pos[workerID][runID][notnew_index];" << std::endl;
    Graphics::asy_stream() << "      label(pic=tree_pic, L=scale(scale_symbols) * \"\\bcrecyclage\", position=new_pos, align=N/10);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < solution_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < solution_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int triang_index : solution_nodes[workerID][runID]) {" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = shift(0, 0.5 * size_y) * node_pos[workerID][runID][triang_index];" << std::endl;
    Graphics::asy_stream() << "      label(pic=tree_pic, L=scale(scale_symbols) * \"\\bctrefle\", position=new_pos, align=N/10);" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "picture statistics_pic;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "real stats_pos_x = 0;" << std::endl;
    Graphics::asy_stream() << "real stats_pos_y = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "int cnt = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < solution_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < solution_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int i = 0; i < solution_nodes[workerID][runID].length; ++i) {" << std::endl;
    Graphics::asy_stream() << "      stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "      label(pic=statistics_pic, L=scale(scale_symbols) * \"\\bctrefle\", position=new_pos, align=Center);" << std::endl;
    Graphics::asy_stream() << "      ++cnt;" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "if (cnt > 0) {" << std::endl;
    Graphics::asy_stream() << "  stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "  label(pic=statistics_pic, L=scale(scale_symbols) * format(\"%d\", cnt), position=new_pos, align=E/10);" << std::endl;
    Graphics::asy_stream() << "  stats_pos_y -= 1.5 * size_x;" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "stats_pos_x = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "cnt = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < deadend_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < deadend_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int i = 0; i < deadend_nodes[workerID][runID].length; ++i) {" << std::endl;
    Graphics::asy_stream() << "      stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "      label(pic=statistics_pic, L=scale(scale_symbols) * \"\\bcinterdit\", position=new_pos, align=Center);" << std::endl;
    Graphics::asy_stream() << "      ++cnt;" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "if (cnt > 0) {" << std::endl;
    Graphics::asy_stream() << "  stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "  label(pic=statistics_pic, L=scale(scale_symbols) * format(\"%d\", cnt), position=new_pos, align=E/10);" << std::endl;
    Graphics::asy_stream() << "  stats_pos_y -= 1.5 * size_x;" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "stats_pos_x = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "cnt = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < earlydeadend_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < earlydeadend_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int i = 0; i < earlydeadend_nodes[workerID][runID].length; ++i) {" << std::endl;
    Graphics::asy_stream() << "      stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "      label(pic=statistics_pic, L=scale(scale_symbols) * \"\\bclampe\", position=new_pos, align=Center);" << std::endl;
    Graphics::asy_stream() << "      ++cnt;" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "if (cnt > 0) {" << std::endl;
    Graphics::asy_stream() << "  stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "  label(pic=statistics_pic, L=scale(scale_symbols) * format(\"%d\", cnt), position=new_pos, align=E/10);" << std::endl;
    Graphics::asy_stream() << "  stats_pos_y -= 1.5 * size_x;" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "stats_pos_x = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "cnt = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < veryearlydeadend_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < veryearlydeadend_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int i = 0; i < veryearlydeadend_nodes[workerID][runID].length; ++i) {" << std::endl;
    Graphics::asy_stream() << "      stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "      label(pic=statistics_pic, L=scale(scale_symbols) * \"\\bcdanger\", position=new_pos, align=Center);" << std::endl;
    Graphics::asy_stream() << "      ++cnt;" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "if (cnt > 0) {" << std::endl;
    Graphics::asy_stream() << "  stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "  label(pic=statistics_pic, L=scale(scale_symbols) * format(\"%d\", cnt), position=new_pos, align=E/10);" << std::endl;
    Graphics::asy_stream() << "  stats_pos_y -= 1.5 * size_x;" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "stats_pos_x = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "cnt = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < missingvolume_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < missingvolume_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int i = 0; i < missingvolume_nodes[workerID][runID].length; ++i) {" << std::endl;
    Graphics::asy_stream() << "      stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "      label(pic=statistics_pic, L=scale(scale_symbols) * \"\\bctetraedre\", position=new_pos, align=Center);" << std::endl;
    Graphics::asy_stream() << "      ++cnt;" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "if (cnt > 0) {" << std::endl;
    Graphics::asy_stream() << "  stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "  label(pic=statistics_pic, L=scale(scale_symbols) * format(\"%d\", cnt), position=new_pos, align=E/10);" << std::endl;
    Graphics::asy_stream() << "  stats_pos_y -= 1.5 * size_x;" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "stats_pos_x = 0;" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "cnt = 0;" << std::endl;
    Graphics::asy_stream() << "for (int workerID = 0; workerID < notnew_nodes.length; ++workerID) {" << std::endl;
    Graphics::asy_stream() << "  for (int runID = 0; runID < notnew_nodes[workerID].length; ++runID) {" << std::endl;
    Graphics::asy_stream() << "    for (int i = 0; i < notnew_nodes[workerID][runID].length; ++i) {" << std::endl;
    Graphics::asy_stream() << "      stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "      pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "      label(pic=statistics_pic, L=scale(scale_symbols) * \"\\bcrecyclage\", position=new_pos, align=Center);" << std::endl;
    Graphics::asy_stream() << "      ++cnt;" << std::endl;
    Graphics::asy_stream() << "    }" << std::endl;
    Graphics::asy_stream() << "  }" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << "if (cnt > 0) {" << std::endl;
    Graphics::asy_stream() << "  stats_pos_x += 1 * size_x;" << std::endl;
    Graphics::asy_stream() << "  pair new_pos = (stats_pos_x, stats_pos_y);" << std::endl;
    Graphics::asy_stream() << "  label(pic=statistics_pic, L=scale(scale_symbols) * format(\"%d\", cnt), position=new_pos, align=E/10);" << std::endl;
    Graphics::asy_stream() << "}" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "shipout(\"TOPCOM\" + filename_postfix + \"tree_graph\", tree_pic);" << std::endl;
    Graphics::asy_stream() << "shipout(\"TOPCOM\" + filename_postfix + \"statistics\", statistics_pic);" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << "// end of drawings section." << std::endl;
    Graphics::asy_stream() << "//////////////////////////////////////////////////////////////////////////////" << std::endl;
    Graphics::asy_stream() << std::endl;
    Graphics::asy_stream() << "// eof" << std::endl;
    std::cerr << "... done." << std::endl;
}
  void Graphics::term_asy() {
    std::cerr << "terminating graphics for asymptote ..." << std::endl;
    Graphics::asy_stream().close();
    std::cerr << "... done." << std::endl;
  }
  
}; // namespace topcom

// eof CommandlineOptions.cc
