diff --git a/nl-writer2/examples/c/nlsol_ex_c_model.c b/nl-writer2/examples/c/nlsol_ex_c_model.c index 9ee51f567..7637ecbef 100644 --- a/nl-writer2/examples/c/nlsol_ex_c_model.c +++ b/nl-writer2/examples/c/nlsol_ex_c_model.c @@ -38,6 +38,17 @@ CAPIExample MakeCAPIExample_Linear_01(void) { static const SparseEntry obj_linpart[] = { {0, 13}, {1, 1.0} }; + static const double ini_x[] = {30.15, 15.11}; + static const double ini_y[] = {-10, -120}; + + static const SparseEntry suf_val[] = {{0, 5.3}}; + + static int n_suf = 1; + static const Suffix suf[] = { + {"zork", 1+4, // constraints, float-valued + 1, suf_val} + }; + /// Solution static double sol_dual[] = {NAN, NAN}; static double sol_primal[] = {NAN, NAN}; @@ -66,6 +77,12 @@ CAPIExample MakeCAPIExample_Linear_01(void) { .n_obj_nz = 2, .obj_name = "TotalSum", + .ini_x = ini_x, + .ini_y = ini_y, + + .n_suf = n_suf, + .suf = suf, + .binary_nl = 1, .sol_dual_ = sol_dual, @@ -98,5 +115,5 @@ void PrintSolution_C(CAPIExample* pex, const char* stub) { pex->var_name[i], pex->sol_primal_[i]); printf("\nObjno used: %d, solve_result_num: %d\n", - pex->objno_, pex->solve_code_); + pex->objno_+1, pex->solve_code_); } diff --git a/nl-writer2/examples/c/nlsol_ex_c_model.h b/nl-writer2/examples/c/nlsol_ex_c_model.h index ef92dc78e..ac22cfa37 100644 --- a/nl-writer2/examples/c/nlsol_ex_c_model.h +++ b/nl-writer2/examples/c/nlsol_ex_c_model.h @@ -26,12 +26,16 @@ subj to C3: 22*x + 14536*y <= 3e5; ## Initial guess -let x := 1.5; -let y := 0.11; +let x := 30.15; +let y := 15.11; + +## Dual initial guess +let C2 := -10; +let C3 := -120; ## A suffix suffix zork; -let C2.zork := 5; +let C2.zork := 5.3; * */ @@ -44,6 +48,15 @@ typedef struct SparseEntry { } SparseEntry; +/// Suffix +typedef struct Suffix { + const char* name_; + int kind_; + int n_val_; + const SparseEntry* values_; // store double's always +} Suffix; + + /// C API example data typedef struct CAPIExample { const int n_var; @@ -97,6 +110,15 @@ typedef struct CAPIExample { int n_obj_nz; const char* obj_name; + /// Primal initial guess (dense vector). + const double* ini_x; + /// Primal dual guess (dense vector). + const double* ini_y; + + /// Suffixes. + int n_suf; + const Suffix* suf; + /// Some technical stuff int binary_nl; diff --git a/nl-writer2/examples/c/nlsol_ex_c_nl.c b/nl-writer2/examples/c/nlsol_ex_c_nl.c index 1f84f7e3a..b1ab6dcc0 100644 --- a/nl-writer2/examples/c/nlsol_ex_c_nl.c +++ b/nl-writer2/examples/c/nlsol_ex_c_nl.c @@ -290,19 +290,45 @@ void FeedColumnSizes(void* p_user_data, void* p_api_data) { ///////////////////// 12. INITIAL GUESSES ///////////////////// - /** Initial primal guesses. - * + +int CountNNZ(const double* parray, int len) { + int result = 0; + for (int i=0; iini_x, pex->n_var); +} +void FeedInitialGuesses(void* p_user_data, void* p_api_data) { + CAPIExample* pex = (CAPIExample*)p_user_data; + WriteDenseAsSparse(pex->ini_x, pex->n_var, p_api_data); +} - /** Initial dual guesses. */ -// void FeedInitialDualGuesses(IDGWriter& ) { } +/// Initial dual guesses +int InitialDualGuessesNNZ(void* p_user_data) { + CAPIExample* pex = (CAPIExample*)p_user_data; + return CountNNZ(pex->ini_y, pex->n_con); +} +void FeedInitialDualGuesses( + void* p_user_data, void* p_api_data) { + CAPIExample* pex = (CAPIExample*)p_user_data; + WriteDenseAsSparse(pex->ini_y, pex->n_con, p_api_data); +} ///////////////////// 13. SUFFIXES ///////////////////// @@ -313,13 +339,25 @@ void FeedColumnSizes(void* p_user_data, void* p_api_data) { * * Implementation: * while (....) { - * auto sw = swf.StartIntSuffix( // or ...DblSuffix - * suf_name, kind, n_nonzeros); + * void* p_api_2 = NLW2_StartIntSuffix( // or ...DblSuffix + * p_api_data, suf_name, kind, n_nonzeros); * for (int i=0; in_suf; ++i_suf) { + const Suffix* ps = &pex->suf[i_suf]; + void* p_api_2 = NLW2_StartDblSuffix( + p_api_data, ps->name_, ps->kind_, ps->n_val_); + for (int i=0; in_val_; ++i) + NLW2_WriteSparseDblEntry(p_api_2, + ps->values_[i].index_, + ps->values_[i].value_); + } +} //////////////////// 14. ROW/COLUMN NAMES ETC ///////////////////// @@ -499,11 +537,10 @@ NLW2_NLFeeder2_C MakeNLFeeder2_C( * ig.Write(i, ini_guess[i]); * } */ - // void FeedInitialGuesses(IGWriter& ) { } - - /** Initial dual guesses. */ - // void FeedInitialDualGuesses(IDGWriter& ) { } - + result.InitialGuessesNNZ = InitialGuessesNNZ; + result.InitialDualGuessesNNZ = InitialDualGuessesNNZ; + result.FeedInitialGuesses = FeedInitialGuesses; + result.FeedInitialDualGuesses = FeedInitialDualGuesses; ///////////////////// 13. SUFFIXES ///////////////////// /** Feed suffixes. @@ -519,8 +556,7 @@ NLW2_NLFeeder2_C MakeNLFeeder2_C( * sw.Write(index[i], value[i]); * } */ - // void FeedSuffixes(SuffixWriterFactory& ) { } - + result.FeedSuffixes = FeedSuffixes; //////////////////// 14. ROW/COLUMN NAMES ETC ///////////////////// /** FeedRowAndObjNames: diff --git a/nl-writer2/examples/cpp/nlsol_ex_sol.h b/nl-writer2/examples/cpp/nlsol_ex_sol.h index d4be7c491..beb06b87b 100644 --- a/nl-writer2/examples/cpp/nlsol_ex_sol.h +++ b/nl-writer2/examples/cpp/nlsol_ex_sol.h @@ -184,7 +184,7 @@ void ExampleSOLHandler2::PrintSolution( printf("%.17g\t", x); printf("\nObjno used: %d, solve_result_num: %d\n", - Model().objno_, Model().solve_result_); + Model().objno_+1, Model().solve_result_); printf("\n%s\n", "Suffixes:"); for (auto suf: Model().suf_out_) { diff --git a/nl-writer2/include/api/c/nl-feeder2-c-impl.h b/nl-writer2/include/api/c/nl-feeder2-c-impl.h index a95657e30..9fed650bf 100644 --- a/nl-writer2/include/api/c/nl-feeder2-c-impl.h +++ b/nl-writer2/include/api/c/nl-feeder2-c-impl.h @@ -16,16 +16,16 @@ namespace mp { /// Implementation: -/// Wrap NLFeeder2_C into a C++ class, +/// Wrap NLW2_NLFeeder2_C into a C++ class, /// in order to interface it for NLWriter2 -class NLFeeder2_C_Impl - : public NLFeeder2 { +class NLW2_NLFeeder2_C_Impl + : public NLFeeder2 { public: /// typedef base class - using Base = NLFeeder2; + using Base = NLFeeder2; /// Construct - NLFeeder2_C_Impl(NLW2_NLFeeder2_C* pnlf2) + NLW2_NLFeeder2_C_Impl(NLW2_NLFeeder2_C* pnlf2) : nlf2_c_(*pnlf2) { } ///////////////////// 1. NL HEADER AND OPTIONS ///////////////// @@ -338,11 +338,11 @@ class NLFeeder2_C_Impl * } */ template - void FeedInitialGuesses(IGWriter& ) { } + void FeedInitialGuesses(IGWriter& ); /** Initial dual guesses. */ template - void FeedInitialDualGuesses(IDGWriter& ) { } + void FeedInitialDualGuesses(IDGWriter& ); ///////////////////// 13. SUFFIXES ///////////////////// @@ -360,7 +360,7 @@ class NLFeeder2_C_Impl * } */ template - void FeedSuffixes(SuffixWriterFactory& ) { } + void FeedSuffixes(SuffixWriterFactory& ); //////////////////// 14. ROW/COLUMN NAMES ETC ///////////////////// diff --git a/nl-writer2/include/api/c/nl-feeder2-c.h b/nl-writer2/include/api/c/nl-feeder2-c.h index 1f811fbba..f5e029b4a 100644 --- a/nl-writer2/include/api/c/nl-feeder2-c.h +++ b/nl-writer2/include/api/c/nl-feeder2-c.h @@ -16,7 +16,10 @@ extern "C" { /// Declare callbacks -/// Write sparse vector entry +/// Write sparse vector(int) entry +void NLW2_WriteSparseIntEntry( + void* p_api_data_, int index, int value); +/// Write sparse vector(double) entry void NLW2_WriteSparseDblEntry( void* p_api_data_, int index, double value); /// Write next variable's Lb, Ub @@ -86,6 +89,13 @@ typedef struct NLW2_AlgConRange_C { /// Callback: write next constraint's range void NLW2_WriteAlgConRange(void* , NLW2_AlgConRange_C*); +/// Callback: start int suffix +void* NLW2_StartIntSuffix(void* p_api_1, + const char* suf_name, int kind, int nnz); +/// Callback: start dbl suffix +void* NLW2_StartDblSuffix(void* p_api_1, + const char* suf_name, int kind, int nnz); + /** Wrap mp::NLFeeder2 for C API. @@ -419,16 +429,16 @@ typedef struct NLW2_NLFeeder2_C { /** Initial primal guesses. * * Implementation: - * if (ini_guess.size()) { - * auto ig = igw.MakeVectorWriter(ini_guess.size()); - * for (size_t i=0; i class VecReader; -/// Wrap SOLHandler2_C into a C++ class, +/// Wrap NLW2_SOLHandler2_C into a C++ class, /// in order to interface it for mp::SOLReader2 -class SOLHandler2_C_Impl +class NLW2_SOLHandler2_C_Impl : public SOLHandler2 { public: /// Construct - SOLHandler2_C_Impl(NLW2_SOLHandler2_C* psh2) + NLW2_SOLHandler2_C_Impl(NLW2_SOLHandler2_C* psh2) : solh2_c_(*psh2) { } /** The NLHeader used to write the NL file. */ diff --git a/nl-writer2/include/mp/nl-writer2.h b/nl-writer2/include/mp/nl-writer2.h index 4c6035e59..2612dc448 100644 --- a/nl-writer2/include/mp/nl-writer2.h +++ b/nl-writer2/include/mp/nl-writer2.h @@ -178,18 +178,39 @@ class NLWriter2 : template class SparseVectorWriter { public: + /// Construct + SparseVectorWriter() { } + /// Not construct(const&) + SparseVectorWriter(const SparseVectorWriter& ) = delete; + /// Construct(&&) + SparseVectorWriter(SparseVectorWriter&& other) { + SparseVectorWriter svw; + svw = std::move(other); + } /// Constructor SparseVectorWriter(NLWriter2& nlw, size_t n); /// Destructor ~SparseVectorWriter() { assert(0 == n_entries_); } + /// No operator=(const&) + SparseVectorWriter& operator=( + const SparseVectorWriter& vw) = delete; + /// operator=(&&) + SparseVectorWriter& operator=( + SparseVectorWriter&& other) { + if (this!=&other) { + std::swap(p_nlw_, other.p_nlw_); + std::swap(n_entries_, other.n_entries_); + } + return *this; + } /// Write next entry void Write(Index , Value ); /// Number of outstanding elements int NLeft() const { return n_entries_; } private: - NLWriter2& nlw_; - size_t n_entries_; + NLWriter2* p_nlw_ = nullptr; + size_t n_entries_ = 0; }; /// Typedef SparseDblVecWriter diff --git a/nl-writer2/include/mp/nl-writer2.hpp b/nl-writer2/include/mp/nl-writer2.hpp index 24879236a..7c05e1164 100644 --- a/nl-writer2/include/mp/nl-writer2.hpp +++ b/nl-writer2/include/mp/nl-writer2.hpp @@ -601,14 +601,14 @@ template template NLWriter2::SparseVectorWriter:: SparseVectorWriter(NLWriter2& nlw, size_t n) - : nlw_(nlw), n_entries_(n) { } + : p_nlw_(&nlw), n_entries_(n) { } template template void NLWriter2::SparseVectorWriter:: Write(Index i, Value v) { --n_entries_; - nlw_.WriteSparseEntry(nlw_.nm, i, v); + p_nlw_->WriteSparseEntry(p_nlw_->nm, i, v); } diff --git a/nl-writer2/src/c_api.cc b/nl-writer2/src/c_api.cc index eab750c6e..a9580b1ea 100644 --- a/nl-writer2/src/c_api.cc +++ b/nl-writer2/src/c_api.cc @@ -29,6 +29,13 @@ extern "C" { ///////////////////////// NLFeeder_C /////////////////////////// /// Sparse vector writers + +void NLW2_WriteSparseIntEntry( + void* svw, int index, int value) { + auto& f = *(std::function*)(svw); + f(index, value); +} + void NLW2_WriteSparseDblEntry( void* svw, int index, double value) { auto& f = *(std::function*)(svw); @@ -53,6 +60,24 @@ void NLW2_WriteColSize(void* csw, int sz) { } +typedef struct NLW2_SuffixWriter_C { + std::function int_suf_starter_; + std::function dbl_suf_starter_; +} NLW2_SuffixWriter_C; + +void* NLW2_StartIntSuffix(void* swf, + const char* suf_name, int kind, int nnz) { + auto& f = *(NLW2_SuffixWriter_C*)(swf); + return f.int_suf_starter_(suf_name, kind, nnz); +} +void* NLW2_StartDblSuffix(void* swf, + const char* suf_name, int kind, int nnz) { + auto& f = *(NLW2_SuffixWriter_C*)(swf); + return f.dbl_suf_starter_(suf_name, kind, nnz); +} + /// Default implementations static const char* NLW2_ObjDescription_C_Default(void* , int ) { return ""; } @@ -187,10 +212,11 @@ static void NLW2_FeedColumnSizes_C_Default(void* , void* ) * ig.Write(i, ini_guess[i]); * } */ -// void FeedInitialGuesses(IGWriter& ) { } +static int NLW2_InitialGuessesNNZ_C_Default(void* ) { return 0; } +static void NLW2_FeedInitialGuesses_C_Default(void*, void* ) { } /** Initial dual guesses. */ -// void FeedInitialDualGuesses(IDGWriter& ) { } +static void NLW2_FeedInitialDualGuesses_C_Default(void*, void* ) { } ///////////////////// 13. SUFFIXES ///////////////////// @@ -207,7 +233,7 @@ static void NLW2_FeedColumnSizes_C_Default(void* , void* ) * sw.Write(index[i], value[i]); * } */ -// void FeedSuffixes(SuffixWriterFactory& ) { } +static void NLW2_FeedSuffixes_C_Default(void*, void* ) { } //////////////////// 14. ROW/COLUMN NAMES ETC ///////////////////// @@ -382,11 +408,10 @@ NLW2_NLFeeder2_C NLW2_MakeNLFeeder2_C_Default(void) { * ig.Write(i, ini_guess[i]); * } */ - // void FeedInitialGuesses(IGWriter& ) { } - - /** Initial dual guesses. */ - // void FeedInitialDualGuesses(IDGWriter& ) { } - + result.InitialGuessesNNZ + = result.InitialDualGuessesNNZ = NLW2_InitialGuessesNNZ_C_Default; + result.FeedInitialGuesses = NLW2_FeedInitialGuesses_C_Default; + result.FeedInitialDualGuesses = NLW2_FeedInitialDualGuesses_C_Default; ///////////////////// 13. SUFFIXES ///////////////////// /** Feed suffixes. @@ -402,7 +427,7 @@ NLW2_NLFeeder2_C NLW2_MakeNLFeeder2_C_Default(void) { * sw.Write(index[i], value[i]); * } */ - // void FeedSuffixes(SuffixWriterFactory& ) { } + result.FeedSuffixes = NLW2_FeedSuffixes_C_Default; //////////////////// 14. ROW/COLUMN NAMES ETC ///////////////////// @@ -563,8 +588,8 @@ namespace mp { /// Typedef our specialization of NLSOL using NLSOL_C_Impl - = mp::NLSOL; + = mp::NLSOL; } // namespace mp @@ -575,13 +600,13 @@ NLW2_NLSOL_C NLW2_MakeNLSOL_C( NLW2_NLFeeder2_C* pnlf, NLW2_SOLHandler2_C* psolh, NLW2_NLUtils_C* putl) { NLW2_NLSOL_C result; - result.p_nlf_ = new mp::NLFeeder2_C_Impl(pnlf); - result.p_solh_ = new mp::SOLHandler2_C_Impl(psolh); + result.p_nlf_ = new mp::NLW2_NLFeeder2_C_Impl(pnlf); + result.p_solh_ = new mp::NLW2_SOLHandler2_C_Impl(psolh); result.p_utl_ = new mp::NLUtils_C_Impl(putl); result.p_nlsol_ = new mp::NLSOL_C_Impl( - *(mp::NLFeeder2_C_Impl*)result.p_nlf_, - *(mp::SOLHandler2_C_Impl*)result.p_solh_, + *(mp::NLW2_NLFeeder2_C_Impl*)result.p_nlf_, + *(mp::NLW2_SOLHandler2_C_Impl*)result.p_solh_, *(mp::NLUtils_C_Impl*)result.p_utl_); return result; @@ -590,8 +615,8 @@ NLW2_NLSOL_C NLW2_MakeNLSOL_C( /// Destroy void NLW2_DestroyNLSOL_C(NLW2_NLSOL_C* pnls) { delete (mp::NLUtils_C_Impl*)(pnls->p_utl_); - delete (mp::SOLHandler2_C_Impl*)(pnls->p_solh_); - delete (mp::NLFeeder2_C_Impl*)(pnls->p_nlf_); + delete (mp::NLW2_SOLHandler2_C_Impl*)(pnls->p_solh_); + delete (mp::NLW2_NLFeeder2_C_Impl*)(pnls->p_nlf_); delete (mp::NLSOL_C_Impl*)(pnls->p_nlsol_); } @@ -647,3 +672,62 @@ int NLW2_ReadSolution(NLW2_NLSOL_C* pnls, const char* filename) { #ifdef __cplusplus } // extern "C" #endif + + +///////////////////////// C++ code ////////////////////////////// + +template +void mp::NLW2_NLFeeder2_C_Impl::FeedInitialGuesses(IGWriter& igw) { + assert(NLF().InitialGuessesNNZ); + if (int nnz = NLF().InitialGuessesNNZ(NLF().p_user_data_)) { + assert(NLF().FeedInitialGuesses); + auto ig = igw.MakeVectorWriter(nnz); + std::function wrt + = [&ig](int i, double v){ + ig.Write(i, v); + }; + NLF().FeedInitialGuesses(NLF().p_user_data_, &wrt); + } +} + +/** Initial dual guesses. */ +template +void mp::NLW2_NLFeeder2_C_Impl::FeedInitialDualGuesses(IGWriter& igw) { + assert(NLF().InitialDualGuessesNNZ); + if (int nnz = NLF().InitialDualGuessesNNZ(NLF().p_user_data_)) { + assert(NLF().FeedInitialDualGuesses); + auto ig = igw.MakeVectorWriter(nnz); + std::function wrt + = [&ig](int i, double v){ + ig.Write(i, v); + }; + NLF().FeedInitialDualGuesses(NLF().p_user_data_, &wrt); + } +} + + + +template +void mp::NLW2_NLFeeder2_C_Impl::FeedSuffixes(SuffixWriterFactory& swf) { + NLW2_SuffixWriter_C sw_c; + decltype( swf.StartIntSuffix(nullptr, 0, 0) ) int_writer; + decltype( swf.StartDblSuffix(nullptr, 0, 0) ) dbl_writer; + // These would write sparse entries + std::function int_write_fn + = [&int_writer](int i, int v) { int_writer.Write(i, v); }; + std::function dbl_write_fn + = [&dbl_writer](int i, double v) { dbl_writer.Write(i, v); }; + // There would start a suffix + sw_c.int_suf_starter_ = [&swf, &int_writer, &int_write_fn] + (const char* suf_name, int kind, int nnz) { + int_writer = swf.StartIntSuffix(suf_name, kind, nnz); + return (void*)(&int_write_fn); + }; + sw_c.dbl_suf_starter_ = [&swf, &dbl_writer, &dbl_write_fn] + (const char* suf_name, int kind, int nnz) { + dbl_writer = swf.StartDblSuffix(suf_name, kind, nnz); + return (void*)(&dbl_write_fn); + }; + assert(NLF().FeedSuffixes); + NLF().FeedSuffixes(NLF().p_user_data_, &sw_c); +}