<commit_before>
#include <QBoxLayout>
#include <QMenuBar>
#include <QSignalMapper>

#include "wd.h"
#include "font.h"
#include "cmd.h"
#include "form.h"
#include "pane.h"
#include "tabs.h"
#include "child.h"
#include "isigraph2.h"
#include "menus.h"
#ifdef QT_OPENGL
#include "opengl2.h"
#endif

extern int jedo(char*);

// ---------------------------------------------------------------------
Form::Form(string s, string p, string loc, QWidget *parent) : QWidget (parent)
{
  Q_UNUSED(parent);
  id=s;
  child=0;
  evtchild=0;
  locale=loc;
  fontdef=0;
  menubar=0;
  tab=0;
  closed=false;
  shown=false;
  setAttribute(Qt::WA_DeleteOnClose);
  QStringList m=s2q(p).split(' ',QString::SkipEmptyParts);
  escclose=m.contains("escclose");
  closeok=escclose||m.contains("closeok");
  setpn(s);

  Qt::WindowFlags flags=0;
  if (m.contains("dialog")) flags=Qt::Dialog|Qt::WindowTitleHint|Qt::WindowStaysOnTopHint|Qt::CustomizeWindowHint;
  if (m.contains("popup")) flags=Qt::Popup;
  if (m.contains("minbutton")) flags|=Qt::WindowMinimizeButtonHint;
  if (m.contains("maxbutton")) flags|=Qt::WindowMaximizeButtonHint;
  if (m.contains("closebutton")) flags|=Qt::WindowCloseButtonHint;
  if (m.contains("ptop")) flags=Qt::WindowStaysOnTopHint;
  setWindowFlags(flags);

  layout=new QVBoxLayout(this);
  layout->setContentsMargins(0,0,0,0);
  layout->setSpacing(0);
  if (m.contains("nosize")) layout->setSizeConstraint( QLayout::SetFixedSize );
  addpane(0);
  signalMapper=new QSignalMapper(this);
  connect(signalMapper,SIGNAL(mapped(QWidget *)),
          this,SLOT(buttonClicked(QWidget *)));
}

// ---------------------------------------------------------------------
Form::~Form()
{
  Child *n;
  for (int i=0; i<children.size(); i++)
    if ("isigraph"==(n=children.at(i))->type) {
      if (((Isigraph2*)n->widget)->painter) {
        ((Isigraph2*)n->widget)->painter->end();
        delete ((Isigraph2*)n->widget)->painter;
        ((Isigraph2*)n->widget)->painter=0;
      }
#ifdef QT_OPENGL
    } else if ("opengl"==(n=children.at(i))->type) {
      if (((Opengl2*)n->widget)->painter) {
        ((Opengl2*)n->widget)->painter->end();
        delete ((Opengl2*)n->widget)->painter;
        ((Opengl2*)n->widget)->painter=0;
      }
#endif
    }
  if (this==form) form = 0;
  if (this==evtform) evtform = 0;
  Forms.removeOne(this);
}

// ---------------------------------------------------------------------
void Form::addchild(Child *c)
{
  child=c;
  children.append(c);
}

// ---------------------------------------------------------------------
void Form::addmenu()
{
  menubar= new Menus("menu","",this,0);
  addchild((Child *) menubar);
  layout->insertWidget(0,child->widget);
}

// ---------------------------------------------------------------------
Pane *Form::addpane(int n)
{
  pane=new Pane(n,this);
  panes.append(pane);
  return pane;
}

// ---------------------------------------------------------------------
void Form::buttonClicked(QWidget *w)
{
  Child *child=(Child *) w;
  child->event="button";
  signalevent(child);
}

// ---------------------------------------------------------------------
void Form::closeEvent(QCloseEvent *e)
{
  if (closeok || closed) {
    e->accept();
    return;
  }
  e->ignore();
  event="close";
  form=this;
  signalevent(0);
  if (closed) {
    e->accept();
  } else e->ignore();
}

// ---------------------------------------------------------------------
// close if not the main pane
void Form::closepane()
{
  if (panes.size()<=1) return;
  panes.removeLast();
  pane=panes.last();
}

// ---------------------------------------------------------------------
string Form::hschild()
{
  return p2s((void *)child);
}

// ---------------------------------------------------------------------
string Form::hsform()
{
  return p2s((void *)this);
}

// ---------------------------------------------------------------------
Child *Form::id2child(string n)
{
  for (int i=0; i<children.size(); i++)
    if (n==children.at(i)->id)
      return children.at(i);
  return (Child *) 0;
}

// ---------------------------------------------------------------------
bool Form::ischild(Child *n)
{
  return children.contains(n);
  //for (int i=0; i<children.size(); i++)
  //if (n==children.at(i))
  //return true;
  //return false;
}

// ---------------------------------------------------------------------
void Form::keyPressEvent(QKeyEvent *e)
{
  if (escclose && e->key()==Qt::Key_Escape) {
    e->ignore();
    delete this;
  }
}

// ---------------------------------------------------------------------
Child *Form::setmenuid(string id)
{
  if (menubar && menubar->items.contains(s2q(id)))
    return (Child *) menubar;
  return (Child *) 0;
}

// ---------------------------------------------------------------------
void Form::setpn(string p)
{
  setWindowTitle(s2q(p));
}

// ---------------------------------------------------------------------
void Form::showit()
{
  for (int i=tabs.size()-1; i>=0; i--)
    tabs.last()->tabend();
  for (int i=panes.size()-1; i>=0; i--)
    panes.last()->fini();
  layout->addWidget(pane);
  setLayout(layout);
  show();
  shown=true;
}

// ---------------------------------------------------------------------
void Form::signalevent(Child *c)
{
  if (NoEvents || closed) return;
  string loc = locale;
  evtform=this;
  evtchild=c;
  if (c) {
    c->setform();
    sysmodifiers=c->sysmodifiers;
    sysdata=c->sysdata;
    loc = (""!=c->locale)?c->locale:locale;
  } else {
  }
  string s="(i.0 0)\"_ wdhandler_" + loc + "_$0";
  jedo((char *)s.c_str());
}

// ---------------------------------------------------------------------
string Form::state(int evt)
{
  string c,c1,e,r,s,ec;

  if (evt) {
    if (evtchild) {
      c=evtchild->id;
      c1=c+"_";
      e=evtchild->event;
      ec=evtchild->locale;
    } else
      e=event;
    r+=spair("syshandler",id+"_handler");
    r+=spair("sysevent",id+"_"+c1+e);
    r+=spair("sysdefault",id+"_default");
    r+=spair("sysparent",id);
    r+=spair("syschild",c);
    r+=spair("systype",e);
    r+=spair("syslocalec",ec);
  }

  // need only syslocale (not syslocalep, syslocalec)?...  in isigraph
  r+=spair("syslocalep",locale);
  r+=spair("syshwndp",hsform());
  r+=spair("syshwndc",hschild());
  r+=spair("syslastfocus","");
  r+=spair("sysmodifiers",sysmodifiers);
  r+=spair("sysdata",sysdata);

  for (int i=0; i<children.size(); i++)
    s+=children.at(i)->state();

  return r+s;
}

// ---------------------------------------------------------------------
// for debugging
void Form::status(string s)
{
  qDebug() << "form status: " << s2q(s);
  qDebug() << "current pane, panes: " << pane << panes;
  qDebug() << "current tab, tabs: " << tab << tabs;
}
<commit_msg>android<commit_after>
#include <QBoxLayout>
#include <QMenuBar>
#include <QSignalMapper>

#include "wd.h"
#include "font.h"
#include "cmd.h"
#include "form.h"
#include "pane.h"
#include "tabs.h"
#include "child.h"
#include "isigraph2.h"
#include "menus.h"
#ifdef QT_OPENGL
#include "opengl2.h"
#endif

extern int jedo(char*);

// ---------------------------------------------------------------------
Form::Form(string s, string p, string loc, QWidget *parent) : QWidget (parent)
{
  Q_UNUSED(parent);
  id=s;
  child=0;
  evtchild=0;
  locale=loc;
  fontdef=0;
  menubar=0;
  tab=0;
  closed=false;
  shown=false;
  setAttribute(Qt::WA_DeleteOnClose);
  QStringList m=s2q(p).split(' ',QString::SkipEmptyParts);
  escclose=m.contains("escclose");
  closeok=escclose||m.contains("closeok");
  setpn(s);

  Qt::WindowFlags flags=0;
  if (m.contains("dialog")) flags=Qt::Dialog|Qt::WindowTitleHint|Qt::WindowStaysOnTopHint|Qt::CustomizeWindowHint;
  if (m.contains("popup")) flags=Qt::Popup;
  if (m.contains("minbutton")) flags|=Qt::WindowMinimizeButtonHint;
  if (m.contains("maxbutton")) flags|=Qt::WindowMaximizeButtonHint;
  if (m.contains("closebutton")) flags|=Qt::WindowCloseButtonHint;
  if (m.contains("ptop")) flags=Qt::WindowStaysOnTopHint;
  setWindowFlags(flags);

  layout=new QVBoxLayout(this);
  layout->setContentsMargins(0,0,0,0);
  layout->setSpacing(0);
  if (m.contains("nosize")) layout->setSizeConstraint( QLayout::SetFixedSize );
  addpane(0);
  signalMapper=new QSignalMapper(this);
  connect(signalMapper,SIGNAL(mapped(QWidget *)),
          this,SLOT(buttonClicked(QWidget *)));
}

// ---------------------------------------------------------------------
Form::~Form()
{
  Child *n;
  for (int i=0; i<children.size(); i++)
    if ("isigraph"==(n=children.at(i))->type) {
      if (((Isigraph2*)n->widget)->painter) {
        ((Isigraph2*)n->widget)->painter->end();
        delete ((Isigraph2*)n->widget)->painter;
        ((Isigraph2*)n->widget)->painter=0;
      }
#ifdef QT_OPENGL
    } else if ("opengl"==(n=children.at(i))->type) {
      if (((Opengl2*)n->widget)->painter) {
        ((Opengl2*)n->widget)->painter->end();
        delete ((Opengl2*)n->widget)->painter;
        ((Opengl2*)n->widget)->painter=0;
      }
#endif
    }
  if (this==form) form = 0;
  if (this==evtform) evtform = 0;
  Forms.removeOne(this);
}

// ---------------------------------------------------------------------
void Form::addchild(Child *c)
{
  child=c;
  children.append(c);
}

// ---------------------------------------------------------------------
void Form::addmenu()
{
  menubar= new Menus("menu","",this,0);
  addchild((Child *) menubar);
  layout->insertWidget(0,child->widget);
}

// ---------------------------------------------------------------------
Pane *Form::addpane(int n)
{
  pane=new Pane(n,this);
  panes.append(pane);
  return pane;
}

// ---------------------------------------------------------------------
void Form::buttonClicked(QWidget *w)
{
  Child *child=(Child *) w;
  child->event="button";
  signalevent(child);
}

// ---------------------------------------------------------------------
void Form::closeEvent(QCloseEvent *e)
{
  if (closeok || closed) {
    e->accept();
    return;
  }
  e->ignore();
  event="close";
  form=this;
  signalevent(0);
  if (closed) {
    e->accept();
  } else e->ignore();
}

// ---------------------------------------------------------------------
// close if not the main pane
void Form::closepane()
{
  if (panes.size()<=1) return;
  panes.removeLast();
  pane=panes.last();
}

// ---------------------------------------------------------------------
string Form::hschild()
{
  return p2s((void *)child);
}

// ---------------------------------------------------------------------
string Form::hsform()
{
  return p2s((void *)this);
}

// ---------------------------------------------------------------------
Child *Form::id2child(string n)
{
  for (int i=0; i<children.size(); i++)
    if (n==children.at(i)->id)
      return children.at(i);
  return (Child *) 0;
}

// ---------------------------------------------------------------------
bool Form::ischild(Child *n)
{
  return children.contains(n);
  //for (int i=0; i<children.size(); i++)
  //if (n==children.at(i))
  //return true;
  //return false;
}

// ---------------------------------------------------------------------
void Form::keyPressEvent(QKeyEvent *e)
{
#ifdef ANDROID
  if (e->key()==Qt::Key_MediaPrevious) {
    activateWindow();
    raise();
    close();
  }
#endif
  if (escclose && e->key()==Qt::Key_Escape) {
    e->ignore();
    delete this;
  }
}

// ---------------------------------------------------------------------
Child *Form::setmenuid(string id)
{
  if (menubar && menubar->items.contains(s2q(id)))
    return (Child *) menubar;
  return (Child *) 0;
}

// ---------------------------------------------------------------------
void Form::setpn(string p)
{
  setWindowTitle(s2q(p));
}

// ---------------------------------------------------------------------
void Form::showit()
{
  for (int i=tabs.size()-1; i>=0; i--)
    tabs.last()->tabend();
  for (int i=panes.size()-1; i>=0; i--)
    panes.last()->fini();
  layout->addWidget(pane);
  setLayout(layout);
  show();
#ifdef ANDROID
  activateWindow();
  raise();
#endif

  shown=true;
}

// ---------------------------------------------------------------------
void Form::signalevent(Child *c)
{
  if (NoEvents || closed) return;
  string loc = locale;
  evtform=this;
  evtchild=c;
  if (c) {
    c->setform();
    sysmodifiers=c->sysmodifiers;
    sysdata=c->sysdata;
    loc = (""!=c->locale)?c->locale:locale;
  } else {
  }
  string s="(i.0 0)\"_ wdhandler_" + loc + "_$0";
  jedo((char *)s.c_str());
}

// ---------------------------------------------------------------------
string Form::state(int evt)
{
  string c,c1,e,r,s,ec;

  if (evt) {
    if (evtchild) {
      c=evtchild->id;
      c1=c+"_";
      e=evtchild->event;
      ec=evtchild->locale;
    } else
      e=event;
    r+=spair("syshandler",id+"_handler");
    r+=spair("sysevent",id+"_"+c1+e);
    r+=spair("sysdefault",id+"_default");
    r+=spair("sysparent",id);
    r+=spair("syschild",c);
    r+=spair("systype",e);
    r+=spair("syslocalec",ec);
  }

  // need only syslocale (not syslocalep, syslocalec)?...  in isigraph
  r+=spair("syslocalep",locale);
  r+=spair("syshwndp",hsform());
  r+=spair("syshwndc",hschild());
  r+=spair("syslastfocus","");
  r+=spair("sysmodifiers",sysmodifiers);
  r+=spair("sysdata",sysdata);

  for (int i=0; i<children.size(); i++)
    s+=children.at(i)->state();

  return r+s;
}

// ---------------------------------------------------------------------
// for debugging
void Form::status(string s)
{
  qDebug() << "form status: " << s2q(s);
  qDebug() << "current pane, panes: " << pane << panes;
  qDebug() << "current tab, tabs: " << tab << tabs;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_HIOP
#define MFEM_HIOP

#include "linalg.hpp"
#include "../config/config.hpp"
#include "../general/globals.hpp"

#ifdef MFEM_USE_MPI
#include "operator.hpp"
#endif

#ifdef MFEM_USE_HIOP

#include "hiopInterface.hpp"
#include "hiopNlpFormulation.hpp"

namespace mfem
{

/// Internal class - adapts the OptimizationProblem class to HiOp's interface.
class HiopOptimizationProblem : public hiop::hiopInterfaceDenseConstraints
{
private:

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

   // Problem info.
   const OptimizationProblem &problem;

   // Local and global number of variables and constraints.
   const hiop::size_type ntdofs_loc, m_total;
   hiop::size_type ntdofs_glob;

   // Initial guess.
   const Vector *x_start;

   Vector constr_vals;
   DenseMatrix constr_grads;
   bool constr_info_is_current;
   void UpdateConstrValsGrads(const Vector x);

public:
   HiopOptimizationProblem(const OptimizationProblem &prob)
      : problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(ntdofs_loc),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
#ifdef MFEM_USE_MPI
      // Used when HiOp with MPI support is called by a serial driver.
      comm = MPI_COMM_WORLD;
#endif
   }

#ifdef MFEM_USE_MPI
   HiopOptimizationProblem(const MPI_Comm& comm_,
                           const OptimizationProblem &prob)
      : comm(comm_),
        problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(0),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
     MPI_Allreduce(&ntdofs_loc, &ntdofs_glob, 1, MPI_HIOP_SIZE_TYPE, MPI_SUM, comm);
   }
#endif

   void setStartingPoint(const Vector &x0) { x_start = &x0; }

   /** Extraction of problem dimensions:
    *  n is the number of variables, m is the number of constraints. */
   virtual bool get_prob_sizes(hiop::size_type& n, hiop::size_type& m);

   /** Provide an primal starting point. This point is subject to adjustments
    *  internally in HiOp. */
   virtual bool get_starting_point(const hiop::size_type &n, double *x0);

   virtual bool get_vars_info(const hiop::size_type &n, double *xlow, double* xupp,
                              NonlinearityType* type);

   /** bounds on the constraints
    *  (clow<=-1e20 means no lower bound, cupp>=1e20 means no upper bound) */
   virtual bool get_cons_info(const hiop::size_type &m, double *clow, double *cupp,
                              NonlinearityType* type);

   /** Objective function evaluation.
    *  Each rank returns the global objective value. */
   virtual bool eval_f(const hiop::size_type &n, const double *x, bool new_x,
                       double& obj_value);

   /** Gradient of the objective function (local chunk). */
   virtual bool eval_grad_f(const hiop::size_type &n, const double *x, bool new_x,
                            double *gradf);

   /** Evaluates a subset of the constraints cons(x). The subset is of size
    *  num_cons and is described by indexes in the idx_cons array,
    *  i.e. cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1.
    *  The methods may be called multiple times, each time for a subset of the
    *  constraints, for example, for the subset containing the equalities and
    *  for the subset containing the inequalities. However, each constraint will
    *  be inquired EXACTLY once. This is done for performance considerations,
    *  to avoid temporary holders and memory copying.
    *
    *  Parameters:
    *   - n, m: the global number of variables and constraints
    *   - num_cons, idx_cons (array of size num_cons): the number and indexes of
    *     constraints to be evaluated
    *   - x: the point where the constraints are to be evaluated
    *   - new_x: whether x has been changed from the previous call to f, grad_f,
    *     or Jac
    *   - cons: array of size num_cons containing the value of the  constraints
    *     indicated by idx_cons
    *
    *  When MPI enabled, every rank populates cons, since the constraints are
    *  not distributed.
    */
   virtual bool eval_cons(const hiop::size_type &n, const hiop::size_type &m,
                          const hiop::size_type &num_cons,
                          const hiop::index_type *idx_cons,
                          const double *x, bool new_x, double *cons);

   /** Evaluates the Jacobian of the subset of constraints indicated by
    *  idx_cons. The idx_cons is assumed to be of size num_cons.
    *  Example: if cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1, then
    *  one needs to do Jac[c][j] = d cons[c] / dx_j, j = 1 .. n_loc.
    *  Jac is computed and stored in a contiguous vector (offset by rows).
    *
    *  Parameters: see eval_cons().
    *
    *  When MPI enabled, each rank computes only the local columns of the
    *  Jacobian, that is the partials with respect to local variables.
    */
   virtual bool eval_Jac_cons(const hiop::size_type &n, const hiop::size_type &m,
                              const hiop::size_type &num_cons,
                              const hiop::index_type *idx_cons,
                              const double *x, bool new_x, double *Jac);

   /** Specifies column partitioning for distributed memory vectors.
    *  Process p owns vector entries with indices cols[p] to cols[p+1]-1,
    *  where p = 0 .. nranks-1. The cols array is of size nranks + 1.
    *  Example: for a vector x of 6 entries (globally) on 3 ranks, the uniform
    *  column partitioning is cols=[0,2,4,6].
    */
   virtual bool get_vecdistrib_info(hiop::size_type global_n, hiop::index_type *cols);

#ifdef MFEM_USE_MPI
   virtual bool get_MPI_comm(MPI_Comm &comm_out)
   {
      comm_out = comm;
      return true;
   }
#endif
};

/// Adapts the HiOp functionality to the MFEM OptimizationSolver interface.
class HiopNlpOptimizer : public OptimizationSolver
{
protected:
   HiopOptimizationProblem *hiop_problem;

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

public:
   HiopNlpOptimizer();
#ifdef MFEM_USE_MPI
   HiopNlpOptimizer(MPI_Comm comm_);
#endif
   virtual ~HiopNlpOptimizer();

   virtual void SetOptimizationProblem(const OptimizationProblem &prob);

   /// Solves the optimization problem with xt as initial guess.
   virtual void Mult(const Vector &xt, Vector &x) const;
};

} // mfem namespace

#endif //MFEM_USE_HIOP
#endif //MFEM_HIOP guard
<commit_msg>codestyle take 2<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_HIOP
#define MFEM_HIOP

#include "linalg.hpp"
#include "../config/config.hpp"
#include "../general/globals.hpp"

#ifdef MFEM_USE_MPI
#include "operator.hpp"
#endif

#ifdef MFEM_USE_HIOP

#include "hiopInterface.hpp"
#include "hiopNlpFormulation.hpp"

namespace mfem
{

/// Internal class - adapts the OptimizationProblem class to HiOp's interface.
class HiopOptimizationProblem : public hiop::hiopInterfaceDenseConstraints
{
private:

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

   // Problem info.
   const OptimizationProblem &problem;

   // Local and global number of variables and constraints.
   const hiop::size_type ntdofs_loc, m_total;
   hiop::size_type ntdofs_glob;

   // Initial guess.
   const Vector *x_start;

   Vector constr_vals;
   DenseMatrix constr_grads;
   bool constr_info_is_current;
   void UpdateConstrValsGrads(const Vector x);

public:
   HiopOptimizationProblem(const OptimizationProblem &prob)
      : problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(ntdofs_loc),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
#ifdef MFEM_USE_MPI
      // Used when HiOp with MPI support is called by a serial driver.
      comm = MPI_COMM_WORLD;
#endif
   }

#ifdef MFEM_USE_MPI
   HiopOptimizationProblem(const MPI_Comm& comm_,
                           const OptimizationProblem &prob)
      : comm(comm_),
        problem(prob),
        ntdofs_loc(prob.input_size), m_total(prob.GetNumConstraints()),
        ntdofs_glob(0),
        x_start(NULL),
        constr_vals(m_total), constr_grads(m_total, ntdofs_loc),
        constr_info_is_current(false)
   {
      MPI_Allreduce(&ntdofs_loc, &ntdofs_glob, 1, MPI_HIOP_SIZE_TYPE, MPI_SUM, comm);
   }
#endif

   void setStartingPoint(const Vector &x0) { x_start = &x0; }

   /** Extraction of problem dimensions:
    *  n is the number of variables, m is the number of constraints. */
   virtual bool get_prob_sizes(hiop::size_type& n, hiop::size_type& m);

   /** Provide an primal starting point. This point is subject to adjustments
    *  internally in HiOp. */
   virtual bool get_starting_point(const hiop::size_type &n, double *x0);

   virtual bool get_vars_info(const hiop::size_type &n, double *xlow, double* xupp,
                              NonlinearityType* type);

   /** bounds on the constraints
    *  (clow<=-1e20 means no lower bound, cupp>=1e20 means no upper bound) */
   virtual bool get_cons_info(const hiop::size_type &m, double *clow, double *cupp,
                              NonlinearityType* type);

   /** Objective function evaluation.
    *  Each rank returns the global objective value. */
   virtual bool eval_f(const hiop::size_type &n, const double *x, bool new_x,
                       double& obj_value);

   /** Gradient of the objective function (local chunk). */
   virtual bool eval_grad_f(const hiop::size_type &n, const double *x, bool new_x,
                            double *gradf);

   /** Evaluates a subset of the constraints cons(x). The subset is of size
    *  num_cons and is described by indexes in the idx_cons array,
    *  i.e. cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1.
    *  The methods may be called multiple times, each time for a subset of the
    *  constraints, for example, for the subset containing the equalities and
    *  for the subset containing the inequalities. However, each constraint will
    *  be inquired EXACTLY once. This is done for performance considerations,
    *  to avoid temporary holders and memory copying.
    *
    *  Parameters:
    *   - n, m: the global number of variables and constraints
    *   - num_cons, idx_cons (array of size num_cons): the number and indexes of
    *     constraints to be evaluated
    *   - x: the point where the constraints are to be evaluated
    *   - new_x: whether x has been changed from the previous call to f, grad_f,
    *     or Jac
    *   - cons: array of size num_cons containing the value of the  constraints
    *     indicated by idx_cons
    *
    *  When MPI enabled, every rank populates cons, since the constraints are
    *  not distributed.
    */
   virtual bool eval_cons(const hiop::size_type &n, const hiop::size_type &m,
                          const hiop::size_type &num_cons,
                          const hiop::index_type *idx_cons,
                          const double *x, bool new_x, double *cons);

   /** Evaluates the Jacobian of the subset of constraints indicated by
    *  idx_cons. The idx_cons is assumed to be of size num_cons.
    *  Example: if cons[c] = C(x)[idx_cons[c]] where c = 0 .. num_cons-1, then
    *  one needs to do Jac[c][j] = d cons[c] / dx_j, j = 1 .. n_loc.
    *  Jac is computed and stored in a contiguous vector (offset by rows).
    *
    *  Parameters: see eval_cons().
    *
    *  When MPI enabled, each rank computes only the local columns of the
    *  Jacobian, that is the partials with respect to local variables.
    */
   virtual bool eval_Jac_cons(const hiop::size_type &n, const hiop::size_type &m,
                              const hiop::size_type &num_cons,
                              const hiop::index_type *idx_cons,
                              const double *x, bool new_x, double *Jac);

   /** Specifies column partitioning for distributed memory vectors.
    *  Process p owns vector entries with indices cols[p] to cols[p+1]-1,
    *  where p = 0 .. nranks-1. The cols array is of size nranks + 1.
    *  Example: for a vector x of 6 entries (globally) on 3 ranks, the uniform
    *  column partitioning is cols=[0,2,4,6].
    */
   virtual bool get_vecdistrib_info(hiop::size_type global_n,
                                    hiop::index_type *cols);

#ifdef MFEM_USE_MPI
   virtual bool get_MPI_comm(MPI_Comm &comm_out)
   {
      comm_out = comm;
      return true;
   }
#endif
};

/// Adapts the HiOp functionality to the MFEM OptimizationSolver interface.
class HiopNlpOptimizer : public OptimizationSolver
{
protected:
   HiopOptimizationProblem *hiop_problem;

#ifdef MFEM_USE_MPI
   MPI_Comm comm;
#endif

public:
   HiopNlpOptimizer();
#ifdef MFEM_USE_MPI
   HiopNlpOptimizer(MPI_Comm comm_);
#endif
   virtual ~HiopNlpOptimizer();

   virtual void SetOptimizationProblem(const OptimizationProblem &prob);

   /// Solves the optimization problem with xt as initial guess.
   virtual void Mult(const Vector &xt, Vector &x) const;
};

} // mfem namespace

#endif //MFEM_USE_HIOP
#endif //MFEM_HIOP guard
<|endoftext|>


<commit_before>/* Little Init by Alexander Richards
   under MIT; Please compile staticly */

///TODO:
///

//Include stuff

#include <signal.h>
#include <iostream>
#include <cstdlib>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <sstream>
#include <thread>
#include <chrono>
#include <fstream>
#include <string.h>

#define MAX_BUF 1024

// #include <time.h>
using namespace std;

// Declare Vars
int done = 0; // is init procedure complete?
int runlevel = 1; // runlevel, 0 should always be shutdown
string version = "little-init v0.3-git";
string rc_script = "/etc/init.d/rc";
// not the final solution, but its the best thing for now, there are more important things :)

// https://www.systutorials.com/5510/catching-the-signal-sent-by-kill-in-c-on-linux/ please don't sue me
void sighandler(int signum, siginfo_t *info, void *ptr) { // so i can turn it off gracefully for now
    	if (signum == SIGTERM) {
      		sync();
      		reboot(RB_POWER_OFF);
    	} else if (signum == SIGHUP) {
      		sync();
      		reboot(RB_AUTOBOOT);
    	}
}

void catch_sig() {
 	static struct sigaction _sigact;
    	memset(&_sigact, 0, sizeof(_sigact));
   	_sigact.sa_sigaction = sighandler;
   	_sigact.sa_flags = SA_SIGINFO;
   	sigaction(SIGTERM, &_sigact, NULL);
   	sigaction(SIGHUP, &_sigact, NULL);
    signal(SIGCHLD, SIG_IGN);
}
//END

void call_rc(int rl) {
  if(rl == 9) {
    system(string(rc_script + string(" S")).c_str());
  } else {
    system(string(rc_script + string(" ") + to_string(rl)).c_str());
  }
}

inline bool exist(const std::string& name) {
	ifstream file(name);
	if (file.good()) {return true;} else {return false;}
} // Simple file checker; This line is probably not required but why not

void init() {
  system("mount -a"); // just mount everything now
	system("mount -o remount,rw /"); // remount root as rw, just in case its ro
  call_rc(9); // call single user first
  call_rc(2);
	done = 1;
	runlevel = 3; // still have to implement switching it
	if(exist("/etc/init.d/shell")) {
		pid_t pid = fork();
		if(pid == 0) { // if child process, run the "shell" symlink, hopefully :)
			execl("/etc/init.d/shell", "/etc/init.d/shell", (char*) 0);
			this_thread::sleep_for(std::chrono::milliseconds(1000));
      kill(getpid(), SIGKILL);
		}
	}
}

// Call said functions
int main(int argc, char** argv) {
  if(getpid() == 1) {
	  cout << version << endl;
    init();
    while(true) { // do stuff
      if(exist("/tmp/runlevel")) {
        int tmp_runlevel = 0; // runlevel from /tmp/runlevel. default = 0
        string temp;
        ifstream file("/tmp/runlevel");
        if(file.is_open()) {
          getline(file, temp);
          // temp should have the runlevel in it. 9 is alias for S
          if(temp == "") {
            // nothing, continue
          } else {
            tmp_runlevel = stoi(temp);
            call_rc(tmp_runlevel);
            runlevel = tmp_runlevel;
          }
        }
        file.close();
      }
      this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
  } else {
    // should be reserved for runlevel changes
    if(argc == 1) {
      cout << "Usage: init <runlevel>";
    } else {
      runlevel = atoi(argv[1]);
      ofstream file("/tmp/runlevel");
      file << runlevel;
      file.close();
    }
  }
}
<commit_msg>Hopefully made it possible to specify runlevel in linux boot args<commit_after>/* Little Init by Alexander Richards
   under MIT; Please compile staticly */

///TODO:
///

//Include stuff

#include <signal.h>
#include <iostream>
#include <cstdlib>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <sstream>
#include <thread>
#include <chrono>
#include <fstream>
#include <string.h>

#define MAX_BUF 1024

// #include <time.h>
using namespace std;

// Declare Vars
int done = 0; // is init procedure complete?
int runlevel = 5; // runlevel, 0 should always be shutdown, default is 5
string version = "little-init v0.3-git";
string rc_script = "/etc/init.d/rc";
// not the final solution, but its the best thing for now, there are more important things :)

// https://www.systutorials.com/5510/catching-the-signal-sent-by-kill-in-c-on-linux/ please don't sue me
void sighandler(int signum, siginfo_t *info, void *ptr) { // so i can turn it off gracefully for now
    	if (signum == SIGTERM) {
      		sync();
      		reboot(RB_POWER_OFF);
    	} else if (signum == SIGHUP) {
      		sync();
      		reboot(RB_AUTOBOOT);
    	}
}

void catch_sig() {
 	static struct sigaction _sigact;
    	memset(&_sigact, 0, sizeof(_sigact));
   	_sigact.sa_sigaction = sighandler;
   	_sigact.sa_flags = SA_SIGINFO;
   	sigaction(SIGTERM, &_sigact, NULL);
   	sigaction(SIGHUP, &_sigact, NULL);
    signal(SIGCHLD, SIG_IGN);
}
//END

void call_rc(int rl) {
  if(rl == 9) {
    system(string(rc_script + string(" S")).c_str());
  } else {
    system(string(rc_script + string(" ") + to_string(rl)).c_str());
  }
}

inline bool exist(const std::string& name) {
	ifstream file(name);
	if (file.good()) {return true;} else {return false;}
} // Simple file checker; This line is probably not required but why not

void init() {
  system("mount -a"); // just mount everything now
	system("mount -o remount,rw /"); // remount root as rw, just in case its ro
  call_rc(9); // call single user first
  call_rc(2);
	done = 1;
	runlevel = 3; // still have to implement switching it
	if(exist("/etc/init.d/shell")) {
		pid_t pid = fork();
		if(pid == 0) { // if child process, run the "shell" symlink, hopefully :)
			execl("/etc/init.d/shell", "/etc/init.d/shell", (char*) 0);
			this_thread::sleep_for(std::chrono::milliseconds(1000));
      kill(getpid(), SIGKILL);
		}
	}
}

// Call said functions
int main(int argc, char** argv) {
  if(getpid() == 1) {
	  cout << version << endl;
    if(argc != 1) {
      runlevel = atoi(argv[1]);
      if(string(argv[1]) == "s" || string(argv[1]) == "S") {
        runlevel = 9;
      }
    }
    init();
    while(true) { // do stuff
      if(exist("/tmp/runlevel")) {
        int tmp_runlevel = 0; // runlevel from /tmp/runlevel. default = 0
        string temp;
        ifstream file("/tmp/runlevel");
        if(file.is_open()) {
          getline(file, temp);
          // temp should have the runlevel in it. 9 is alias for S
          if(temp == "") {
            // nothing, continue
          } else {
            tmp_runlevel = stoi(temp);
            call_rc(tmp_runlevel);
            runlevel = tmp_runlevel;
          }
        }
        file.close();
      }
      this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
  } else {
    // should be reserved for runlevel changes
    if(argc == 1) {
      cout << "Usage: init <runlevel>";
    } else {
      runlevel = atoi(argv[1]);
      ofstream file("/tmp/runlevel");
      file << runlevel;
      file.close();
    }
  }
}
<|endoftext|>


<commit_before>#include "binaryio.h"
#include <stdexcept>

namespace scpak
{
    void BinaryReader::readBytes(int size, byte buf[])
    {
        for (int i = 0; i<size; ++i)
            buf[i] = readByte();
    }

    std::int32_t BinaryReader::readInt32()
    {
        int value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    std::float_t BinaryReader::readSingle()
    {
        float value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    std::int32_t BinaryReader::read7BitEncodedInt()
    {
        int value = 0;
        int offset = 0;
        while (offset != 35)
        {
            byte b = readByte();
            value |= static_cast<int>(b & 127) << offset;
            offset += 7;
            if ((b & 128) == 0)
                return value;
        }
        throw std::runtime_error("bad 7 bit encoded int32");
    }

    int BinaryReader::readUtf8Char()
    {
        byte first = readByte();
        if ((first & 0b10000000) == 0)
            // only one byte long, 0b0???????
            return static_cast<int>(first);
        if ((first & 0b11000000) == 0b11000000 && (first & 0b00100000) == 0)
        {
            // two bytes long, 0b110????? 0b10??????
            int second = readByte();
            int value = (first & 0b00011111) << 6;
            value |= second & 0b00111111;
            return value;
        }
        if ((first & 0b11100000) == 0b11100000 && (first & 0b00010000) == 0)
        {
            // three bytes long, 0b1110???? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int value = (first & 0b00001111) << 12;
            value |= (second & 0b00111111) << 6;
            value |= third & 0b00111111;
            return value;
        }
        if ((first & 0b11110000) == 0b11110000 && (first & 0b00001000) == 0)
        {
            // four bytes long, 0b11110??? 0b10?????? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int fourth = readByte();
            int value = (first & 0b00000111) << 18;
            value |= (second & 0b00111111) << 12;
            value |= (third & 0b00111111) << 6;
            value |= fourth & 0b00111111;
            return value;
        }
        throw std::runtime_error("utf-8 encoded unicode is too large");
    }

    bool BinaryReader::readBoolean()
    {
        return readByte() ? true : false;
    }

    std::string BinaryReader::readString()
    {
        int length = read7BitEncodedInt();
        std::string buffer;
        buffer.resize(length);
        for (int i = 0; i<length; ++i)
            buffer[i] = static_cast<char>(readByte());
        return buffer;
    }

    int BinaryReader::getUtf8CharCount(const std::string &value)
    {
        MemoryBinaryReader reader(reinterpret_cast<const byte*>(value.data()));
        int count = 0;
        while (reader.position < value.length())
        {
            int unicode = reader.readUtf8Char();
            ++count;
        }
        return count;
    }

    StreamBinaryReader::StreamBinaryReader(std::istream *stream)
    {
        m_stream = stream;
    }

    byte StreamBinaryReader::readByte()
    {
        if (!*m_stream)
            throw std::runtime_error("bad stream");
        char ch;
        m_stream->get(ch);
        return static_cast<byte>(ch);
    }

    MemoryBinaryReader::MemoryBinaryReader(const byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    byte MemoryBinaryReader::readByte()
    {
        return m_buffer[position++];
    }

    StreamBinaryWriter::StreamBinaryWriter(std::ostream *stream)
    {
        m_stream = stream;
    }

    void StreamBinaryWriter::writeByte(byte value)
    {
        if (!m_stream)
            throw std::runtime_error("bad stream");
        char ch = static_cast<char>(value);
        m_stream->put(ch);
    }

    MemoryBinaryWriter::MemoryBinaryWriter(byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    void MemoryBinaryWriter::writeByte(byte value)
    {
        m_buffer[position++] = value;
    }

    void BinaryWriter::writeBytes(int size, const byte value[])
    {
        for (int i = 0; i<size; ++i)
            writeByte(value[i]);
    }

    void BinaryWriter::writeInt(std::int32_t value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    void BinaryWriter::writeFloat(std::float_t value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    int BinaryWriter::write7BitEncodedInt(std::int32_t value)
    {
        int count = 0;
        while (value > 127)
        {
            byte n = static_cast<byte>(value & 127);
            n |= 128;
            writeByte(n); ++count;
            value >>= 7;
        }
        byte n = static_cast<byte>(value);
        writeByte(n); ++count;
        return count;
    }

    int BinaryWriter::writeUtf8Char(int value)
    {
        if (value <= 0x7f)
        {
            writeByte(static_cast<byte>(value));
            return 1;
        }
        if (value <= 0x7ff)
        {
            byte first = value >> 6;
            first &= 0b11011111;
            first |= 0b11000000;
            byte second = value & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;
            writeByte(first);
            writeByte(second);
            return 2;
        }
        if (value <= 0xffff)
        {
            byte first = value >> 12;
            first &= 0b11101111;
            first |= 0b11100000;

            byte second = (value >> 6) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = value & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            return 3;
        }
        if (value <= 0x10ffff)
        {
            byte first = value >> 18;
            first &= 0b11110111;
            first |= 0b11110000;

            byte second = (value >> 12) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = (value >> 6) & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            byte fourth = value & 0b00111111;
            fourth &= 0b10111111;
            fourth |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            writeByte(fourth);
            return 4;
        }
        throw std::runtime_error("unicode is too large");
    }

    void BinaryWriter::writeBoolean(bool value)
    {
        writeByte(byte(value));
    }

    void BinaryWriter::writeString(const std::string &value)
    {
        write7BitEncodedInt(value.length());
        writeBytes(value.length(), reinterpret_cast<const byte*>(value.data()));
    }
}
<commit_msg>修复无法解包汉化版 Content.pak 的问题<commit_after>#include "binaryio.h"
#include <stdexcept>

namespace scpak
{
    void BinaryReader::readBytes(int size, byte buf[])
    {
        for (int i = 0; i<size; ++i)
            buf[i] = readByte();
    }

    std::int32_t BinaryReader::readInt32()
    {
        int value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    std::float_t BinaryReader::readSingle()
    {
        float value;
        readBytes(4, reinterpret_cast<byte*>(&value));
        return value;
    }

    std::int32_t BinaryReader::read7BitEncodedInt()
    {
        int value = 0;
        int offset = 0;
        while (offset != 35)
        {
            byte b = readByte();
            value |= static_cast<int>(b & 127) << offset;
            offset += 7;
            if ((b & 128) == 0)
                return value;
        }
        throw std::runtime_error("bad 7 bit encoded int32");
    }

    int BinaryReader::readUtf8Char()
    {
        byte first = readByte();
        if (first == 0xff)
            return -1; // not a valid utf-8 character, in fact
        if ((first & 0b10000000) == 0)
            // only one byte long, 0b0???????
            return static_cast<int>(first);
        if ((first & 0b11000000) == 0b11000000 && (first & 0b00100000) == 0)
        {
            // two bytes long, 0b110????? 0b10??????
            int second = readByte();
            int value = (first & 0b00011111) << 6;
            value |= second & 0b00111111;
            return value;
        }
        if ((first & 0b11100000) == 0b11100000 && (first & 0b00010000) == 0)
        {
            // three bytes long, 0b1110???? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int value = (first & 0b00001111) << 12;
            value |= (second & 0b00111111) << 6;
            value |= third & 0b00111111;
            return value;
        }
        if ((first & 0b11110000) == 0b11110000 && (first & 0b00001000) == 0)
        {
            // four bytes long, 0b11110??? 0b10?????? 0b10?????? 0b10??????
            int second = readByte();
            int third = readByte();
            int fourth = readByte();
            int value = (first & 0b00000111) << 18;
            value |= (second & 0b00111111) << 12;
            value |= (third & 0b00111111) << 6;
            value |= fourth & 0b00111111;
            return value;
        }
        throw std::runtime_error("utf-8 encoded unicode is too large");
    }

    bool BinaryReader::readBoolean()
    {
        return readByte() ? true : false;
    }

    std::string BinaryReader::readString()
    {
        int length = read7BitEncodedInt();
        std::string buffer;
        buffer.resize(length);
        for (int i = 0; i<length; ++i)
            buffer[i] = static_cast<char>(readByte());
        return buffer;
    }

    int BinaryReader::getUtf8CharCount(const std::string &value)
    {
        MemoryBinaryReader reader(reinterpret_cast<const byte*>(value.data()));
        int count = 0;
        while (reader.position < value.length())
        {
            int unicode = reader.readUtf8Char();
            ++count;
        }
        return count;
    }

    StreamBinaryReader::StreamBinaryReader(std::istream *stream)
    {
        m_stream = stream;
    }

    byte StreamBinaryReader::readByte()
    {
        if (!*m_stream)
            throw std::runtime_error("bad stream");
        char ch;
        m_stream->get(ch);
        return static_cast<byte>(ch);
    }

    MemoryBinaryReader::MemoryBinaryReader(const byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    byte MemoryBinaryReader::readByte()
    {
        return m_buffer[position++];
    }

    StreamBinaryWriter::StreamBinaryWriter(std::ostream *stream)
    {
        m_stream = stream;
    }

    void StreamBinaryWriter::writeByte(byte value)
    {
        if (!m_stream)
            throw std::runtime_error("bad stream");
        char ch = static_cast<char>(value);
        m_stream->put(ch);
    }

    MemoryBinaryWriter::MemoryBinaryWriter(byte *buffer)
    {
        position = 0;
        m_buffer = buffer;
    }

    void MemoryBinaryWriter::writeByte(byte value)
    {
        m_buffer[position++] = value;
    }

    void BinaryWriter::writeBytes(int size, const byte value[])
    {
        for (int i = 0; i<size; ++i)
            writeByte(value[i]);
    }

    void BinaryWriter::writeInt(std::int32_t value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    void BinaryWriter::writeFloat(std::float_t value)
    {
        writeBytes(4, reinterpret_cast<byte*>(&value));
    }

    int BinaryWriter::write7BitEncodedInt(std::int32_t value)
    {
        int count = 0;
        while (value > 127)
        {
            byte n = static_cast<byte>(value & 127);
            n |= 128;
            writeByte(n); ++count;
            value >>= 7;
        }
        byte n = static_cast<byte>(value);
        writeByte(n); ++count;
        return count;
    }

    int BinaryWriter::writeUtf8Char(int value)
    {
        if (value <= 0x7f)
        {
            writeByte(static_cast<byte>(value));
            return 1;
        }
        if (value <= 0x7ff)
        {
            byte first = value >> 6;
            first &= 0b11011111;
            first |= 0b11000000;
            byte second = value & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;
            writeByte(first);
            writeByte(second);
            return 2;
        }
        if (value <= 0xffff)
        {
            byte first = value >> 12;
            first &= 0b11101111;
            first |= 0b11100000;

            byte second = (value >> 6) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = value & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            return 3;
        }
        if (value <= 0x10ffff)
        {
            byte first = value >> 18;
            first &= 0b11110111;
            first |= 0b11110000;

            byte second = (value >> 12) & 0b00111111;
            second &= 0b10111111;
            second |= 0b10000000;

            byte third = (value >> 6) & 0b00111111;
            third &= 0b10111111;
            third |= 0b10000000;

            byte fourth = value & 0b00111111;
            fourth &= 0b10111111;
            fourth |= 0b10000000;

            writeByte(first);
            writeByte(second);
            writeByte(third);
            writeByte(fourth);
            return 4;
        }
        throw std::runtime_error("unicode is too large");
    }

    void BinaryWriter::writeBoolean(bool value)
    {
        writeByte(byte(value));
    }

    void BinaryWriter::writeString(const std::string &value)
    {
        write7BitEncodedInt(value.length());
        writeBytes(value.length(), reinterpret_cast<const byte*>(value.data()));
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <limits>
#include <cassert>
#include <cmath>
#include <memory>

#include "acmacs-base/number-of-dimensions.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"
#include "acmacs-base/indexes.hh"
#include "acmacs-base/range.hh"

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

namespace acmacs
{
    struct Area
    {
        PointCoordinates min, max;

        Area(const PointCoordinates& a_min, const PointCoordinates& a_max) : min(a_min), max(a_max) {}
        Area(const PointCoordinates& a_min) : min(a_min), max(a_min) {}

        number_of_dimensions_t num_dim() const { return min.number_of_dimensions(); }

        void extend(const PointCoordinates& point)
        {
            for (auto dim : range(num_dim())) {
                min[dim] = std::min(point[dim], min[dim]);
                max[dim] = std::max(point[dim], max[dim]);
            }
        }

        double area() const
        {
            double result = max.x() - min.x();
            for (auto dim : range(1UL, num_dim()))
                result *= max[dim] - min[dim];
            return result;
        }

        class Iterator
        {
         private:
            double step_;
            PointCoordinates min_, max_, current_;

            friend struct Area;
            Iterator(double step, const PointCoordinates& a_min, const PointCoordinates& a_max) : step_(step), min_(a_min), max_(a_min), current_(a_min) { set_max(a_max); }
            Iterator() : step_(std::numeric_limits<double>::quiet_NaN()), min_{number_of_dimensions_t{2}}, max_{number_of_dimensions_t{2}}, current_{number_of_dimensions_t{2}} {}

            void set_max(const PointCoordinates& a_max)
                {
                    for (auto dim : range(a_max.number_of_dimensions()))
                        max_[dim] = min_[dim] + std::ceil((a_max[dim] - min_[dim]) / step_) * step_;
                }

          public:
            bool operator==(const Iterator& rhs) const
                {
                    if (std::isnan(rhs.step_))
                        return current_.x() > max_.x();
                    else if (std::isnan(step_))
                        return rhs.current_.x() > rhs.max_.x();
                    else
                        throw std::runtime_error("cannot compare Area::Iterators");
                }

            bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
            const PointCoordinates& operator*() const { return current_; }
            const PointCoordinates* operator->() const { return &current_; }

            const Iterator& operator++()
                {
                    if (current_.x() <= max_.x()) {
                        for (auto dim : range(current_.number_of_dimensions())) {
                            current_[dim] += step_;
                            if (current_[dim] <= max_[dim]) {
                                std::copy(min_.begin(), min_.begin() + static_cast<size_t>(dim), current_.begin());
                                break;
                            }
                        }
                    }
                    return *this;
                }
        };

        Iterator begin(double step) const { return Iterator(step, min, max); }
        Iterator end() const { return Iterator{}; }

    }; // struct Area

    inline std::string to_string(const Area& area, size_t precision = 32) { return acmacs::to_string(area.min, precision) + ' ' + acmacs::to_string(area.max, precision); }

    // inline std::ostream& operator<<(std::ostream& s, const Area& area) { return s << to_string(area, 4); }

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

    class Layout;

    class LayoutConstIterator
    {
      public:
        PointCoordinates operator*() const;
        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }
        bool operator==(const LayoutConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const Layout& parent_;
        mutable size_t point_no_;

        LayoutConstIterator(const Layout& parent, size_t point_no) : parent_{parent}, point_no_{point_no} {}

        friend class Layout;

    }; // class LayoutConstIterator

    class LayoutDimensionConstIterator
    {
      public:
        using difference_type = ssize_t;

        double operator*() const;

        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }

        LayoutDimensionConstIterator operator+(difference_type offset) const
        {
            return {parent_, point_no_ + static_cast<size_t>(offset), dimension_no_};
        }

        bool operator==(const LayoutDimensionConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            if (dimension_no_ != rhs.dimension_no_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for dimensions");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutDimensionConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const Layout& parent_;
        mutable size_t point_no_;
        const number_of_dimensions_t dimension_no_;

        LayoutDimensionConstIterator(const Layout& parent, size_t point_no, number_of_dimensions_t dimension_no) : parent_{parent}, point_no_{point_no}, dimension_no_{dimension_no} {}

        friend class Layout;

    }; // class LayoutDimensionConstIterator

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

    class Layout : public std::vector<double>
    {
      public:
        using Vec = std::vector<double>;

        Layout() = default;
        Layout(const Layout&) = default;
        Layout(Layout&&) = default;
        Layout(size_t number_of_points, number_of_dimensions_t number_of_dimensions) : Vec(number_of_points * static_cast<size_t>(number_of_dimensions), std::numeric_limits<double>::quiet_NaN()), number_of_dimensions_{number_of_dimensions} {}
        Layout(number_of_dimensions_t number_of_dimensions, const double* first, const double* last) : Vec(first, last), number_of_dimensions_{number_of_dimensions} {}
        Layout(const Layout& source, const std::vector<size_t>& indexes);
        virtual ~Layout() = default;
        Layout& operator=(const Layout&) = default;
        Layout& operator=(Layout&&) = default;

        size_t number_of_points() const noexcept { return size() / static_cast<size_t>(number_of_dimensions_); }
        constexpr number_of_dimensions_t number_of_dimensions() const noexcept { return number_of_dimensions_; }

        void change_number_of_dimensions(number_of_dimensions_t num_dim, bool allow_dimensions_increase = false)
        {
            if (!allow_dimensions_increase && num_dim >= number_of_dimensions_)
                throw std::runtime_error(fmt::format("Layout::change_number_of_dimensions: dimensions increase: {} --> {}", number_of_dimensions_, num_dim));
            resize(number_of_points() * static_cast<size_t>(num_dim));
            number_of_dimensions_ = num_dim;
        }

        const PointCoordinates operator[](size_t point_no) const
        {
            return PointCoordinates(Vec::begin() + static_cast<difference_type>(point_no * static_cast<size_t>(number_of_dimensions_)), Vec::begin() + static_cast<difference_type>((point_no + 1) * static_cast<size_t>(number_of_dimensions_)));
        }

        PointCoordinates operator[](size_t point_no)
        {
            return PointCoordinates(Vec::begin() + static_cast<difference_type>(point_no * static_cast<size_t>(number_of_dimensions_)), Vec::begin() + static_cast<difference_type>((point_no + 1) * static_cast<size_t>(number_of_dimensions_)));
        }

        PointCoordinates at(size_t point_no) const { return operator[](point_no); }

        double operator()(size_t point_no, number_of_dimensions_t aDimensionNo) const { return Vec::operator[](point_no * static_cast<size_t>(number_of_dimensions_) + static_cast<size_t>(aDimensionNo)); }
        double& operator()(size_t point_no, number_of_dimensions_t aDimensionNo) { return Vec::operator[](point_no * static_cast<size_t>(number_of_dimensions_) + static_cast<size_t>(aDimensionNo)); }
        double coordinate(size_t point_no, number_of_dimensions_t aDimensionNo) const { return operator()(point_no, aDimensionNo); }
        double& coordinate(size_t point_no, number_of_dimensions_t aDimensionNo) { return operator()(point_no, aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const { return operator[](point_no).exists(); }
        const std::vector<double>& as_flat_vector_double() const { return *this; }

        void set_nan(size_t point_no)
        {
            const auto first{Vec::begin() + static_cast<difference_type>(point_no * static_cast<size_t>(number_of_dimensions_))}, last{first + static_cast<difference_type>(*number_of_dimensions_)};
            std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
        }

        void remove_points(const ReverseSortedIndexes& indexes, size_t base)
        {
            for (const auto index : indexes) {
                const auto first = Vec::begin() + static_cast<difference_type>((index + base) * static_cast<size_t>(number_of_dimensions_));
                erase(first, first + static_cast<difference_type>(*number_of_dimensions_));
            }
        }

        void insert_point(size_t before, size_t base)
        {
            insert(Vec::begin() + static_cast<difference_type>((before + base) * static_cast<size_t>(number_of_dimensions_)), *number_of_dimensions_, std::numeric_limits<double>::quiet_NaN());
        }

        std::vector<std::pair<double, double>> minmax() const;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            if (const auto c1 = operator[](p1), c2 = operator[](p2); c1.exists() && c2.exists())
                return acmacs::distance(c1, c2);
            else
                return no_distance;
        }

        // returns indexes for min points for each dimension and max points for each dimension
        std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
        // returns boundary coordinates (min and max)
        Area area() const;                                  // for all points
        Area area(const std::vector<size_t>& points) const; // just for the specified point indexes
        std::shared_ptr<Layout> transform(const Transformation& aTransformation) const;
        PointCoordinates centroid() const;

        LayoutConstIterator begin() const { return {*this, 0}; }
        LayoutConstIterator end() const { return {*this, number_of_points()}; }
        LayoutConstIterator begin_antigens(size_t /*number_of_antigens*/) const { return {*this, 0}; }
        LayoutConstIterator end_antigens(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator begin_sera(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator end_sera(size_t /*number_of_antigens*/) const { return {*this, number_of_points()}; }

        LayoutDimensionConstIterator begin_dimension(number_of_dimensions_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_dimension(number_of_dimensions_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }
        LayoutDimensionConstIterator begin_antigens_dimension(size_t /*number_of_antigens*/, number_of_dimensions_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_antigens_dimension(size_t number_of_antigens, number_of_dimensions_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator begin_sera_dimension(size_t number_of_antigens, number_of_dimensions_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator end_sera_dimension(size_t /*number_of_antigens*/, number_of_dimensions_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }

      private:
        number_of_dimensions_t number_of_dimensions_{2};

    }; // class Layout

    inline PointCoordinates LayoutConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.at(point_no_);
    }

    inline double LayoutDimensionConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.coordinate(point_no_, dimension_no_);
    }

} // namespace acmacs

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

template <> struct fmt::formatter<acmacs::Area>
{
    template <typename ParseContext> constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
    template <typename FormatContext> auto format(const acmacs::Area& area, FormatContext& ctx) { return format_to(ctx.out(), "Area{{min:{:.4f}, max:{:.4f}}}", area.min, area.max); }
};

// format for Layout is format for double of each coordinate, e.g. :.8f

template <> struct fmt::formatter<acmacs::Layout>
{
    template <typename ParseContext> constexpr auto parse(ParseContext& ctx)
    {
        if (const auto end_of_fomat = std::find(ctx.begin(), ctx.end(), '}'); end_of_fomat != ctx.end()) {
            const auto begin = *ctx.begin() == ':' ? std::next(ctx.begin()) : ctx.begin();
            format_for_point_coord.resize(static_cast<size_t>(end_of_fomat - begin + 3));
            format_for_point_coord[0] = '{';
            format_for_point_coord[1] = ':';
            std::copy(begin, end_of_fomat, std::next(format_for_point_coord.begin(), 2));
            format_for_point_coord.back() = '}';
            return end_of_fomat;
        }
        return ctx.begin();
    }

    template <typename FormatContext> auto format(const acmacs::Layout& layout, FormatContext& ctx)
    {
        const auto format_val = [this](const acmacs::PointCoordinates& pc) { return fmt::format(format_for_point_coord, pc); };
        format_to(ctx.out(), "Layout {}d ({})\n", layout.number_of_dimensions(), layout.number_of_points());
        const auto num_digits_in_point_no = static_cast<int>(std::log10(layout.number_of_points())) + 1;
        for (size_t no = 0; no < layout.number_of_points(); ++no)
            format_to(ctx.out(), "  {:{}d} {}\n", no, num_digits_in_point_no, format_val(layout[no]));
        return ctx.out();
    }

    std::string format_for_point_coord;
};

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>Layout interface improvements<commit_after>#pragma once

#include <limits>
#include <cassert>
#include <cmath>
#include <memory>

#include "acmacs-base/number-of-dimensions.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"
#include "acmacs-base/indexes.hh"
#include "acmacs-base/range.hh"

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

namespace acmacs
{
    struct Area
    {
        PointCoordinates min, max;

        Area(const PointCoordinates& a_min, const PointCoordinates& a_max) : min(a_min), max(a_max) {}
        Area(const PointCoordinates& a_min) : min(a_min), max(a_min) {}

        number_of_dimensions_t num_dim() const { return min.number_of_dimensions(); }

        void extend(const PointCoordinates& point)
        {
            for (auto dim : range(num_dim())) {
                min[dim] = std::min(point[dim], min[dim]);
                max[dim] = std::max(point[dim], max[dim]);
            }
        }

        double area() const
        {
            double result = max.x() - min.x();
            for (auto dim : range(1UL, num_dim()))
                result *= max[dim] - min[dim];
            return result;
        }

        class Iterator
        {
         private:
            double step_;
            PointCoordinates min_, max_, current_;

            friend struct Area;
            Iterator(double step, const PointCoordinates& a_min, const PointCoordinates& a_max) : step_(step), min_(a_min), max_(a_min), current_(a_min) { set_max(a_max); }
            Iterator() : step_(std::numeric_limits<double>::quiet_NaN()), min_{number_of_dimensions_t{2}}, max_{number_of_dimensions_t{2}}, current_{number_of_dimensions_t{2}} {}

            void set_max(const PointCoordinates& a_max)
                {
                    for (auto dim : range(a_max.number_of_dimensions()))
                        max_[dim] = min_[dim] + std::ceil((a_max[dim] - min_[dim]) / step_) * step_;
                }

          public:
            bool operator==(const Iterator& rhs) const
                {
                    if (std::isnan(rhs.step_))
                        return current_.x() > max_.x();
                    else if (std::isnan(step_))
                        return rhs.current_.x() > rhs.max_.x();
                    else
                        throw std::runtime_error("cannot compare Area::Iterators");
                }

            bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
            const PointCoordinates& operator*() const { return current_; }
            const PointCoordinates* operator->() const { return &current_; }

            const Iterator& operator++()
                {
                    if (current_.x() <= max_.x()) {
                        for (auto dim : range(current_.number_of_dimensions())) {
                            current_[dim] += step_;
                            if (current_[dim] <= max_[dim]) {
                                std::copy(min_.begin(), min_.begin() + static_cast<size_t>(dim), current_.begin());
                                break;
                            }
                        }
                    }
                    return *this;
                }
        };

        Iterator begin(double step) const { return Iterator(step, min, max); }
        Iterator end() const { return Iterator{}; }

    }; // struct Area

    inline std::string to_string(const Area& area, size_t precision = 32) { return acmacs::to_string(area.min, precision) + ' ' + acmacs::to_string(area.max, precision); }

    // inline std::ostream& operator<<(std::ostream& s, const Area& area) { return s << to_string(area, 4); }

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

    class Layout;

    class LayoutConstIterator
    {
      public:
        PointCoordinates operator*() const;
        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }
        bool operator==(const LayoutConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const Layout& parent_;
        mutable size_t point_no_;

        LayoutConstIterator(const Layout& parent, size_t point_no) : parent_{parent}, point_no_{point_no} {}

        friend class Layout;

    }; // class LayoutConstIterator

    class LayoutDimensionConstIterator
    {
      public:
        using difference_type = ssize_t;

        double operator*() const;

        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }

        LayoutDimensionConstIterator operator+(difference_type offset) const
        {
            return {parent_, point_no_ + static_cast<size_t>(offset), dimension_no_};
        }

        bool operator==(const LayoutDimensionConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            if (dimension_no_ != rhs.dimension_no_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for dimensions");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutDimensionConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const Layout& parent_;
        mutable size_t point_no_;
        const number_of_dimensions_t dimension_no_;

        LayoutDimensionConstIterator(const Layout& parent, size_t point_no, number_of_dimensions_t dimension_no) : parent_{parent}, point_no_{point_no}, dimension_no_{dimension_no} {}

        friend class Layout;

    }; // class LayoutDimensionConstIterator

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

    class Layout : public std::vector<double>
    {
      public:
        using Vec = std::vector<double>;

        Layout() = default;
        Layout(const Layout&) = default;
        Layout(Layout&&) = default;
        Layout(size_t number_of_points, number_of_dimensions_t number_of_dimensions) : Vec(number_of_points * static_cast<size_t>(number_of_dimensions), std::numeric_limits<double>::quiet_NaN()), number_of_dimensions_{number_of_dimensions} {}
        Layout(number_of_dimensions_t number_of_dimensions, const double* first, const double* last) : Vec(first, last), number_of_dimensions_{number_of_dimensions} {}
        Layout(const Layout& source, const std::vector<size_t>& indexes);
        virtual ~Layout() = default;
        Layout& operator=(const Layout&) = default;
        Layout& operator=(Layout&&) = default;

        size_t number_of_points() const noexcept { return size() / static_cast<size_t>(number_of_dimensions_); }
        constexpr number_of_dimensions_t number_of_dimensions() const noexcept { return number_of_dimensions_; }

        void change_number_of_dimensions(number_of_dimensions_t num_dim, bool allow_dimensions_increase = false)
        {
            if (!allow_dimensions_increase && num_dim >= number_of_dimensions_)
                throw std::runtime_error(fmt::format("Layout::change_number_of_dimensions: dimensions increase: {} --> {}", number_of_dimensions_, num_dim));
            resize(number_of_points() * static_cast<size_t>(num_dim));
            number_of_dimensions_ = num_dim;
        }

        const PointCoordinates operator[](size_t point_no) const
        {
            return PointCoordinates(Vec::begin() + static_cast<difference_type>(point_no * static_cast<size_t>(number_of_dimensions_)), Vec::begin() + static_cast<difference_type>((point_no + 1) * static_cast<size_t>(number_of_dimensions_)));
        }

        // use update(index, point) instead of layout[index] = point

        const PointCoordinates at(size_t point_no) const { return operator[](point_no); }

        double operator()(size_t point_no, number_of_dimensions_t aDimensionNo) const { return Vec::operator[](point_no * static_cast<size_t>(number_of_dimensions_) + static_cast<size_t>(aDimensionNo)); }
        double& operator()(size_t point_no, number_of_dimensions_t aDimensionNo) { return Vec::operator[](point_no * static_cast<size_t>(number_of_dimensions_) + static_cast<size_t>(aDimensionNo)); }
        double coordinate(size_t point_no, number_of_dimensions_t aDimensionNo) const { return operator()(point_no, aDimensionNo); }
        double& coordinate(size_t point_no, number_of_dimensions_t aDimensionNo) { return operator()(point_no, aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const { return operator[](point_no).exists(); }
        const std::vector<double>& as_flat_vector_double() const { return *this; }

        void update(size_t point_no, const PointCoordinates& point)
        {
            assert(point_no < number_of_points());
            assert(point.number_of_dimensions() == number_of_dimensions());
            for (number_of_dimensions_t dim{0}; dim < number_of_dimensions(); ++dim)
                coordinate(point_no, dim) = point[dim];
        }

        void set_nan(size_t point_no)
        {
            const auto first{Vec::begin() + static_cast<difference_type>(point_no * static_cast<size_t>(number_of_dimensions_))}, last{first + static_cast<difference_type>(*number_of_dimensions_)};
            std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
        }

        void remove_points(const ReverseSortedIndexes& indexes, size_t base)
        {
            for (const auto index : indexes) {
                const auto first = Vec::begin() + static_cast<difference_type>((index + base) * static_cast<size_t>(number_of_dimensions_));
                erase(first, first + static_cast<difference_type>(*number_of_dimensions_));
            }
        }

        void insert_point(size_t before, size_t base)
        {
            insert(Vec::begin() + static_cast<difference_type>((before + base) * static_cast<size_t>(number_of_dimensions_)), *number_of_dimensions_, std::numeric_limits<double>::quiet_NaN());
        }

        std::vector<std::pair<double, double>> minmax() const;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            if (const auto c1 = operator[](p1), c2 = operator[](p2); c1.exists() && c2.exists())
                return acmacs::distance(c1, c2);
            else
                return no_distance;
        }

        // returns indexes for min points for each dimension and max points for each dimension
        std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
        // returns boundary coordinates (min and max)
        Area area() const;                                  // for all points
        Area area(const std::vector<size_t>& points) const; // just for the specified point indexes
        std::shared_ptr<Layout> transform(const Transformation& aTransformation) const;
        PointCoordinates centroid() const;

        LayoutConstIterator begin() const { return {*this, 0}; }
        LayoutConstIterator end() const { return {*this, number_of_points()}; }
        LayoutConstIterator begin_antigens(size_t /*number_of_antigens*/) const { return {*this, 0}; }
        LayoutConstIterator end_antigens(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator begin_sera(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator end_sera(size_t /*number_of_antigens*/) const { return {*this, number_of_points()}; }

        LayoutDimensionConstIterator begin_dimension(number_of_dimensions_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_dimension(number_of_dimensions_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }
        LayoutDimensionConstIterator begin_antigens_dimension(size_t /*number_of_antigens*/, number_of_dimensions_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_antigens_dimension(size_t number_of_antigens, number_of_dimensions_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator begin_sera_dimension(size_t number_of_antigens, number_of_dimensions_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator end_sera_dimension(size_t /*number_of_antigens*/, number_of_dimensions_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }

      private:
        number_of_dimensions_t number_of_dimensions_{2};

    }; // class Layout

    inline PointCoordinates LayoutConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.at(point_no_);
    }

    inline double LayoutDimensionConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.coordinate(point_no_, dimension_no_);
    }

} // namespace acmacs

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

template <> struct fmt::formatter<acmacs::Area>
{
    template <typename ParseContext> constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
    template <typename FormatContext> auto format(const acmacs::Area& area, FormatContext& ctx) { return format_to(ctx.out(), "Area{{min:{:.4f}, max:{:.4f}}}", area.min, area.max); }
};

// format for Layout is format for double of each coordinate, e.g. :.8f

template <> struct fmt::formatter<acmacs::Layout>
{
    template <typename ParseContext> constexpr auto parse(ParseContext& ctx)
    {
        if (const auto end_of_fomat = std::find(ctx.begin(), ctx.end(), '}'); end_of_fomat != ctx.end()) {
            const auto begin = *ctx.begin() == ':' ? std::next(ctx.begin()) : ctx.begin();
            format_for_point_coord.resize(static_cast<size_t>(end_of_fomat - begin + 3));
            format_for_point_coord[0] = '{';
            format_for_point_coord[1] = ':';
            std::copy(begin, end_of_fomat, std::next(format_for_point_coord.begin(), 2));
            format_for_point_coord.back() = '}';
            return end_of_fomat;
        }
        return ctx.begin();
    }

    template <typename FormatContext> auto format(const acmacs::Layout& layout, FormatContext& ctx)
    {
        const auto format_val = [this](const acmacs::PointCoordinates& pc) { return fmt::format(format_for_point_coord, pc); };
        format_to(ctx.out(), "Layout {}d ({})\n", layout.number_of_dimensions(), layout.number_of_points());
        const auto num_digits_in_point_no = static_cast<int>(std::log10(layout.number_of_points())) + 1;
        for (size_t no = 0; no < layout.number_of_points(); ++no)
            format_to(ctx.out(), "  {:{}d} {}\n", no, num_digits_in_point_no, format_val(layout[no]));
        return ctx.out();
    }

    std::string format_for_point_coord;
};

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#pragma once

#include <limits>
#include <cassert>

#include "acmacs-base/vector.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"
#include "acmacs-base/indexes.hh"

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

namespace acmacs
{
    class Coordinates : public Vector
    {
     public:
        using Vector::Vector;

        Coordinates transform(const Transformation& aTransformation) const
            {
                const auto [x, y] = aTransformation.transform(operator[](0), operator[](1));
                return {x, y};
            }

        bool not_nan() const
            {
                return !empty() && std::all_of(begin(), end(), [](double value) -> bool { return ! std::isnan(value); });
            }

        operator Location() const { assert(size() == 2); return {operator[](0), operator[](1)}; }

    }; // class Coordinates

    inline std::ostream& operator<<(std::ostream& s, const Coordinates& c)
    {
        stream_internal::write_to_stream(s, c, "[", "]", ", ");
        return s;
    }

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

    class LayoutInterface
    {
     public:
        LayoutInterface() = default;
        LayoutInterface(const LayoutInterface&) = default;
        virtual ~LayoutInterface() = default;
        LayoutInterface& operator=(const LayoutInterface&) = default;

        virtual size_t number_of_points() const noexcept = 0;
        virtual size_t number_of_dimensions() const noexcept = 0;
        virtual const Coordinates operator[](size_t aPointNo) const = 0;
        const Coordinates get(size_t aPointNo) const { return operator[](aPointNo); }
        Coordinates& operator[](size_t) = delete; // use set()!
        virtual double coordinate(size_t aPointNo, size_t aDimensionNo) const = 0;
        double operator()(size_t aPointNo, size_t aDimensionNo) const { return coordinate(aPointNo, aDimensionNo); }
        virtual bool point_has_coordinates(size_t point_no) const = 0;
        virtual std::vector<double> as_flat_vector_double() const = 0;
        virtual std::vector<float> as_flat_vector_float() const = 0;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            const auto c1 = operator[](p1);
            const auto c2 = operator[](p2);
            return (c1.not_nan() && c2.not_nan()) ? c1.distance(c2) : no_distance;
        }

          // returns indexes for min points for each dimension and max points for each dimension
        virtual std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
          // returns boundary coordinates (min and max)
        virtual std::pair<Coordinates, Coordinates> boundaries() const;
        virtual LayoutInterface* transform(const Transformation& aTransformation) const;
        virtual Coordinates centroid() const;

        virtual void set(size_t aPointNo, const Coordinates& aCoordinates) = 0;
        virtual void set(size_t point_no, size_t dimension_no, double value) = 0;

    }; // class LayoutInterface

    inline std::ostream& operator<<(std::ostream& s, const LayoutInterface& aLayout)
    {
        s << "Layout [";
        for (size_t no = 0; no < aLayout.number_of_points(); ++no)
            s << aLayout[no] << ' ';
        s << ']';
        return s;
    }

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

    class Layout : public virtual LayoutInterface, public std::vector<double>
    {
     public:
        Layout() = default;
        Layout(size_t aNumberOfPoints, size_t aNumberOfDimensions)
            : std::vector<double>(aNumberOfPoints * aNumberOfDimensions, std::numeric_limits<double>::quiet_NaN()),
            number_of_dimensions_{aNumberOfDimensions}
            {}
        Layout(const Layout&) = default;
        Layout(const LayoutInterface& aSource) : std::vector<double>(aSource.as_flat_vector_double()), number_of_dimensions_{aSource.number_of_dimensions()} {}
        Layout(const LayoutInterface& aSource, const std::vector<size_t>& aIndexes); // make layout by subsetting source
        Layout& operator=(const Layout&) = default;

        size_t number_of_points() const noexcept override { return size() / number_of_dimensions_; }
        size_t number_of_dimensions() const noexcept override { return number_of_dimensions_; }

        void change_number_of_dimensions(size_t num_dim, bool allow_dimensions_increase = false)
            {
                if (!allow_dimensions_increase && num_dim >= number_of_dimensions_) {
                    throw std::runtime_error("Layout::change_number_of_dimensions: dimensions increase: " + std::to_string(number_of_dimensions_) + " --> " + std::to_string(num_dim));
                      // std::cerr << "WARNING: Layout::change_number_of_dimensions: " << number_of_dimensions_ << " --> " << num_dim << '\n';
                }
                resize(number_of_points() * num_dim);
                number_of_dimensions_ = num_dim;
            }

        const Coordinates operator[](size_t aPointNo) const override
            {
                using diff_t = decltype(begin())::difference_type;
                return {begin() + static_cast<diff_t>(aPointNo * number_of_dimensions_), begin() + static_cast<diff_t>((aPointNo + 1) * number_of_dimensions_)};
            }

        double coordinate(size_t aPointNo, size_t aDimensionNo) const override { return at(aPointNo * number_of_dimensions_ + aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const override { return !std::isnan(coordinate(point_no, 0)); }
        std::vector<double> as_flat_vector_double() const override { return *this; }
        std::vector<float> as_flat_vector_float() const override { return {begin(), end()}; }
        void set(size_t aPointNo, const Coordinates& aCoordinates) override
            {
                std::copy(aCoordinates.begin(), aCoordinates.end(), begin() + static_cast<decltype(begin())::difference_type>(aPointNo * number_of_dimensions()));
            }

        void set_nan(size_t aPointNo)
            {
                using diff_t = decltype(begin())::difference_type;
                const auto first{begin() + static_cast<diff_t>(aPointNo * number_of_dimensions())}, last{first + static_cast<diff_t>(number_of_dimensions())};
                std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
            }

        virtual void set(size_t point_no, size_t dimension_no, double value) override { std::vector<double>::operator[](point_no * number_of_dimensions() + dimension_no) = value; }

        void remove_points(const ReverseSortedIndexes& indexes, size_t base)
        {
            for (const auto index : indexes) {
                const auto first = begin() + static_cast<difference_type>(index + base);
                erase(first, first + static_cast<difference_type>(number_of_dimensions_));
            }
        }

      private:
        size_t number_of_dimensions_;

    }; // class Layout

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>bug fix<commit_after>#pragma once

#include <limits>
#include <cassert>

#include "acmacs-base/vector.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"
#include "acmacs-base/indexes.hh"

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

namespace acmacs
{
    class Coordinates : public Vector
    {
     public:
        using Vector::Vector;

        Coordinates transform(const Transformation& aTransformation) const
            {
                const auto [x, y] = aTransformation.transform(operator[](0), operator[](1));
                return {x, y};
            }

        bool not_nan() const
            {
                return !empty() && std::all_of(begin(), end(), [](double value) -> bool { return ! std::isnan(value); });
            }

        operator Location() const { assert(size() == 2); return {operator[](0), operator[](1)}; }

    }; // class Coordinates

    inline std::ostream& operator<<(std::ostream& s, const Coordinates& c)
    {
        stream_internal::write_to_stream(s, c, "[", "]", ", ");
        return s;
    }

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

    class LayoutInterface
    {
     public:
        LayoutInterface() = default;
        LayoutInterface(const LayoutInterface&) = default;
        virtual ~LayoutInterface() = default;
        LayoutInterface& operator=(const LayoutInterface&) = default;

        virtual size_t number_of_points() const noexcept = 0;
        virtual size_t number_of_dimensions() const noexcept = 0;
        virtual const Coordinates operator[](size_t aPointNo) const = 0;
        const Coordinates get(size_t aPointNo) const { return operator[](aPointNo); }
        Coordinates& operator[](size_t) = delete; // use set()!
        virtual double coordinate(size_t aPointNo, size_t aDimensionNo) const = 0;
        double operator()(size_t aPointNo, size_t aDimensionNo) const { return coordinate(aPointNo, aDimensionNo); }
        virtual bool point_has_coordinates(size_t point_no) const = 0;
        virtual std::vector<double> as_flat_vector_double() const = 0;
        virtual std::vector<float> as_flat_vector_float() const = 0;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            const auto c1 = operator[](p1);
            const auto c2 = operator[](p2);
            return (c1.not_nan() && c2.not_nan()) ? c1.distance(c2) : no_distance;
        }

          // returns indexes for min points for each dimension and max points for each dimension
        virtual std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
          // returns boundary coordinates (min and max)
        virtual std::pair<Coordinates, Coordinates> boundaries() const;
        virtual LayoutInterface* transform(const Transformation& aTransformation) const;
        virtual Coordinates centroid() const;

        virtual void set(size_t aPointNo, const Coordinates& aCoordinates) = 0;
        virtual void set(size_t point_no, size_t dimension_no, double value) = 0;

    }; // class LayoutInterface

    inline std::ostream& operator<<(std::ostream& s, const LayoutInterface& aLayout)
    {
        s << "Layout [";
        for (size_t no = 0; no < aLayout.number_of_points(); ++no)
            s << aLayout[no] << ' ';
        s << ']';
        return s;
    }

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

    class Layout : public virtual LayoutInterface, public std::vector<double>
    {
     public:
        Layout() = default;
        Layout(size_t aNumberOfPoints, size_t aNumberOfDimensions)
            : std::vector<double>(aNumberOfPoints * aNumberOfDimensions, std::numeric_limits<double>::quiet_NaN()),
            number_of_dimensions_{aNumberOfDimensions}
            {}
        Layout(const Layout&) = default;
        Layout(const LayoutInterface& aSource) : std::vector<double>(aSource.as_flat_vector_double()), number_of_dimensions_{aSource.number_of_dimensions()} {}
        Layout(const LayoutInterface& aSource, const std::vector<size_t>& aIndexes); // make layout by subsetting source
        Layout& operator=(const Layout&) = default;

        size_t number_of_points() const noexcept override { return size() / number_of_dimensions_; }
        size_t number_of_dimensions() const noexcept override { return number_of_dimensions_; }

        void change_number_of_dimensions(size_t num_dim, bool allow_dimensions_increase = false)
            {
                if (!allow_dimensions_increase && num_dim >= number_of_dimensions_) {
                    throw std::runtime_error("Layout::change_number_of_dimensions: dimensions increase: " + std::to_string(number_of_dimensions_) + " --> " + std::to_string(num_dim));
                      // std::cerr << "WARNING: Layout::change_number_of_dimensions: " << number_of_dimensions_ << " --> " << num_dim << '\n';
                }
                resize(number_of_points() * num_dim);
                number_of_dimensions_ = num_dim;
            }

        const Coordinates operator[](size_t aPointNo) const override
            {
                return {begin() + static_cast<difference_type>(aPointNo * number_of_dimensions_), begin() + static_cast<difference_type>((aPointNo + 1) * number_of_dimensions_)};
            }

        double coordinate(size_t aPointNo, size_t aDimensionNo) const override { return at(aPointNo * number_of_dimensions_ + aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const override { return !std::isnan(coordinate(point_no, 0)); }
        std::vector<double> as_flat_vector_double() const override { return *this; }
        std::vector<float> as_flat_vector_float() const override { return {begin(), end()}; }
        void set(size_t aPointNo, const Coordinates& aCoordinates) override
            {
                std::copy(aCoordinates.begin(), aCoordinates.end(), begin() + static_cast<decltype(begin())::difference_type>(aPointNo * number_of_dimensions()));
            }

        void set_nan(size_t aPointNo)
            {
                const auto first{begin() + static_cast<difference_type>(aPointNo * number_of_dimensions())}, last{first + static_cast<difference_type>(number_of_dimensions())};
                std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
            }

        virtual void set(size_t point_no, size_t dimension_no, double value) override { std::vector<double>::operator[](point_no * number_of_dimensions() + dimension_no) = value; }

        void remove_points(const ReverseSortedIndexes& indexes, size_t base)
        {
            for (const auto index : indexes) {
                const auto first = begin() + static_cast<difference_type>((index + base) * number_of_dimensions_);
                erase(first, first + static_cast<difference_type>(number_of_dimensions_));
            }
        }

      private:
        size_t number_of_dimensions_;

    }; // class Layout

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>