Skip to content

Commit

Permalink
Fix handling of nsol
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Oct 6, 2014
1 parent 32aee7a commit 7b2d7cb
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 105 deletions.
98 changes: 1 addition & 97 deletions include/mp/problem-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,106 +31,10 @@

#include "mp/error.h"
#include "mp/problem-base.h"
#include "mp/suffix.h"

namespace mp {

class Suffix {
private:
std::string name_;
int kind_;
std::vector<int> values_;

public:
explicit Suffix(const std::string &name, int kind = 0, std::size_t size = 0)
: name_(name), kind_(kind), values_(size) {}

const char *name() const { return name_.c_str(); }

int kind() const { return kind_; }

void Swap(Suffix &other) {
name_.swap(other.name_);
values_.swap(other.values_);
}

int value(std::size_t index) const {
assert(index <= values_.size());
return values_[index];
}
void set_value(std::size_t index, int value) {
assert(index <= values_.size());
values_[index] = value;
}

// Iterates over nonzero suffix values and sends them to the visitor.
template <typename Visitor>
void VisitValues(Visitor &visitor) const {
for (std::size_t i = 0, n = values_.size(); i < n; ++i) {
int value = values_[i];
if (value != 0)
visitor.Visit(i, value);
}
}
};

class SuffixSet {
private:
int kind_;

struct SuffixLess {
bool operator()(const Suffix &lhs, const Suffix &rhs) const {
return std::strcmp(lhs.name(), rhs.name()) < 0;
}
};

typedef std::set<Suffix, SuffixLess> Set;
Set set_;

public:
explicit SuffixSet(int kind = 0) : kind_(kind) {
assert(0 <= kind && kind <= suf::NUM_KINDS);
}

// Finds a suffix with specified name.
Suffix *Find(const char *name) {
Set::iterator i = set_.find(Suffix(name));
return const_cast<Suffix*>(i != set_.end() ? &*i : 0);
}
const Suffix *Find(const char *name) const {
Set::const_iterator i = set_.find(Suffix(name));
return i != set_.end() ? &*i : 0;
}

Suffix &Add(const char *name, std::size_t num_values) {
Suffix &suffix = const_cast<Suffix&>(*set_.insert(Suffix(name)).first);
Suffix(name, kind_, num_values).Swap(suffix);
return suffix;
}

typedef Set::const_iterator iterator;

iterator begin() const { return set_.begin(); }
iterator end() const { return set_.end(); }
};

class SuffixManager {
private:
SuffixSet suffixes_[suf::NUM_KINDS];

public:
SuffixManager() {
for (int kind = 0; kind < suf::NUM_KINDS; ++kind)
suffixes_[kind] = SuffixSet(kind);
}

SuffixSet &get(int kind) {
assert(kind < suf::NUM_KINDS);
return suffixes_[kind];
}
};

// TODO: test suffixes

// A minimal implementation of the ProblemBuilder concept.
template <typename Impl, typename ExprT>
class ProblemBuilder {
Expand Down
8 changes: 5 additions & 3 deletions include/mp/solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "mp/nl.h"
#include "mp/option.h"
#include "mp/sol.h"
#include "mp/suffix.h"

namespace mp {

Expand Down Expand Up @@ -958,11 +959,12 @@ template <typename Solver, typename Writer>
void SolutionWriter<Solver, Writer>::HandleSolution(
fmt::StringRef message, const double *values,
const double *dual_values, double) {
typedef typename ProblemBuilder::SuffixPtr SuffixPtr;
SuffixData<SuffixPtr> data;
if (solver_.need_multiple_solutions()) {
typedef typename ProblemBuilder::SuffixPtr SuffixPtr;
SuffixPtr nsol_suffix = builder_.suffixes(suf::PROBLEM).Find("nsol");
if (nsol_suffix)
nsol_suffix->set_value(0, num_solutions_);
data.Attach(nsol_suffix, 1);
data.set_value(0, num_solutions_);
}
// TODO: pass to WriteSol
//option_info.bsname = const_cast<char*>(solver_.long_name());
Expand Down
166 changes: 166 additions & 0 deletions include/mp/suffix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
AMPL suffix support
Suffixes are values associated with model components.
See http://www.ampl.com/NEW/suffixes.html
Copyright (C) 2014 AMPL Optimization Inc
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that the copyright notice and this permission notice and warranty
disclaimer appear in supporting documentation.
The author and AMPL Optimization Inc disclaim all warranties with
regard to this software, including all implied warranties of
merchantability and fitness. In no event shall the author be liable
for any special, indirect or consequential damages or any damages
whatsoever resulting from loss of use , data or profits, whether in an
action of contract, negligence or other tortious action, arising out
of or in connection with the use or performance of this software.
Author: Victor Zverovich
*/

#ifndef MP_SUFFIX_H_
#define MP_SUFFIX_H_

namespace mp {

template <typename SuffixPtr>
class SuffixData;

class Suffix {
private:
std::string name_;
int kind_;
int *values_;
std::size_t size_;

friend class SuffixData<Suffix*>;

void set_data(int *values, std::size_t size) {
size_ = size;
values_ = values;
}

public:
explicit Suffix(const std::string &name, int kind = 0)
: name_(name), kind_(kind), values_(0), size_(0) {}

const char *name() const { return name_.c_str(); }

int kind() const { return kind_; }

int value(std::size_t index) const {
assert(index <= size_);
return values_[index];
}

// Iterates over nonzero suffix values and sends them to the visitor.
template <typename Visitor>
void VisitValues(Visitor &visitor) const {
for (std::size_t i = 0; i < size_; ++i) {
int value = values_[i];
if (value != 0)
visitor.Visit(i, value);
}
}
};

// Suffix data.
// For compatibility with ASL, suffix data is stored separately.
// This class is used to control the lifetime of the data and
// automatically detach it from the suffix once it is destroyed.
template <typename SuffixPtr>
class SuffixData {
private:
SuffixPtr suffix_;
std::vector<int> values_;

FMT_DISALLOW_COPY_AND_ASSIGN(SuffixData);

public:
SuffixData() : suffix_() {}
~SuffixData() {
if (suffix_)
suffix_->set_data(0, 0);
}

// Attaches data to a suffix.
void Attach(SuffixPtr suffix, std::size_t num_values) {
suffix_ = suffix;
values_.resize(num_values);
suffix->set_data(&values_[0], values_.size());
}

int value(std::size_t index) const {
assert(index <= values_.size());
return values_[index];
}

void set_value(std::size_t index, int value) {
assert(index <= values_.size());
values_[index] = value;
}
};

class SuffixSet {
private:
int kind_;

struct SuffixLess {
bool operator()(const Suffix &lhs, const Suffix &rhs) const {
return std::strcmp(lhs.name(), rhs.name()) < 0;
}
};

typedef std::set<Suffix, SuffixLess> Set;
Set set_;

public:
explicit SuffixSet(int kind = 0) : kind_(kind) {
assert(0 <= kind && kind <= suf::NUM_KINDS);
}

// Finds a suffix with specified name.
Suffix *Find(const char *name) {
Set::iterator i = set_.find(Suffix(name));
return const_cast<Suffix*>(i != set_.end() ? &*i : 0);
}
const Suffix *Find(const char *name) const {
Set::const_iterator i = set_.find(Suffix(name));
return i != set_.end() ? &*i : 0;
}

Suffix &Add(const char *name) {
return const_cast<Suffix&>(*set_.insert(Suffix(name, kind_)).first);
}

typedef Set::const_iterator iterator;

iterator begin() const { return set_.begin(); }
iterator end() const { return set_.end(); }
};

class SuffixManager {
private:
SuffixSet suffixes_[suf::NUM_KINDS];

public:
SuffixManager() {
for (int kind = 0; kind < suf::NUM_KINDS; ++kind)
suffixes_[kind] = SuffixSet(kind);
}

SuffixSet &get(int kind) {
assert(kind < suf::NUM_KINDS);
return suffixes_[kind];
}
};

// TODO: test suffixes

} // namespace mp

#endif // MP_SUFFIX_H_
9 changes: 9 additions & 0 deletions src/asl/problem.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@

namespace mp {

template <typename SuffixPtr>
class SuffixData;

namespace internal {
class ASLBuilder;
}
Expand Down Expand Up @@ -120,6 +123,12 @@ class ASLSuffixPtr {

Proxy(ASL *asl, SufDesc *p) : asl_(asl), ptr_(p) {}

friend class mp::SuffixData<ASLSuffixPtr>;

void set_data(int *values, std::size_t) {
ptr_->u.i = values;
}

public:
const char *name() const { return ptr_->sufname; }
int kind() const { return ptr_->kind; }
Expand Down
11 changes: 6 additions & 5 deletions test/solver-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1227,7 +1227,7 @@ TEST(SolutionWriterTest, CountSolutions) {
int nsol = 5;
for (int i = 0; i < nsol; ++i)
writer.HandleFeasibleSolution("", 0, 0, 0);
problem_builder.suffixes(mp::suf::PROBLEM).Add("nsol", 1);
problem_builder.suffixes(mp::suf::PROBLEM).Add("nsol");
EXPECT_CALL(writer.sol_writer(), Write(_, MatchNSol(nsol)));
writer.HandleSolution("", 0, 0, 0);
}
Expand All @@ -1249,7 +1249,7 @@ TEST(SolutionWriterTest, WriteFeasibleSolutions) {
EXPECT_CALL(sol_writer, Write(StringRefEq(filename), _));
writer.HandleFeasibleSolution("", 0, 0, 0);
}
problem_builder.suffixes(mp::suf::PROBLEM).Add("nsol", 1);
problem_builder.suffixes(mp::suf::PROBLEM).Add("nsol");
EXPECT_CALL(sol_writer, Write(_, MatchNSol(nsol)));
writer.HandleSolution("", 0, 0, 0);
}
Expand Down Expand Up @@ -1348,7 +1348,7 @@ TEST_F(SolverAppTest, ParseOptionsBeforeReadingProblem) {
EXPECT_EQ(0, app_.Run(Args("test", "-w", "testproblem")));
}

// Matcher that checks if the argument of type ProblemBuilderToNLAdapter
// Matcher that return true if the argument of type ProblemBuilderToNLAdapter
// points to the solver's problem builder.
MATCHER_P(MatchAdapterToBuilder, solver, "") {
return &arg.builder() == solver->GetProblemBuilder("");
Expand Down Expand Up @@ -1402,7 +1402,8 @@ TEST_F(SolverAppTest, ReportInputTime) {
EXPECT_THAT(output(), testing::MatchesRegex("timing=1\nInput time = .+s\n"));
}

// Matcher that checks if the argument points to the solver's problem builder.
// Matcher that returns true if the argument points to the solver's problem
// builder.
MATCHER_P(MatchBuilder, solver, "") {
return &arg == solver->GetProblemBuilder("");
}
Expand All @@ -1416,7 +1417,7 @@ TEST_F(SolverAppTest, Solve) {
EXPECT_EQ(0, app_.Run(Args("test", "testproblem")));
}

// Matcher that checks if the argument is a solution writer.
// Matcher that returns true if the argument is a solution writer.
MATCHER(MatchSolutionWriter, "") {
return dynamic_cast<mp::SolutionWriter<TestSolver>*>(&arg) != 0;
}
Expand Down

0 comments on commit 7b2d7cb

Please sign in to comment.