[med-svn] [Git][med-team/gjh-asl-json][master] Initial package commit

Andrei Rozanski gitlab at salsa.debian.org
Fri Sep 4 13:32:28 BST 2020



Andrei Rozanski pushed to branch master at Debian Med / gjh-asl-json


Commits:
b2d3dc3e by Andrei Rozanski at 2020-09-04T14:32:12+02:00
Initial package commit

- - - - -


14 changed files:

- + .travis.yml
- + LICENSE
- + Makefile
- + README.rst
- + Thirdparty/get.ASL
- + src/AmplInterface.cpp
- + src/AmplInterface.hpp
- + src/gjh_asl_json.cpp
- + tests/generate_tests.py
- + tests/runtests.sh
- + tests/stub1.col
- + tests/stub1.nl
- + tests/stub1.row
- + tests/stub2.nl


Changes:

=====================================
.travis.yml
=====================================
@@ -0,0 +1,33 @@
+language: cpp
+sudo: false
+matrix:
+  include:
+    - os: linux
+      compiler: clang
+      env: COVCMD="llvm-cov gcov"
+    - os: linux
+      compiler: gcc
+      env: COVCMD="gcov"
+    - os: osx
+      compiler: clang
+      env: COVCMD="gcov"
+    - os: osx
+      compiler: gcc
+      env: COVCMD="gcov"
+install:
+ - cd Thirdparty/
+ - ./get.ASL
+ - cd ..
+ - make COVERAGE="-coverage -O0"
+script:
+ - echo ${COVCMD}
+ - test -x bin/gjh_asl_json
+ - cd tests/
+ - bash runtests.sh
+ - cd ..
+ - ${COVCMD} src/*
+after_success:
+ - bash <(curl -s https://codecov.io/bash) -X gcov
+after_script:
+ - make clean
+ - "! test -f bin/gjh_asl_json"


=====================================
LICENSE
=====================================
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>


=====================================
Makefile
=====================================
@@ -0,0 +1,34 @@
+SRC=src
+TPL=Thirdparty
+
+PREFIX=.
+BIN=$(PREFIX)/bin
+
+# Override this to inject gcov flags "-coverage -O0"
+# in travis CI script. E.g., $ make COVERAGE="-coverage -O0"
+COVERAGE=-O3
+
+CINC=-I$(SRC) -I$(TPL)/solvers
+CFLAGS= -pipe -DASL_BUILD -fPIC -DPIC -Wall
+LDFLAGS=-ldl
+
+all: 	$(TPL)/solvers/amplsolver.a \
+	$(BIN)/gjh_asl_json
+
+$(BIN)/gjh_asl_json: $(SRC)/gjh_asl_json.o \
+	             $(SRC)/AmplInterface.o \
+		     $(TPL)/solvers/amplsolver.a
+	@mkdir -p $(BIN)
+	$(CXX) $(COVERAGE) $(CFLAGS) $(CINC) $^ $(LDFLAGS) -o $@
+
+%.o : %.cpp $(SRC)/AmplInterface.hpp
+	$(CXX) $(COVERAGE) $(CFLAGS) $(CINC) -c $< -o $@
+
+$(TPL)/solvers/amplsolver.a :
+	make -C $(TPL)/solvers/;
+
+clean:
+	rm -f $(BIN)/gjh_asl_json;
+	rm -f $(SRC)/*.o
+	rm -f $(SRC)/*~
+	make clean -C $(TPL)/solvers;


=====================================
README.rst
=====================================
@@ -0,0 +1,32 @@
+gjh_asl_json
+============
+
+.. image:: https://travis-ci.org/ghackebeil/gjh_asl_json.svg?branch=master
+    :target: https://travis-ci.org/ghackebeil/gjh_asl_json
+
+.. image:: https://codecov.io/gh/ghackebeil/gjh_asl_json/branch/master/graph/badge.svg
+    :target: https://codecov.io/gh/ghackebeil/gjh_asl_json
+
+A simple tool providing similar functionality to that of the gjh
+"solver" distributed with the AMPL Solver Library. NLP information
+is summarized in a JSON-formatted output file.
+
+Installation
+~~~~~~~~~~~~
+
+1. $ cd Thirdparty/
+2. $ ./get.ASL
+3. $ cd ..
+4. $ make
+
+Usage
+~~~~~
+
+1. $ gjh_asl_json stub.nl rows=stub.row cols=stub.col
+2. $ python
+
+.. code-block:: pycon
+
+    >>> import json
+    >>> with open('stub.json') as f:
+    >>>    gjh = json.load(f)


=====================================
Thirdparty/get.ASL
=====================================
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+
+rm -f solvers.tgz
+wget http://www.ampl.com/netlib/ampl/solvers.tgz
+rm -rf solvers
+tar xf solvers.tgz
+rm solvers.tgz
+cd solvers
+sed -e 's/CFLAGS = /CFLAGS = -O3 -pipe -DNDEBUG -DASL_BUILD  -fPIC -DPIC /g' makefile.u > Makefile
+cd ..


=====================================
src/AmplInterface.cpp
=====================================
@@ -0,0 +1,1023 @@
+#include "AmplInterface.hpp"
+#include <sstream>
+#include <algorithm>
+#include <stdexcept>
+
+#include "asl.h"
+#include "asl_pfgh.h"
+#include "getstub.h"
+
+namespace {
+
+void _ASSERT_(bool x) {if (!(x)) {throw std::runtime_error("Assertion Failed");}}
+void _ASSERT_(bool x, std::string message) {if (!(x)) {throw std::runtime_error(message);}}
+
+} // end local namespace
+
+AmplInterface::AmplInterface(int argc, char**& argv)
+  :
+   asl_(NULL),
+   Oinfo_ptr_(NULL),
+   primal_assumed_(1.0),
+   dual_assumed_(1.0),
+   stubname_(""),
+   objn_(-1),
+   obj_sense_(0),
+   nnz_hes_lag_(-1)
+{
+   rows_map.clear();
+   cols_map.clear();
+
+   // The ASL include files #define certain
+   // variables that they expect you to work with.
+   // These variables then appear as though they are
+   // global variables when, in fact, they are not
+   // Most of them are data members of an asl object
+
+   // Create the ASL structure
+   ASL_pfgh* asl(NULL);
+   asl = (ASL_pfgh*)ASL_alloc(ASL_read_pfgh);
+   _ASSERT_(asl != NULL, "ASL Error: ASL_alloc return NULL for asl struct pointer");
+   asl_ = asl; // keep the pointer for ourselves to use later...
+
+   // Read the options and stub
+   Oinfo_ptr_ = new Option_Info;
+   char sname[] = "gjh_asl_json";
+   Oinfo_ptr_->sname = new char[strlen(sname)+1];
+   strcpy(Oinfo_ptr_->sname, sname);
+
+   char bsname[] = "gjh_asl_json: Version 1.0.0";
+   Oinfo_ptr_->bsname = new char[strlen(bsname)+1];
+   strcpy(Oinfo_ptr_->bsname, bsname);
+
+   char opname[] = "gjh_asl_json_options";
+   Oinfo_ptr_->opname = new char[strlen(opname)+1];
+   strcpy(Oinfo_ptr_->opname, opname);
+
+   int options_count = 5;
+   char* rows_res(NULL);
+   char* cols_res(NULL);
+   keyword keywords[] = {/* must be alphabetical */
+      /* one may notice that I'm going overboard here to shut up warnings
+	 about 'deprecated conversion from string const to char*' */
+      KW(const_cast<char*>("assumed_dual"),
+         D_val,
+         &dual_assumed_,
+         const_cast<char*>("Assumed value of dual when not specified (default: 1)")),
+      KW(const_cast<char*>("assumed_primal"),
+         D_val,
+         &primal_assumed_,
+         const_cast<char*>("Assumed value of primal when not specified (default: 1)")),
+      KW(const_cast<char*>("cols"),
+         C_val,
+         &cols_res,
+         const_cast<char*>("Map of variable names to variable ids")),
+      KW(const_cast<char*>("rows"),
+         C_val,
+         &rows_res,
+         const_cast<char*>("Map of constraint names to constraint ids")),
+      KW(const_cast<char*>("wantsol"),
+         WS_val,
+         NULL,
+         WS_desc_ASL+5)};
+
+   Oinfo_ptr_->keywds = keywords;
+   Oinfo_ptr_->n_keywds = options_count;
+   Oinfo_ptr_->flags = 0;
+   Oinfo_ptr_->version = NULL;
+   Oinfo_ptr_->usage = NULL;
+   Oinfo_ptr_->kwf = NULL;
+   Oinfo_ptr_->feq = NULL;
+   Oinfo_ptr_->options = NULL;
+   Oinfo_ptr_->n_options = 0;
+   Oinfo_ptr_->driver_date = 0;
+   Oinfo_ptr_->wantsol = 0;
+   Oinfo_ptr_->nS = 0;
+   Oinfo_ptr_->S = NULL;
+   Oinfo_ptr_->uinfo = NULL;
+   Oinfo_ptr_->asl = NULL;
+   Oinfo_ptr_->eqsign = NULL;
+   Oinfo_ptr_->n_badopts = 0;
+   Oinfo_ptr_->option_echo = 0;
+   Oinfo_ptr_->nnl = 0;
+
+   // read the options and get the name of the .nl file (stub)
+   char* stub = getstops(argv, Oinfo_ptr_);
+
+   // Try to handle most of the input suffixes commonly
+   // handled by solvers. Is there a way to except any
+   // suffix?  If new ones are encountered they should be
+   // added. This program is only meant to summarize what
+   // has been passed to an ASL solver, so we are ignoring
+   // outonly suffixes.
+   SufDecl suftab[] = {
+         /* these are used for testing */
+      {const_cast<char*>("var_int"), 0, ASL_Sufkind_var},
+      {const_cast<char*>("var_real"), 0, ASL_Sufkind_var | ASL_Sufkind_real},
+      {const_cast<char*>("con_int"), 0, ASL_Sufkind_con},
+      {const_cast<char*>("con_real"), 0, ASL_Sufkind_con | ASL_Sufkind_real},
+      {const_cast<char*>("obj_int"), 0, ASL_Sufkind_obj},
+      {const_cast<char*>("obj_real"), 0, ASL_Sufkind_obj | ASL_Sufkind_real},
+      {const_cast<char*>("obj_int"), 0, ASL_Sufkind_obj},
+      {const_cast<char*>("obj_real"), 0, ASL_Sufkind_obj | ASL_Sufkind_real},
+      {const_cast<char*>("prob_int"), 0, ASL_Sufkind_prob},
+      {const_cast<char*>("prob_real"), 0, ASL_Sufkind_prob | ASL_Sufkind_real},
+         /* these are commonly associated with solvers */
+      {const_cast<char*>("direction"), 0, ASL_Sufkind_var},
+      {const_cast<char*>("lazy"), 0, ASL_Sufkind_con},
+      {const_cast<char*>("lbpen"), 0, ASL_Sufkind_var | ASL_Sufkind_real},
+      {const_cast<char*>("priority"), 0, ASL_Sufkind_var},
+      {const_cast<char*>("ref"), 0, ASL_Sufkind_var | ASL_Sufkind_real},
+      {const_cast<char*>("rhspen"), 0, ASL_Sufkind_con | ASL_Sufkind_real},
+      {const_cast<char*>("sos"), 0, ASL_Sufkind_var},
+      {const_cast<char*>("sos"), 0, ASL_Sufkind_con},
+      {const_cast<char*>("sosno"), 0, ASL_Sufkind_var | ASL_Sufkind_real},
+      {const_cast<char*>("sosref"), 0, ASL_Sufkind_var | ASL_Sufkind_real},
+      {const_cast<char*>("sstatus"), 0, ASL_Sufkind_var, 1},
+      {const_cast<char*>("sstatus"), 0, ASL_Sufkind_con, 1},
+      {const_cast<char*>("ubpen"), 0, ASL_Sufkind_var | ASL_Sufkind_real}};
+
+   suf_declare(suftab, sizeof(suftab)/sizeof(SufDecl));
+
+   _ASSERT_(stub != NULL, "ASL Error: nl filename pointer is NULL");
+   stubname_ = std::string(stub);
+
+   FILE* nl = NULL;
+   nl = jac0dim(stub, (int)strlen(stub));
+   _ASSERT_(nl != NULL, "ASL Error: jac0dim return NULL for nl file pointer");
+
+   // tells ASL to get initial values for primal and dual
+   // if available and allocate memory for X0 and pi0
+   want_xpi0 = 1 | 2;
+   // tells ASL to keep track of which dual and primal
+   // indicies were supplied by the user
+   havex0 = new char[n_var];
+   std::fill_n(havex0,n_var,0);
+   havepi0 = new char[n_con];
+   std::fill_n(havepi0,n_con,0);
+
+   // read the rest of the nl file accepting the most general
+   // problem form
+   int read_flags = ASL_return_read_err;
+   // Still confused as to why this one causes a segfault.
+   // Maybe keep means "keep out of memory" and NOT
+   // "allocate memory for"...????
+   //read_flags |= ASL_keep_all_suffixes;
+   read_flags |= ASL_allow_CLP;
+   read_flags |= ASL_findgroups;
+   read_flags |= ASL_find_co_class;
+   int retcode = pfgh_read(nl, read_flags);
+   // close the stub.nl file, we are finished with it
+   // calling this causes a seg fauilt on some systems
+   //fclose(nl);
+
+   switch (retcode) {
+   case ASL_readerr_none : {}
+      break;
+   case ASL_readerr_nofile : {
+      throw std::runtime_error("ASL Error: cannot open .nl file");
+   }
+      break;
+   case ASL_readerr_nonlin : {
+      throw std::runtime_error("ASL Error: model involves nonlinearities (ed0read)");
+   }
+      break;
+   case  ASL_readerr_argerr : {
+      throw std::runtime_error("ASL Error: user-defined function with bad args");
+   }
+      break;
+   case ASL_readerr_unavail : {
+      throw std::runtime_error("ASL Error: user-defined function not available");
+   }
+      break;
+   case ASL_readerr_corrupt : {
+      throw std::runtime_error("ASL Error: corrupt .nl file");
+   }
+      break;
+   case ASL_readerr_bug : {
+      throw std::runtime_error("ASL Error: bug in .nl reader");
+   }
+      break;
+   case ASL_readerr_CLP : {
+      throw std::runtime_error("ASL Error: AMPL model contains a constraint without \"=\", \">=\", or \"<=\".");
+   }
+      break;
+   default: {
+      std::ostringstream output;
+      output << "ASL Error: Unknown error in stub file read. retcode = " << retcode;
+      throw std::runtime_error(output.str());
+   }
+      break;
+   }
+
+   // Build the variable and constraint output maps
+   // use .col/.row files if supplied as options
+   if (cols_res) {
+      std::ifstream in;
+      in.open(cols_res, std::ios_base::in);
+      if (in.is_open() && in.good()) {
+	 for (int i = 0; i < n_var; ++i) {
+	    in >> cols_map[i];
+	 }
+      }
+      else {
+         std::ostringstream output;
+         output << "Failed to open cols file: " << std::string(cols_res);
+         throw std::runtime_error(output.str());
+      }
+      in.close();
+   }
+   else {
+      for (int i = 0; i < n_var; ++i) {
+	 std::ostringstream stream;
+	 stream << i;
+	 cols_map[i] = stream.str();
+      }
+   }
+   if (rows_res) {
+      std::ifstream in;
+      in.open(rows_res, std::ios_base::in);
+      if (in.is_open() && in.good()) {
+	 for (int i = 0; i < n_con+n_obj; ++i) {
+	    in >> rows_map[i];
+	 }
+      }
+      else {
+         std::ostringstream output;
+         output << "Failed to open rows file: " << std::string(rows_res);
+         throw std::runtime_error(output.str());
+      }
+      in.close();
+   }
+   else {
+      for (int i = 0; i < n_con; ++i) {
+	 std::ostringstream stream;
+	 stream << i;
+	 rows_map[i] = stream.str();
+      }
+      for (int i = 0; i < n_obj; ++i) {
+	 std::ostringstream stream;
+	 stream << i;
+	 rows_map[n_con+i] = stream.str();
+      }
+   }
+
+   set_current_objective(0);
+}
+
+AmplInterface::~AmplInterface()
+{
+   ASL_pfgh* asl = asl_;
+
+   delete [] havex0;
+   havex0 = NULL;
+   delete [] havepi0;
+   havepi0 = NULL;
+
+   // delete options object
+   delete [] Oinfo_ptr_->sname;
+   Oinfo_ptr_->sname = NULL;
+   delete [] Oinfo_ptr_->bsname;
+   Oinfo_ptr_->bsname = NULL;
+   delete [] Oinfo_ptr_->opname;
+   Oinfo_ptr_->opname = NULL;
+   delete Oinfo_ptr_;
+   Oinfo_ptr_ = NULL;
+
+   if (asl) {
+     ASL* asl_to_free = (ASL*)asl_;
+     ASL_free(&asl_to_free);
+     asl_ = NULL;
+   }
+
+   // output maps
+   rows_map.clear();
+   cols_map.clear();
+
+   stubname_ = std::string("");
+   objn_ = -1;
+   obj_sense_ = -1;
+   nnz_hes_lag_ = -1;
+}
+
+void AmplInterface::write_solution_file()
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+
+   std::vector<double> start_primal_dense(n_var);
+   std::vector<double> start_dual_dense(n_con);
+   primal_starting_point(&(start_primal_dense[0]));
+   dual_starting_point(&(start_dual_dense[0]));
+   write_sol("",
+             &(start_primal_dense[0]),
+             &(start_dual_dense[0]),
+             (Option_Info*)Oinfo_ptr_);
+}
+
+void AmplInterface::write_json_summary(std::ostream& out)
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(objective_count() == n_obj,
+            "Number of objectives does not match");
+   out << "{" << std::endl; // JSON START
+   ////////////////////////
+   // PROBLEM STATISTICS //
+   ////////////////////////
+   out << "\"problem statistics\": {" << std::endl;
+   out << "  \"no. linear network constraints\": " << lnc << "," << std::endl;
+   out << "  \"no. of linear binary variables\": " << nbv << "," << std::endl;
+   out << "  \"no. of linear non-binary integer variables\": " << niv << "," << std::endl;
+   out << "  \"total no. of nonlinear constraints\": " << nlc << "," << std::endl;
+   out << "  \"number of equality constraints or -1 if unknown (ampl prior to 19970627)\": " << n_eqn << "," << std::endl;
+   out << "  \"total complementarity conditions\": " << n_cc << "," << std::endl;
+   out << "  \"nonlinear complementarity conditions\": " << nlcc << "," << std::endl;
+   /* ndcc is not defined */
+   //out << "  \"number of complementarities involving double inequalities\": " << ndcc << "," << std::endl;
+   /* nzlb is not defined */
+   //out << "  \"number of complemented variables with a nonzero lower bound\": " << nzlb << "," << std::endl;
+   out << "  \"no. of nonlinear network constraints\": " << nlnc << "," << std::endl;
+   out << "  \"no. of nonlinear objectives\": " << nlo << "," << std::endl;
+   out << "  \"no. of nonlinear variables in both constraints and objectives\": " << nlvb << "," << std::endl;
+   /* nlvc and nlvo include nlvb\": "*/
+   out << "  \"no. of nonlinear variables in constraints\": " << nlvc << "," << std::endl;
+   out << "  \"no. of nonlinear variables in objectives\": " << nlvo << "," << std::endl;
+   out << "  \"integer nonlinear variables in both constraints and objectives\": " << nlvbi << "," << std::endl;
+   out << "  \"integer nonlinear vars just in constraints\": " << nlvci << "," << std::endl;
+   out << "  \"integer nonlinear vars just in objectives\": " << nlvoi << "," << std::endl;
+   out << "  \"no. of (linear) network variables (arcs)\": " << nwv << "," << std::endl;
+   out << "  \"no. of nonzeros in constraints' Jacobian\": " << nzc << "," << std::endl;
+   out << "  \"no. of logical constraints\": " << n_lcon << "," << std::endl;
+   out << "  \"no. of nonzeros in all objective gradients\": " << nzo << "," << std::endl;
+   _ASSERT_(n_obj == 1, "multiple objectives found");
+   out << "  \"total no. of variables\": " << n_var << "," << std::endl;
+   out << "  \"total no. of constraints\": " << n_con << "," << std::endl;
+   out << "  \"total no. of objectives\": " << objective_count() << "," << std::endl;
+   out << "  \"objective statistics\": {" << std::endl;
+   for (int objective_number = 0; objective_number < n_obj; ++objective_number) {
+      out << "    \"" << rows_map[n_con+objective_number] << "\": {" << std::endl;
+      set_current_objective(objective_number);
+      int tmpx;
+      int tmpc;
+      int tmpnnzjacc;
+      int tmpnnzheslag;
+      nlp_dimensions(tmpx, tmpc, tmpnnzjacc, tmpnnzheslag);
+      _ASSERT_(tmpx == n_var,
+               "Number of vars does not match");
+      _ASSERT_(tmpc == n_con,
+               "Number of cons does not match");
+      _ASSERT_(tmpnnzjacc == nzc,
+               "Number nonzeros in constraints jacobian does not match");
+      _ASSERT_(tmpnnzheslag == nnz_hes_lag_,
+               "Number of nonzeros in lagrangian hessian does not match");
+      if (current_objective_sense() == -1) {
+         out << "      \"objective sense\": " << "\"maximize\"" << "," << std::endl;
+      }
+      else if (current_objective_sense() == 1) {
+         out << "      \"objective sense\": " << "\"minimize\"" << "," << std::endl;
+      }
+      out << "        \"no. of nonzeros in full lagrangian hessian\": " << nnz_hes_lag_ << std::endl;
+      out << "    }";
+      if (objective_number < n_obj-1) {out << ",";}
+      out << std::endl;
+   }
+   out << "  }" << std::endl; // end OBJECTIVE STATISTICS
+   out << "}," << std::endl; // end PROBLEM STATISTICS
+
+   /////////////////////
+   // SOS CONSTRAINTS //
+   /////////////////////
+   // treat sos suffixes a little differently than the rest
+   out << "\"sos constraints\": [" << std::endl;
+   int n_sos_sets = 0;
+   int nsosnz = 0;
+   char *sostype(NULL);
+   int *sosbeg(NULL), *sosind(NULL);
+   real *sosref(NULL);
+   int i = ASL_suf_sos_explict_free;
+   n_sos_sets = suf_sos(i, &nsosnz, &sostype, 0, 0, &sosbeg, &sosind, &sosref);
+   for(int i = 0; i < n_sos_sets; ++i) {
+      out << "  {" << std::endl;
+      out << "  \"type\": " << sostype[i] << "," << std::endl;
+      out << "  \"vars\": [ ";
+      int start = sosbeg[i];
+      int stop = sosbeg[i+1];
+      for (int j = start; j < stop; ++j) {
+	 out << "[\"" << cols_map[sosind[j]] << "\"," << sosref[j] << "]";
+	 if (j != stop-1) {out << ",";}
+	 out << " ";
+      }
+      out << "]" << std::endl;
+      out << "  }";
+      if (i != n_sos_sets-1) {out << ",";}
+      out << std::endl;
+   }
+   free(sosref);
+   out << "]," << std::endl; // end SOS CONSTRAINTS
+
+   //////////////////////////////
+   // SUFFIXES //
+   //////////////////////////////
+   out << "\"suffixes\": {" << std::endl;
+   out << "  \"variable\": {" << std::endl;
+   SufDesc d;
+   for (int i = 0; i < asl->i.nsuff[ASL_Sufkind_var]; ++i) {
+      d = asl->i.suffixes[ASL_Sufkind_var][i];
+      if (d.u.i || d.u.r) {
+	 out << "    \"" << std::string(d.sufname) << "\": {" << std::endl;
+	 if (d.u.i) {
+	    for (int j = 0; j < n_var; ++j) {
+	       if (d.u.i[j] != 0) {
+		  out << "      \"" << cols_map[j] << "\": " << d.u.i[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < n_var; ++k) {
+		     if (d.u.i[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 if (d.u.r) {
+	    for (int j = 0; j < n_var; ++j) {
+	       if (d.u.r[j] != 0) {
+		  out << "      \"" << cols_map[j] << "\": " << d.u.r[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < n_var; ++k) {
+		     if (d.u.r[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 out << "    }";
+	 // check if anything else will output, if so we need a comma
+	 for (int k=i+1; k < asl->i.nsuff[ASL_Sufkind_var]; ++k) {
+	    d = asl->i.suffixes[ASL_Sufkind_var][k];
+	    if (d.u.i || d.u.r) {
+	       out << ",";
+	       break;
+	    }
+	 }
+	 out << std::endl;
+      }
+   }
+   out << "  }," << std::endl; // end variable
+
+   out << "  \"constraint\": {" << std::endl;
+   for (int i = 0; i < asl->i.nsuff[ASL_Sufkind_con]; ++i) {
+      d = asl->i.suffixes[ASL_Sufkind_con][i];
+      if (d.u.i || d.u.r) {
+	 out << "    \"" << std::string(d.sufname) << "\": {" << std::endl;
+	 if (d.u.i) {
+	    for (int j = 0; j < n_con; ++j) {
+	       if (d.u.i[j] != 0) {
+		  out << "      \"" << rows_map[j] << "\": " << d.u.i[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < n_con; ++k) {
+		     if (d.u.i[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 if (d.u.r) {
+	    for (int j = 0; j < n_con; ++j) {
+	       if (d.u.r[j] != 0) {
+		  out << "      \"" << rows_map[j] << "\": " << d.u.r[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < n_con; ++k) {
+		     if (d.u.r[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 out << "    }";
+	 // check if anything else will output, if so we need a comma
+	 for (int k=i+1; k < asl->i.nsuff[ASL_Sufkind_con]; ++k) {
+	    d = asl->i.suffixes[ASL_Sufkind_con][k];
+	    if (d.u.i || d.u.r) {
+	       out << ",";
+	       break;
+	    }
+	 }
+	 out << std::endl;
+      }
+   }
+   out << "  }," << std::endl; // end constraint
+
+
+   out << "  \"objective\": {" << std::endl;
+   for (int i = 0; i < asl->i.nsuff[ASL_Sufkind_obj]; ++i) {
+      d = asl->i.suffixes[ASL_Sufkind_obj][i];
+      if (d.u.i || d.u.r) {
+	 out << "    \"" << std::string(d.sufname) << "\": {" << std::endl;
+	 if (d.u.i) {
+	    for (int j = 0; j < n_obj; ++j) {
+	       if (d.u.i[j] != 0) {
+		  out << "      \"" << rows_map[n_con+j] << "\": " << d.u.i[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < n_obj; ++k) {
+		     if (d.u.i[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 if (d.u.r) {
+	    for (int j = 0; j < n_obj; ++j) {
+	       if (d.u.r[j] != 0) {
+		  out << "      \"" << rows_map[n_con+j] << "\": " << d.u.r[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < n_obj; ++k) {
+		     if (d.u.r[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 out << "    }";
+	 // check if anything else will output, if so we need a comma
+	 for (int k=i+1; k < asl->i.nsuff[ASL_Sufkind_obj]; ++k) {
+	    d = asl->i.suffixes[ASL_Sufkind_obj][k];
+	    if (d.u.i || d.u.r) {
+	       out << ",";
+	       break;
+	    }
+	 }
+	 out << std::endl;
+      }
+   }
+   out << "  }," << std::endl; // end obj
+
+   out << "  \"problem\": {" << std::endl;
+   for (int i = 0; i < asl->i.nsuff[ASL_Sufkind_prob]; ++i) {
+      d = asl->i.suffixes[ASL_Sufkind_prob][i];
+      if (d.u.i || d.u.r) {
+	 out << "    \"" << std::string(d.sufname) << "\": {" << std::endl;
+	 if (d.u.i) {
+	    for (int j = 0; j < asl->i.n_prob; ++j) {
+	       if (d.u.i[j] != 0) {
+		  out << "      \"" << j << "\": " << d.u.i[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < asl->i.n_prob; ++k) {
+		     if (d.u.i[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 if (d.u.r) {
+	    for (int j = 0; j < asl->i.n_prob; ++j) {
+	       if (d.u.r[j] != 0) {
+		  out << "      \"" << j << "\": " << d.u.r[j];
+		  // check if anything else will output, if so we need a comma
+		  for (int k=j+1; k < asl->i.n_prob; ++k) {
+		     if (d.u.r[k] != 0) {
+			out << ",";
+			break;
+		     }
+		  }
+		  out << std::endl;
+	       }
+	    }
+	 }
+	 out << "    }";
+	 // check if anything else will output, if so we need a comma
+	 for (int k=i+1; k < asl->i.nsuff[ASL_Sufkind_prob]; ++k) {
+	    d = asl->i.suffixes[ASL_Sufkind_prob][k];
+	    if (d.u.i || d.u.r) {
+	       out << ",";
+	       break;
+	    }
+	 }
+	 out << std::endl;
+      }
+   }
+   out << "  }" << std::endl; // end problem
+   out << "}," << std::endl; // end SUFFIXES
+
+   //////////////////////////////
+   // SUPPLIED STARTING POINTS //
+   //////////////////////////////
+   out << "\"supplied starting points\": {" << std::endl;
+   std::map<int,double> start_primal_sparse, start_dual_sparse;
+   primal_starting_point(start_primal_sparse);
+   dual_starting_point(start_dual_sparse);
+   out << "  \"primal\": {" << std::endl;
+   for (std::map<int,double>::iterator pos = start_primal_sparse.begin(),
+           pos_stop = start_primal_sparse.end();
+        pos != pos_stop; /*++inside loop*/) {
+      out << "    \"" << cols_map[pos->first] << "\": " << pos->second;
+      if (++pos != pos_stop) {out << ",";}
+      out << std::endl;
+   }
+   out << "  }," << std::endl; // end primal
+   out << "  \"dual\": {" << std::endl;
+   for (std::map<int,double>::iterator pos = start_dual_sparse.begin(),
+           pos_stop = start_dual_sparse.end();
+        pos != pos_stop; /*++ inside loop*/) {
+      out << "    \"" << rows_map[pos->first] << "\": " << pos->second;
+      if (++pos != pos_stop) {out << ",";}
+      out << std::endl;
+   }
+   out << "  }" << std::endl; // end dual
+   out << "}," << std::endl; // end SUPPLIED STARTING POINTS
+
+   /////////////////////////////
+   // ASSUMED STARTING POINTS //
+   /////////////////////////////
+   out << "\"assumed starting points\": {" << std::endl;
+   std::vector<double> start_primal_dense(n_var, primal_assumed_);
+   std::vector<double> start_dual_dense(n_con, dual_assumed_);
+   primal_starting_point(&(start_primal_dense[0]));
+   dual_starting_point(&(start_dual_dense[0]));
+   out << "  \"primal\": " << primal_assumed_ << "," << std::endl;
+   out << "  \"dual\": " << dual_assumed_ << std::endl;
+   out << "}," << std::endl; // end ASSUMED STARTING POINTS
+
+   /////////////////////
+   // VARIABLE BOUNDS //
+   /////////////////////
+   out << "\"variable bounds\": {" << std::endl;
+   std::vector<double> XL(n_var), XU(n_var);
+   var_bounds(&(XL[0]),&(XU[0]));
+   for (int i = 0; i < n_var; ++i) {
+      std::ostringstream XLs;
+      std::ostringstream XUs;
+      if (XU[i] == negInfinity) {XUs << "-Infinity";} // JSON
+      else if (XU[i] == Infinity) {XUs << "Infinity";} // JSON
+      else {XUs << XU[i];}
+      if (XL[i] == negInfinity) {XLs << "-Infinity";} // JSON
+      else if (XL[i] == Infinity) {XLs << "Infinity";} // JSON
+      else {XLs << XL[i];}
+      out << "  \"" << cols_map[i] << "\": [" << XLs.str() << "," << XUs.str() << "]";
+      if (i < n_var-1) {out << ",";}
+      out << std::endl;
+   }
+   out << "}," << std::endl; // end VARIABLE BOUNDS
+
+   ///////////////////////
+   // CONSTRAINT BOUNDS //
+   ///////////////////////
+   out << "\"constraint bounds\": {" << std::endl;
+   std::vector<double> CL(n_con), CU(n_con);
+   con_bounds(&(CL[0]),&(CU[0]));
+   for (int i = 0; i < n_con; ++i) {
+      std::ostringstream CLs;
+      std::ostringstream CUs;
+      if (CU[i] == negInfinity) {CUs << "-Infinity";} // JSON
+      else if (CU[i] == Infinity) {CUs << "Infinity";} // JSON
+      else {CUs << CU[i];}
+      if (CL[i] == negInfinity) {CLs << "-Infinity";} // JSON
+      else if (CL[i] == Infinity) {CLs << "Infinity";} // JSON
+      else {CLs << CL[i];}
+      out << "  \"" << rows_map[i] << "\": [" << CLs.str() << "," << CUs.str() << "]";
+      if (i < n_con-1) {out << ",";}
+      out << std::endl;
+   }
+   out << "}," << std::endl; // end CONSTRAINT BOUNDS
+
+   /////////////////////////
+   // INITIAL EVALUATIONS //
+   /////////////////////////
+   out << "\"initial evaluations\": {" << std::endl;
+   out << "  \"objective function\": {" << std::endl;
+   std::vector<double> con_eval(n_con);
+   for (int objective_number = 0; objective_number < n_obj; ++objective_number) {
+      out << "    \"" << rows_map[n_con+objective_number] << "\": {" << std::endl;
+      set_current_objective(objective_number);
+
+      // objective
+      double F = 0.0;
+      eval_f(&(start_primal_dense[0]),F);
+      // so we can call eval_hes_lag
+      eval_c(&(start_primal_dense[0]), &(con_eval[0]));
+      out << "      \"value\": " << F << "," << std::endl;
+
+      // derivative of objective
+      std::vector<double> deriv_F(n_var);
+      eval_deriv_f(&(start_primal_dense[0]),&(deriv_F[0]));
+      out << "      \"gradient\": {" << std::endl;
+      for (int i = 0; i < n_var; ++i) {
+         out << "        \"" << cols_map[i] << "\": " << deriv_F[i];
+         if (i < n_var-1) {out << ",";}
+         out << std::endl;
+      }
+      out << "      }," << std::endl; // end objective gradient
+
+      // lagrangian hessian
+      out << "      \"lagrangian hessian\": {" << std::endl;
+      if (nnz_hes_lag_ > 0) {
+         std::vector<int> hlag_irow(nnz_hes_lag_), hlag_jcol(nnz_hes_lag_);
+         struct_hes_lag(&(hlag_irow[0]),&(hlag_jcol[0]));
+         std::vector<double> hlag_vals(nnz_hes_lag_);
+         eval_hes_lag(&(start_dual_dense[0]),&(hlag_vals[0]));
+         for (int i = 0; i < nnz_hes_lag_; ++i) {
+            out << "        \"" << cols_map[hlag_irow[i]] << "_" << cols_map[hlag_jcol[i]] << "\": " << hlag_vals[i];
+            if (i < nnz_hes_lag_-1) {out << ",";}
+            out << std::endl;
+         }
+      }
+      out << "      }" << std::endl; // end lagrangian hessian
+      out << "    }";
+      if (objective_number < n_obj-1) {out << ",";}
+      out << std::endl;
+   }
+   out << "  }," << std::endl; // end OBJECTIVE FUNCTION
+
+   // constraints
+   eval_c(&(start_primal_dense[0]),&(con_eval[0]));
+   out << "  \"constraints\": {" << std::endl;
+   for (int i = 0; i < n_con; ++i) {
+      out << "    \"" << rows_map[i] << "\": " << con_eval[i];
+      if (i < n_con-1) {out << ",";}
+      out << std::endl;
+   }
+   out << "  }," << std::endl; // end constraints
+
+   // jacobian of constraints
+   std::vector<int> jac_irow(nzc), jac_jcol(nzc);
+   struct_jac_c(&(jac_irow[0]),&(jac_jcol[0]));
+   std::vector<double> jac_vals(nzc);
+   eval_jac_c(&(start_primal_dense[0]),&(jac_vals[0]));
+   out << "  \"constraints' jacobian\": {" << std::endl;
+   for (int i = 0; i < nzc; ++i) {
+      out << "    \"" << rows_map[jac_irow[i]] << "_" << cols_map[jac_jcol[i]] << "\": " << jac_vals[i];
+      if (i < nzc-1) {out << ",";}
+      out << std::endl;
+   }
+   out << "  }" << std::endl; // end constraints' jacobian
+   out << "}" << std::endl; // end INITIAL EVALUATIONS
+   out << "}" << std::endl; // JSON STOP
+}
+
+int AmplInterface::objective_count()
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   return n_obj;
+}
+
+void AmplInterface::set_current_objective(int objective_number)
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(objective_number >= 0,
+            "objective id must be non-negative when calling set_objective");
+   _ASSERT_(objective_number < n_obj,
+            "found invalid objective id when calling set_objective");
+
+   objn_ = objective_number;
+   if (objtype[objective_number] != 0) {
+      obj_sense_ = -1;
+   }
+   else {
+      obj_sense_ = 1;
+   }
+
+   int mult_supplied = 1; // multipliers will be supplied
+   // I specifically ask for the entire matrix (even though it is
+   // symmetric) so that we can compare AMPL and Pyomo. Because of
+   // differences in the variable ordering, we can have that dxdy ends up
+   // in the upper triangle for AMPL nl files whereas dydx ends up in the
+   // upper triangle for Pyomo nl files. Obtaining the entire matrix
+   // avoids this complication.
+   int uptri = 0; // use the full sparse matrix
+   nnz_hes_lag_ = sphsetup(objn_, NULL, mult_supplied, uptri);
+}
+
+void AmplInterface::nlp_dimensions(int& n_x,
+                                   int& n_c,
+                                   int& nnz_jac_c,
+                                   int& nnz_hes_lag) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   n_x = n_var;
+   n_c = n_con;
+   nnz_jac_c = nzc;
+   nnz_hes_lag = nnz_hes_lag_;
+}
+
+void AmplInterface::con_bounds(double* c_l, double* c_u) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   if (n_con == 0) {return ;} // unconstrained problem
+   _ASSERT_(c_l && c_u, "One or more arguments to con_bounds is NULL");
+
+   for (int i = 0; i < n_con; ++i) {
+      c_l[i] = LUrhs[2*i];
+      c_u[i] = LUrhs[2*i+1];
+   }
+}
+
+void AmplInterface::var_bounds(double* x_l, double* x_u) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(x_l && x_u, "One or more arguments to var_bounds is NULL");
+
+   for (int i = 0; i < n_var; ++i) {
+      x_l[i] = LUv[2*i];
+      x_u[i] = LUv[2*i+1];
+   }
+}
+
+void AmplInterface::eval_f(const double* x, double& f) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(n_obj == 1 && "AMPL problem must have a single objective function");
+   _ASSERT_(x, "First argument to eval_f is NULL");
+
+   int nerror = 1;
+   f = objval(obj_no, (double*)x, &nerror);
+   if (nerror != 0) {
+      throw std::runtime_error("ASL Error: Problem evaluating objective.");
+   }
+}
+
+void AmplInterface::eval_deriv_f(const double* x, double* deriv_f) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(n_obj == 1 && "AMPL problem must have a single objective function.");
+   _ASSERT_(x && deriv_f, "One or more arguments to eval_deriv_f is NULL");
+
+   int nerror = 1;
+   objgrd(obj_no, (double*)x, deriv_f, &nerror);
+   if (nerror != 0) {
+      throw std::runtime_error("ASL Error: Problem evaluating objective gradient.");
+   }
+}
+
+void AmplInterface::eval_c(const double* x, double* c) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   if (n_con == 0) {return ;} // unconstrained problem
+   _ASSERT_(x && c, "One or more arguments to eval_c is NULL");
+
+   // call AMPL to evaluate the constraints
+   int nerror = 1;
+   conval((double*)x, c, &nerror);
+   if (nerror != 0) {
+      throw std::runtime_error("ASL Error: Problem evaluating constraints.");
+   }
+}
+
+void AmplInterface::struct_jac_c(int* irow, int* jcol) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   if (n_con == 0) {return ;} // unconstrained problem
+   _ASSERT_(irow && jcol, "One or more arguments to struct_jac_c is NULL");
+
+   // get the non zero structure of the jacobian of c
+   int current_nz = 0;
+   for (int i = 0; i < n_con; ++i) {
+      for (cgrad* cg=Cgrad[i]; cg; cg = cg->next) {
+	 irow[cg->goff] = i;
+	 jcol[cg->goff] = cg->varno;
+	 ++current_nz;
+      }
+   }
+   _ASSERT_(current_nz == nzc, "Problem evaluating struct_jac_c");
+}
+
+void AmplInterface::eval_jac_c(const double* x, double* jac_c_values) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   if (n_con == 0) {return ;} // unconstrained problem
+   _ASSERT_(x && jac_c_values);
+
+   int nerror=1;
+   jacval((double*)x, jac_c_values, &nerror);
+   if (nerror != 0) {
+      throw std::runtime_error("ASL Error: Problem evaluating constraints' jacobian.");
+   }
+}
+
+void AmplInterface::struct_hes_lag(int* irow, int* jcol) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(n_obj == 1 && "AMPL problem must have a single objective function");
+   _ASSERT_(irow && jcol, "One or more arguments to struct_jac_c is NULL");
+
+   // setup the structure
+   int k = 0;
+   for (int i = 0; i < n_var; ++i) {
+      for (int j=sputinfo->hcolstarts[i]; j<sputinfo->hcolstarts[i+1]; j++) {
+	 irow[k] = i;
+	 jcol[k] = sputinfo->hrownos[j];
+	 k++;
+      }
+   }
+   _ASSERT_(k == nnz_hes_lag_);
+}
+
+void AmplInterface::eval_hes_lag(const double* lam_c, double* hes_lag) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(n_obj == 1, "AMPL problem must have a single objective function");
+   if (n_con == 0) { // unconstrained problem
+      _ASSERT_(hes_lag, "The second argument to eval_hes_lag is NULL");
+      // NOTE: This must be called AFTER a call to objval and conval
+      // (i.e. You must call eval_f and eval_c with the same x before calling this)
+      sphes(hes_lag, objn_ , NULL, NULL);
+   }
+   else {
+      _ASSERT_(lam_c && hes_lag, "One or more arguments to eval_hes_lag is NULL");
+      // NOTE: This must be called AFTER a call to objval and conval
+      // (i.e. You must call eval_f and eval_c with the same x before calling this)
+      sphes(hes_lag, objn_ , NULL, const_cast<double*>(lam_c));
+   }
+}
+
+void AmplInterface::dual_starting_point(double* x) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   if (n_con == 0) {return ;} // unconstrained problem
+   _ASSERT_(x, "Argument of dual_starting_point is NULL");
+
+   for (int i = 0; i < n_con; ++i) {
+      if (havepi0[i]) {
+	 x[i] = pi0[i];
+      }
+      else {
+         x[i] = dual_assumed_;
+      }
+   }
+}
+
+void AmplInterface::dual_starting_point(std::map<int,double>& x) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   x.clear();
+   if (n_con == 0) {return ;} // unconstrained problem
+
+   for (int i = 0; i < n_con; ++i) {
+      if (havepi0[i]) {
+	 x[i] = pi0[i];
+      }
+   }
+}
+
+
+void AmplInterface::primal_starting_point(double* x) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   _ASSERT_(x, "Argument of primal_starting_point is NULL");
+
+   for (int i = 0; i < n_var; ++i) {
+      if (havex0[i]) {
+	 x[i] = X0[i];
+      }
+      else {
+         x[i] = primal_assumed_;
+      }
+   }
+}
+
+void AmplInterface::primal_starting_point(std::map<int,double>& x) const
+{
+   ASL_pfgh* asl = asl_;
+   _ASSERT_(asl_, "Found NULL for asl struct pointer");
+   x.clear();
+
+   for (int i = 0; i < n_var; ++i) {
+      if (havex0[i]) {
+	 x[i] = X0[i];
+      }
+   }
+}


=====================================
src/AmplInterface.hpp
=====================================
@@ -0,0 +1,145 @@
+/*
+*** NOTE: Although the output from WriteSummary() can be parsed
+          using both JSON and YAML, currently the values -inf and inf
+          are written in such a way that only JSON will correctly interpret
+	  them for Python. In summary:
+
+	  Current implementation -
+	  C (-inf, inf) -> JSON (-Infinity, Infinity)
+	  -> parsed by python JSON becomes Python (-inf, inf)
+	  -> parsed by python YAML becomes Python ('-Infinity','Infinity')
+
+	  Alternative implementation -
+	  C (-inf, inf) -> YAML (-.inf, .inf)
+	  -> parsed by python JSON becomes Python ERROR
+	  -> parsed by python YAML becomes Python (-inf,inf)
+*/
+
+#ifndef __AMPLINTERFACE_HPP__
+#define __AMPLINTERFACE_HPP__
+
+#include <iostream>
+#include <fstream>
+#include <cassert>
+#include <vector>
+#include <map>
+#include <string>
+
+/* forward declarations */
+struct ASL_pfgh;
+struct Option_Info;
+
+class AmplInterface
+{
+public:
+   AmplInterface(int argc, char**& argv);
+
+   virtual ~AmplInterface();
+
+   // get the nl file stub name
+   std::string get_stubname() const {return stubname_;}
+
+   // write a sol file
+   void write_solution_file();
+
+   // summarize everything in JSON format
+   void write_json_summary(std::ostream& out);
+
+   double dual_assumed() const {return dual_assumed_;}
+   double primal_assumed() const {return primal_assumed_;}
+
+   void set_dual_assumed(double x) {dual_assumed_ = x;}
+   void set_primal_assumed(double x) {primal_assumed_ = x;}
+
+   // get the current objective
+   int current_objective() const {return objn_;}
+
+   // get the number of objectives for this NLP
+   int objective_count();
+
+   // Sets up interface for subsequent calls to
+   // struct_hes_lag and eval_hes_lag
+   // and determines nnz_hes_lag_ for the current objective
+   void set_current_objective(int objective_number);
+
+   // return the objective sense for the current objective
+   // -1 = maximize, 1 = minimize
+   int current_objective_sense() const {return obj_sense_;}
+
+   // called after setting each objective
+   void nlp_dimensions(int& n_x,
+                       int& n_c,
+                       int& nnz_jac_c,
+                       int& nnz_hes_lag) const;
+
+   void con_bounds(double* c_l, double* c_u) const;
+
+   void var_bounds(double* x_l, double* x_u) const;
+
+   void eval_f(const double* x, double& f) const;
+
+   void eval_deriv_f(const double* x, double* deriv_f) const;
+
+   void eval_c(const double* x, double* c) const;
+
+   void struct_jac_c(int* irow, int* jcol) const;
+
+   void eval_jac_c(const double* x, double* jac_c_values) const;
+
+   void struct_hes_lag(int* irow, int* jcol) const;
+
+   // NOTE: This must be called AFTER a call to objval and conval
+   // (i.e. You must call eval_f and eval_c with the same x before calling this)
+   void eval_hes_lag(const double* lam_c, double* hes_lag) const;
+
+   void primal_starting_point(double* x) const;
+   // sparse version, map is cleared, then filled with only
+   // user supplied values
+   void primal_starting_point(std::map<int,double>& x) const;
+
+   void dual_starting_point(double* x) const;
+   // sparse version, map is cleared, then filled with only
+   // user supplied values
+   void dual_starting_point(std::map<int,double>& x) const;
+
+private:
+
+   // Default Constructor
+   AmplInterface();
+
+   // Copy Constructor
+   AmplInterface(const AmplInterface&);
+
+   // Overloaded Equals Operator
+   void operator=(const AmplInterface&);
+
+   // ASL pointer
+   ASL_pfgh* asl_;
+   Option_Info* Oinfo_ptr_;
+
+   // Assumed primal starting point, when not explicitly given
+   double primal_assumed_;
+
+   // Assumed primal starting point, when not explicitly given
+   double dual_assumed_;
+
+   // stub file name
+   std::string stubname_;
+
+   // keep track if which objective is being used
+   int objn_;
+
+   // obj. sense ... -1 = maximize, 1 = minimize
+   int obj_sense_;
+
+   // number of nonzeros in the hessian
+   int nnz_hes_lag_;
+
+   // output maps to translate ASL indices to
+   // variables/constraint names if .col/.row
+   // files are provided
+   std::map<int,std::string> rows_map;
+   std::map<int,std::string> cols_map;
+};
+
+#endif


=====================================
src/gjh_asl_json.cpp
=====================================
@@ -0,0 +1,22 @@
+#include <AmplInterface.hpp>
+
+#include <iostream>
+#include <fstream>
+
+int main(int argc, char** argv)
+{
+   AmplInterface solver(argc, argv);
+
+   std::string output_name = solver.get_stubname()+".json";
+
+   std::ofstream out;
+   out.open(output_name.c_str(), std::ios::out | std::ios::trunc);
+   out.precision(15);
+   solver.write_json_summary(out);
+   out.close();
+
+   solver.set_current_objective(0);
+   solver.write_solution_file();
+
+   return 0;
+}


=====================================
tests/generate_tests.py
=====================================
@@ -0,0 +1,70 @@
+#
+# The Pyomo script that was used to generate the
+# test files in this directory.
+#
+
+from pyomo.environ import *
+
+model = ConcreteModel()
+model.x = Var([1], initialize=2.0)
+model.y = Var()
+model.o = Objective(expr=model.x[1]**2 + model.y)
+model.c = ConstraintList()
+model.c.add(model.x[1]*model.y + model.x[1] >= 1)
+model.c.add(model.y == 2)
+model.c.add(-10 <= model.y + model.x[1] <= 10.5)
+
+model.dual = Suffix(direction=Suffix.EXPORT)
+model.dual[model.c[1]] = 1.0
+model.dual[model.c[2]] = 0.1
+
+model.sosno = Suffix(direction=Suffix.EXPORT,datatype=Suffix.INT)
+model.sosno[model.x[1]] = 1
+model.sosno[model.y] = 1
+model.ref = Suffix(direction=Suffix.EXPORT,datatype=Suffix.INT)
+model.ref[model.x[1]] = 2
+model.ref[model.y] = 3
+
+model.prob_int = Suffix(direction=Suffix.EXPORT,
+                           datatype=Suffix.INT)
+model.prob_int[model] = 1
+model.prob_real = Suffix(direction=Suffix.EXPORT,
+                             datatype=Suffix.FLOAT)
+model.prob_real[model] = 1.5
+
+model.obj_int = Suffix(direction=Suffix.EXPORT,
+                           datatype=Suffix.INT)
+model.obj_int[model.o] = 2
+model.obj_real = Suffix(direction=Suffix.EXPORT,
+                             datatype=Suffix.FLOAT)
+model.obj_real[model.o] = 2.5
+
+model.con_int = Suffix(direction=Suffix.EXPORT,
+                           datatype=Suffix.INT)
+model.con_int[model.c[1]] = 3
+model.con_int[model.c[2]] = 4
+model.con_int[model.c[3]] = 5
+model.con_real = Suffix(direction=Suffix.EXPORT,
+                             datatype=Suffix.FLOAT)
+model.con_real[model.c[1]] = 3.5
+model.con_real[model.c[2]] = 4.5
+model.con_real[model.c[3]] = 5.5
+
+model.var_int = Suffix(direction=Suffix.EXPORT,
+                           datatype=Suffix.INT)
+model.var_int[model.x[1]] = 6
+model.var_int[model.y] = 7
+model.var_real = Suffix(direction=Suffix.EXPORT,
+                             datatype=Suffix.FLOAT)
+model.var_real[model.x[1]] = 6.5
+model.var_real[model.y] = 7.5
+
+model.write('stub1.nl',
+            io_options={'symbolic_solver_labels':True})
+
+model = ConcreteModel()
+model.x = Var(bounds=(-1, 1))
+model.o = Objective(expr=model.x,
+                    sense=maximize)
+
+model.write('stub2.nl')


=====================================
tests/runtests.sh
=====================================
@@ -0,0 +1,50 @@
+#! /bin/bash
+
+# These are simple tests that mostly serve
+# to generate a code coverage report.
+
+set -e
+
+rm -f stub1.json
+rm -f stub1.sol
+
+# stub1.nl
+! test -f stub1.json
+cmd="../bin/gjh_asl_json stub1.nl"
+echo "Testing command: ${cmd}"
+${cmd}
+test -f stub1.json
+python -c "import json; f = open('stub1.json'); json.load(f); f.close()"
+rm -f stub1.json
+
+# stub1.nl with -s
+! test -f stub1.json
+! test -f stub1.sol
+cmd="../bin/gjh_asl_json -s stub1.nl"
+echo "Testing command: ${cmd}"
+${cmd}
+test -f stub1.json
+test -f stub1.sol
+python -c "import json; f = open('stub1.json'); json.load(f); f.close()"
+rm -f stub1.json
+rm -f stub1.sol
+
+# stub1.nl with row and col labels
+! test -f stub1.json
+cmd="../bin/gjh_asl_json stub1.nl rows=stub1.row cols=stub1.col"
+echo "Testing command: ${cmd}"
+${cmd}
+test -f stub1.json
+python -c "import json; f = open('stub1.json'); json.load(f); f.close()"
+rm -f stub1.json
+
+# stub2.nl
+rm -f stub2.json
+! test -f stub2.json
+cmd="../bin/gjh_asl_json stub2.nl"
+echo "Testing command: ${cmd}"
+${cmd}
+test -f stub2.json
+python -c "import json; f = open('stub2.json'); json.load(f); f.close()"
+
+rm -f stub2.json


=====================================
tests/stub1.col
=====================================
@@ -0,0 +1,2 @@
+x[1]
+y


=====================================
tests/stub1.nl
=====================================
@@ -0,0 +1,75 @@
+g3 1 1 0	# problem unknown
+ 2 3 1 1 1 	# vars, constraints, objectives, ranges, eqns
+ 1 1 0 0 0 0	# nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
+ 0 0	# network constraints: nonlinear, linear
+ 2 1 1 	# nonlinear vars in constraints, objectives, both
+ 0 0 0 1	# linear network variables; functions; arith, flags
+ 0 0 0 0 0 	# discrete variables: binary, integer, nonlinear (b,c,o)
+ 5 2 	# nonzeros in Jacobian, obj. gradient
+ 0 0	# max name lengths: constraints, variables
+ 0 0 0 0 0	# common exprs: b,c,o,c1,o1
+S7 1 prob_real
+0 1.5
+S6 1 obj_real
+0 2.5
+S4 2 var_real
+0 6.5
+1 7.5
+S0 2 var_int
+0 6
+1 7
+S3 1 prob_int
+0 1
+S1 3 con_int
+0 3
+1 4
+2 5
+S2 1 obj_int
+0 2
+S5 3 con_real
+0 3.5
+1 4.5
+2 5.5
+S0 2 ref
+0 2
+1 3
+S0 2 sosno
+0 1
+1 1
+C0	#c[1]
+o2	#*
+v0	#x[1]
+v1	#y
+C1	#c[2]
+n0
+C2	#c[3]
+n0
+O0 0	#o
+o5	#pow
+v0	#x[1]
+n2.0
+d2	# dual initial guess
+0 1.0
+1 0.1
+x1	# initial guess
+0 2.0
+r	#3 ranges (rhs's)
+2 1.0
+4 2.0
+0 -10.0 10.5
+b	#2 bounds (on variables)
+3
+3
+k1	#intermediate Jacobian column lengths
+2
+J0 2
+0 1.0
+1 0
+J1 1
+1 1
+J2 2
+0 1
+1 1
+G0 2
+0 0
+1 1.0


=====================================
tests/stub1.row
=====================================
@@ -0,0 +1,4 @@
+c[1]
+c[2]
+c[3]
+o


=====================================
tests/stub2.nl
=====================================
@@ -0,0 +1,19 @@
+g3 1 1 0	# problem unknown
+ 1 0 1 0 0 	# vars, constraints, objectives, ranges, eqns
+ 0 0 0 0 0 0	# nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
+ 0 0	# network constraints: nonlinear, linear
+ 0 0 0 	# nonlinear vars in constraints, objectives, both
+ 0 0 0 1	# linear network variables; functions; arith, flags
+ 0 0 0 0 0 	# discrete variables: binary, integer, nonlinear (b,c,o)
+ 0 1 	# nonzeros in Jacobian, obj. gradient
+ 0 0	# max name lengths: constraints, variables
+ 0 0 0 0 0	# common exprs: b,c,o,c1,o1
+O0 1
+n0
+x0
+r
+b
+0 -1 1
+k0
+G0 1
+0 1



View it on GitLab: https://salsa.debian.org/med-team/gjh-asl-json/-/commit/b2d3dc3e2c89b70d0b9e35f76681272a481e0557

-- 
View it on GitLab: https://salsa.debian.org/med-team/gjh-asl-json/-/commit/b2d3dc3e2c89b70d0b9e35f76681272a481e0557
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20200904/0e1cb63d/attachment-0001.html>


More information about the debian-med-commit mailing list