Skip to content

Commit

Permalink
NLSolver 'easy': ini guesses, suffix I/O #30
Browse files Browse the repository at this point in the history
  • Loading branch information
glebbelov committed Feb 19, 2024
1 parent 9599638 commit e3baad2
Show file tree
Hide file tree
Showing 9 changed files with 245 additions and 83 deletions.
4 changes: 2 additions & 2 deletions nl-writer2/examples/c/fullAPI_1/nlsol_ex_c_nl.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ int CountNNZ(const double* parray, int len) {
}
void WriteDenseAsSparse(
const double* parray, int len, void* p_api_data) {
for (int i=0; i<len; ++i)
if (parray[i])
for (int i=0; i<len; ++i) // actually we should also write 0
if (parray[i]) // initial guesses if meaningful
NLW2_WriteSparseDblEntry(p_api_data, i, parray[i]);
}

Expand Down
74 changes: 38 additions & 36 deletions nl-writer2/examples/cpp/fullAPI_1/nlsol_ex_nl.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,46 +99,48 @@ class ExampleNLFeeder
csw.Write(Model().col_sizes[i]);
}

// Actually we should write all meaningful entries,
// including 0's
template <class IGWriter>
void FeedInitialGuesses(IGWriter& igw)
{ WriteDense2Sparse(igw, Model().ini_x); }

template <class SuffixWriterFactory>
void FeedSuffixes(SuffixWriterFactory& swf) {
for (int i=0; i<Model().n_suf; ++i) {
if (Model().suf[i].kind_ & 4) { // double's
auto sw = swf.StartDblSuffix(
Model().suf[i].name_,
Model().suf[i].kind_,
CountNNZ(Model().suf[i].values_));
WriteDense2Sparse_Pure(sw, Model().suf[i].values_);
} else { // int's
auto sw = swf.StartIntSuffix(
Model().suf[i].name_,
Model().suf[i].kind_,
CountNNZ(Model().suf[i].values_));
WriteDense2Sparse_Pure(sw, Model().suf[i].values_);
}
}
}

template <class RowObjNameWriter>
void FeedRowAndObjNames(RowObjNameWriter& wrt) {
if (wrt) { // && output_desired
for (int i=0; i<Model().n_con; ++i)
wrt << Model().con_name[i];
wrt << Model().obj_name;
}
}

/** Provide variable names. */
template <class ColNameWriter>
void FeedColNames(ColNameWriter& wrt) {
if (wrt) { // && output_desired
for (int i=0; i<Model().n_var; ++i)
wrt << Model().var_name[i];
}
}
template <class SuffixWriterFactory>
void FeedSuffixes(SuffixWriterFactory& swf) {
for (int i=0; i<Model().n_suf; ++i) {
if (Model().suf[i].kind_ & 4) { // double's
auto sw = swf.StartDblSuffix(
Model().suf[i].name_,
Model().suf[i].kind_,
CountNNZ(Model().suf[i].values_));
WriteDense2Sparse_Pure(sw, Model().suf[i].values_);
} else { // int's
auto sw = swf.StartIntSuffix(
Model().suf[i].name_,
Model().suf[i].kind_,
CountNNZ(Model().suf[i].values_));
WriteDense2Sparse_Pure(sw, Model().suf[i].values_);
}
}
}

template <class RowObjNameWriter>
void FeedRowAndObjNames(RowObjNameWriter& wrt) {
if (wrt) { // && output_desired
for (int i=0; i<Model().n_con; ++i)
wrt << Model().con_name[i];
wrt << Model().obj_name;
}
}

/** Provide variable names. */
template <class ColNameWriter>
void FeedColNames(ColNameWriter& wrt) {
if (wrt) { // && output_desired
for (int i=0; i<Model().n_var; ++i)
wrt << Model().var_name[i];
}
}


protected:
Expand Down
9 changes: 5 additions & 4 deletions nl-writer2/include/api/c/nl-feeder-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,9 +437,10 @@ typedef struct NLW2_NLFeeder_C {
///////////////////// 12. INITIAL GUESSES /////////////////////
/** Initial primal guesses.
*
* Implementation:
* Implementation: write all meaningful entries (incl. zeros.)
* for (size_t i=0; i<n_ini_guess; ++i)
* NLW2_WriteSparseDblEntry(p_api_data, i, ini_guess[i]);
* NLW2_WriteSparseDblEntry(
* p_api_data, ini_index[i], ini_value[i]);
*/
int (*InitialGuessesNNZ)(void* p_user_data);
void (*FeedInitialGuesses)(void* p_user_data, void* p_api_data);
Expand All @@ -456,13 +457,13 @@ typedef struct NLW2_NLFeeder_C {
* For constraints, assume ordering:
* first algebraic, then logical.
*
* Implementation:
* Implementation: write all non-0 entries (0 is the default.)
* while (....) {
* void* p_api_2 = NLW2_StartIntSuffix( // or ...DblSuffix
* p_api_data, suf_name, kind, n_nonzeros);
* for (int i=0; i<n_nonzeros; ++i)
* NLW2_WriteSparseIntEntry(p_api_2, // or ...DblEntry
* index[i], value[i]); // <- p_api_2 here
* index[i], value[i]); // ^<- p_api_2 here
* }
*/
void (*FeedSuffixes)(void* p_user_data, void* p_api_data);
Expand Down
9 changes: 5 additions & 4 deletions nl-writer2/include/mp/nl-feeder.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ namespace mp {
- C API implementation class `~mp::NLW2_NLFeeder_C_Impl`
- Other examples/tests, e.g., see `ExampleNLFeeder`.
@param: *Impl* is a type derived from `~mp::NLFeeder`.
@param: *Impl* is the final CRTP type
derived from `~mp::NLFeeder`.
@param: *ExprType* is a type storing expressions from
methods such as `~mp::NLFeeder::FeedExpr`. If not used,
Expand Down Expand Up @@ -458,11 +459,11 @@ class NLFeeder {
///////////////////// 12. INITIAL GUESSES /////////////////////
/** Initial primal guesses.
*
* Implementation:
* Implementation: write all meaningfuls entries (incl. zeros.)
* if (ini_guess.size()) {
* auto ig = igw.MakeVectorWriter(ini_guess.size());
* for (size_t i=0; i<ini_guess.size(); ++i)
* ig.Write(i, ini_guess[i]);
* ig.Write(ini_guess[i].index_, ini_guess[i].value_);
* }
*/
template <class IGWriter>
Expand All @@ -479,7 +480,7 @@ class NLFeeder {
* For constraints, assume ordering:
* first algebraic, then logical.
*
* Implementation:
* Implementation: write all non-0 entries (0 is the default.)
* while (....) {
* auto sw = swf.StartIntSuffix( // or ...DblSuffix
* suf_name, kind, n_nonzeros);
Expand Down
125 changes: 104 additions & 21 deletions nl-writer2/include/mp/nl-model.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,77 @@

namespace mp {


/// NL suffix type
struct NLSuffix {
/// Construct
NLSuffix(std::string name, int kind, std::vector<double> v={})
: name_(std::move(name)), table_({}), kind_(kind),
values_(std::move(v)) { }
/// Construct
NLSuffix(std::string name, std::string table, int kind,
std::vector<double> v={})
: name_(std::move(name)), table_(std::move(table)),
kind_(kind), values_(std::move(v)) { }

/// Name
std::string name_{};
/// Suffix table
std::string table_{};
/// Kind.
///
/// VAR = 0, /**< Applies to variables. */
/// CON = 1, /**< Applies to constraints. */
/// OBJ = 2, /**< Applies to objectives. */
/// PROBLEM = 3 /**< Applies to problems. */
///
/// If the suffix should be delivered as real-valued,
/// the kind_ should be bitwise-OR'ed with 0x4.
int kind_{-1};
/// Values. Always double precision. Dense vector.
std::vector<double> values_ {};

/// operator<
bool operator<(const NLSuffix& s) const {
return std::make_pair(name_, kind_)
< std::make_pair(s.name_, s.kind_);
}
};

/// NL suffix set.
class NLSuffixSet : private std::set<NLSuffix> {
protected:
using Base = std::set<NLSuffix>;
public:
/// Add suffix.
/// @return true iff new suffix (not existed before.)
bool Add(NLSuffix suf)
{ return this->insert(suf).second; }

/// Find suffix.
/// @return NLSuffix*, nullptr if not found.
const NLSuffix* Find(const std::string& nm, int k) const {
NLSuffix tmp {nm, {}, k};
auto it = this->find(tmp);
return (this->end()!=it) ? &*it : nullptr;
}

/// Expose size, empty
using Base::size;
using Base::empty;

/// Expose begin, end
using Base::begin;
using Base::end;
using Base::rbegin;
using Base::rend;
using Base::cbegin;
using Base::cend;
using Base::crbegin;
using Base::crend;
};

/// Declare
class NLUtils;

/// Class NLModel.
Expand Down Expand Up @@ -103,6 +174,27 @@ class NLModel {
/// loading the model into NLSolver.
void SetObjName(const char* nm) { obj_name_=(nm ? nm : ""); }

/// Set initial solution.
///
/// @note All pointers should stay valid until
/// loading the model into NLSolver.
void SetWarmstart(NLW2_SparseVector_C ini_x)
{ ini_x_ = ini_x; }

/// Set dual initial solution.
///
/// @note All pointers should stay valid until
/// loading the model into NLSolver.
void SetDualWarmstart(NLW2_SparseVector_C ini_y)
{ ini_y_ = ini_y; }

/// Add suffix.
/// @return true iff new suffix added (vs replaced.)
/// @note SOS constraints can be modeled as suffixes
/// for some AMPL solvers.
bool AddSuffix(NLSuffix suf)
{ return suffixes_.Add(std::move(suf)); }

/// Information exported by WriteNL()
struct PreprocessData {
/// var permutation
Expand Down Expand Up @@ -163,6 +255,15 @@ class NLModel {
/// Obj name
const char* ObjName() const { return obj_name_; }

/// Warm start
NLW2_SparseVector_C Warmstart() const
{ return ini_x_; }
/// Dual warm start
NLW2_SparseVector_C DualWarmstart() const
{ return ini_y_; }
/// Suffixes
const NLSuffixSet Suffixes() const { return suffixes_; }

private:
const char* prob_name_ {"mp::NLModel"};
NLW2_ColData_C vars_ {};
Expand All @@ -178,31 +279,13 @@ class NLModel {
int Q_format_ {};
NLW2_SparseMatrix_C Q_ {};
const char* obj_name_ {"obj[1]"};
};


/// NL suffix type
struct NLSuffix {
/// Name
std::string name_;
/// Suffix table
std::string table_;
/// Kind
int kind_;
/// Values. Always double precision.
std::vector<double> values_;

/// operator<
bool operator<(const NLSuffix& s) const {
return std::make_pair(name_, kind_)
< std::make_pair(s.name_, s.kind_);
}
NLW2_SparseVector_C ini_y_ {}, ini_x_{};
NLSuffixSet suffixes_;
};

/// NL suffix set.
using NLSuffixSet = std::set<NLSuffix>;

/// Solution
/// Returned solution.
struct NLSolution {
/// Any result obtained from the solver?
operator bool() const { return solve_result_ > -2; }
Expand Down
10 changes: 10 additions & 0 deletions nl-writer2/include/mp/nl-solver-basics-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ typedef struct NLW2_SparseMatrix_C {
const double *value_;
} NLW2_SparseMatrix_C;

/// Sparse vector.
typedef struct NLW2_SparseVector_C {
/// Number of entries
int num_;
/// Entry index
const int* index_;
/// Entry value
const double* value_;
} NLW2_SparseVector_C;


/// Basic NL options for NLModel.
/// Prefer to create by NLW2_MakeNLOptionsBasic_Default().
Expand Down
4 changes: 2 additions & 2 deletions nl-writer2/include/mp/sol-handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ class SOLHandler {
* while (sr.Size()) {
* std::pair<int, int> val = sr.ReadNext();
* if (val.first<0 || val.first>=nmax) {
* sr.SetError(mp::SOL_Read_Bad_Suffix,
* sr.SetError(NLW2_SOLRead_Bad_Suffix,
* "bad suffix element index");
* return;
* }
* suf[val.first] = val.second;
* }
* if (mp::SOL_Read_OK == sr.ReadResult()) // Can check
* if (NLW2_SOLRead_OK == sr.ReadResult()) // Can check
* RegisterSuffix(kind, name, table, suf);
*/
template <class SuffixReader>
Expand Down
2 changes: 1 addition & 1 deletion nl-writer2/src/nl-solver-c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ static NLW2_Solution_C NLW2_WrapNLSOL_Solution_C

NLW2_Solution_C result;
{
auto& sol=sol_data.sol_;
const auto& sol=sol_data.sol_;
result.nbs_ = sol.nbs_;
result.nsuf_ = sol.suffixes_.size();
result.obj_val_ = sol.obj_val_;
Expand Down
Loading

0 comments on commit e3baad2

Please sign in to comment.