Skip to content

Commit

Permalink
Option cvt:names
Browse files Browse the repository at this point in the history
Whether to read or provide generic names

ModelManager: use NameProvider
  • Loading branch information
glebbelov committed Jun 15, 2023
1 parent c8d2dec commit c0f0217
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 21 deletions.
2 changes: 1 addition & 1 deletion doc/rst/components.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ it unless you need access to the full NL reader API, described below.
* `mp::NLHeader` stores problem information

* `mp::NameProvider` reads variable and constraint names
(see AMPL option ``auxfiles``),
(see AMPL options ``auxfiles``, ``(solver)_auxfiles``),
or provides generic names otherwise

* `mp::ReadError`, `mp::BinaryReadError`
Expand Down
52 changes: 48 additions & 4 deletions include/mp/model-mgr-with-pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class ModelManagerWithProblemBuilder :
if (after_header)
after_header(); // parse options
});
ReadVarNames(filename_no_ext + ".col");
ReadNames(filename_no_ext);

double read_time = GetTimeAndReset(start);
if (GetEnv().timing())
Expand All @@ -108,6 +108,7 @@ class ModelManagerWithProblemBuilder :
GetEnv().Print("NL model conversion time = {:.6f}s\n", cvt_time);
}

/// Read the NL file
void ReadNLFile(
const std::string& nl_filename,
std::function<void()> after_header) {
Expand All @@ -117,9 +118,27 @@ class ModelManagerWithProblemBuilder :
reader.Read(nl_filename, *nl_read_result_.handler_, 0);
}

void ReadVarNames(const std::string& filename) {
internal::NameReader nr;
nr.Read(filename, *nl_read_result_.handler_);
/// Read var / con / obj names.
/// The .row file has cons + objs.
void ReadNames(const std::string& namebase) {
if (WantNames()) {
NameProvider npv("_svar");
NameProvider npc("_scon");
if (WantNames()<=2) {
npv.ReadNames(namebase + ".col",
GetModel().num_vars());
npc.ReadNames(namebase + ".row",
GetModel().num_cons()
+ GetModel().num_objs());
}
if (WantNames()>=2
|| npv.number_read()+npc.number_read()) {
GetModel().SetVarNames(
npv.get_names(GetModel().num_vars()));
GetModel().SetConNames(
npv.get_names(GetModel().num_cons()));
}
}
}

/// Once NL header is read
Expand Down Expand Up @@ -229,8 +248,33 @@ class ModelManagerWithProblemBuilder :
}


protected:
/// Whether and what names
int WantNames() const { return options_.nNames_; }


private:
const mp::OptionValueInfo values_want_names_[4] = {
{ "0", "No names", 0},
{ "1", "Only provide names if at least one of "
".col / .row name files was written by AMPL "
"(AMPL options auxfiles, <solver>_auxfiles)", 1},
{ "2", "Read names from AMPL, but provide generic "
"names otherwise", 2},
{ "3", "Provide generic names.", 3}
};

struct Options {
int nNames_ = 1;
};
Options options_;

void InitOwnOptions() {
GetEnv().AddStoredOption("cvt:names names modelnames",
"Whether to read or generate variable / constraint / "
"objective names:\n"
"\n.. value-table::\n",
options_.nNames_, values_want_names_);
}


Expand Down
35 changes: 24 additions & 11 deletions include/mp/nl-reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2228,9 +2228,6 @@ class NLProblemBuilder {
/// Get builder
ProblemBuilder &builder() { return builder_; }

void OnName(fmt::StringRef name) {
builder_.AddVarName(name);
}
/// OnHeader event
void OnHeader(const NLHeader &h) {
builder_.SetInfo(h);
Expand Down Expand Up @@ -2623,18 +2620,34 @@ inline void ReadNLFile(fmt::CStringRef filename, Handler &handler, int flags) {
/// A variable or constraint name provider.
/// Caters for possible missing names.
class NameProvider {
private:
public:
/// Construct and read
NameProvider(fmt::CStringRef filename,
fmt::CStringRef gen_name,
std::size_t num_items);

/// Construct without reading (generic names can be provided)
NameProvider(fmt::CStringRef gen_name);

/// Read names
void ReadNames(fmt::CStringRef filename,
std::size_t num_items);

/// Number of names read from file
size_t number_read() const;

/// Returns the name of the item at specified index.
fmt::StringRef name(std::size_t index);

/// Return vector of names, length n.
/// If number_read() < n, generic names are filled.
std::vector<std::string> get_names(size_t n);

private:
std::vector<const char *> names_;
std::string gen_name_;
internal::NameReader reader_;
fmt::MemoryWriter writer_;

public:
NameProvider(fmt::CStringRef filename, fmt::CStringRef gen_name,
std::size_t num_items);

// Returns the name of the item at specified index.
fmt::StringRef name(std::size_t index);
};

} // namespace mp
Expand Down
30 changes: 26 additions & 4 deletions include/mp/problem.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,19 @@ class BasicProblem : public ExprFactory, public SuffixManager {
typedef internal::ExprTypes ExprTypes;

private:
/// Names
std::vector<std::string> var_names_;
std::vector<std::string> con_names_;
std::vector<std::string> obj_names_;

/// A variable.
struct Var {
double lb;
double ub;
Var(double lb, double ub) : lb(lb), ub(ub) { assert(lb<=ub); }
};
std::vector<Var> vars_;
std::vector<std::string> var_names_;

/// Packed variable type information.
/// is_var_int_[i] specifies whether variable i is integer.
std::vector<bool> is_var_int_;
Expand Down Expand Up @@ -477,6 +482,11 @@ class BasicProblem : public ExprFactory, public SuffixManager {
/** Returns the number of objectives. */
int num_objs() const { return static_cast<int>(linear_objs_.size()); }

/** Returns total number of constraints from the NL file. */
int num_cons() const {
return num_algebraic_cons() + num_logical_cons();
}

/** Returns the number of algebraic constraints. */
int num_algebraic_cons() const {
return static_cast<int>(algebraic_cons_.size());
Expand Down Expand Up @@ -623,9 +633,7 @@ class BasicProblem : public ExprFactory, public SuffixManager {
is_var_int_.push_back(type != var::CONTINUOUS);
return Variable(this, static_cast<int>(index));
}
void AddVarName(const std::string& name) {
var_names_.push_back(name);
}

void AddVars(int num_vars, var::Type type) {
MP_ASSERT(num_vars >= 0, "invalid size");
std::size_t new_size = val(SafeInt<int>(vars_.size()) + num_vars);
Expand Down Expand Up @@ -655,6 +663,20 @@ class BasicProblem : public ExprFactory, public SuffixManager {
return newVars;
}

/// Set name vectors
void SetVarNames(std::vector<std::string> names) {
assert((size_t)num_vars() == names.size());
var_names_ = names;
}
void SetConNames(std::vector<std::string> names) {
assert((size_t)num_cons() == names.size());
con_names_ = names;
}
void SetObjNames(std::vector<std::string> names) {
assert((size_t)num_objs() == names.size());
obj_names_ = names;
}

class LinearExprBuilder {
private:
LinearExpr *expr_;
Expand Down
26 changes: 25 additions & 1 deletion src/nl-reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,18 @@ class NameHandler {

} // namespace internal


mp::NameProvider::NameProvider(
fmt::CStringRef filename, fmt::CStringRef gen_name, std::size_t num_items)
: gen_name_(gen_name.c_str()) {
ReadNames(filename, num_items);
}

mp::NameProvider::NameProvider(fmt::CStringRef gen_name)
: gen_name_(gen_name.c_str()) { }

void mp::NameProvider::ReadNames(
fmt::CStringRef filename, std::size_t num_items) {
::internal::NameHandler handler(names_);
names_.reserve(num_items + 1);
try {
Expand All @@ -341,13 +350,28 @@ mp::NameProvider::NameProvider(
fmt::StringRef mp::NameProvider::name(std::size_t index) {
if (index + 1 < names_.size()) {
const char *name = names_[index];
return fmt::StringRef(name, names_[index + 1] - name - 1);
const auto* pos1past = names_[index + 1] - 1;
assert('\n' == *pos1past);
if ('\r' == *(pos1past-1)) // Windows
--pos1past;
return fmt::StringRef(name, pos1past - name);
}
writer_.clear();
writer_ << gen_name_ << '[' << (index + 1) << ']';
return fmt::StringRef(writer_.c_str(), writer_.size());
}

size_t mp::NameProvider::number_read() const {
return (names_.size() ? names_.size()-1 : 0);
}

std::vector<std::string> mp::NameProvider::get_names(size_t n) {
std::vector<std::string> result;
result.reserve(n);
for (size_t i=0; i<n; ++i)
result.push_back(name(i));
return result;
}

// Instantiate
template class mp::internal::TextReader<>;
Expand Down

1 comment on commit c0f0217

@glebbelov
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mapgccv using NameProvider to read names. Please check if the Windows issue with '\r' is handled correctly.

This goes towards #209.

Please sign in to comment.