1/*
2 * Domain.cpp
3 * @brief Domain restriction constraint
4 * @date Feb 13, 2012
5 * @author Frank Dellaert
6 */
7
8#include <gtsam/base/Testable.h>
9#include <gtsam/discrete/DecisionTreeFactor.h>
10#include <gtsam_unstable/discrete/Domain.h>
11
12#include <sstream>
13namespace gtsam {
14
15using namespace std;
16
17/* ************************************************************************* */
18void Domain::print(const string& s, const KeyFormatter& formatter) const {
19 cout << s << ": Domain on " << formatter(key()) << " (j=" << formatter(key())
20 << ") with values";
21 for (size_t v : values_) cout << " " << v;
22 cout << endl;
23}
24
25/* ************************************************************************* */
26string Domain::base1Str() const {
27 stringstream ss;
28 for (size_t v : values_) ss << v + 1;
29 return ss.str();
30}
31
32/* ************************************************************************* */
33double Domain::evaluate(const Assignment<Key>& values) const {
34 return contains(value: values.at(k: key()));
35}
36
37/* ************************************************************************* */
38DecisionTreeFactor Domain::toDecisionTreeFactor() const {
39 const DiscreteKeys keys{DiscreteKey(key(), cardinality_)};
40 vector<double> table;
41 for (size_t i1 = 0; i1 < cardinality_; ++i1) table.push_back(x: contains(value: i1));
42 DecisionTreeFactor converted(keys, table);
43 return converted;
44}
45
46/* ************************************************************************* */
47DecisionTreeFactor Domain::operator*(const DecisionTreeFactor& f) const {
48 // TODO: can we do this more efficiently?
49 return toDecisionTreeFactor() * f;
50}
51
52/* ************************************************************************* */
53bool Domain::ensureArcConsistency(Key j, Domains* domains) const {
54 if (j != key()) throw invalid_argument("Domain check on wrong domain");
55 Domain& D = domains->at(k: j);
56 for (size_t value : values_)
57 if (!D.contains(value)) throw runtime_error("Unsatisfiable");
58 D = *this;
59 return true;
60}
61
62/* ************************************************************************* */
63std::optional<Domain> Domain::checkAllDiff(const KeyVector keys,
64 const Domains& domains) const {
65 Key j = key();
66 // for all values in this domain
67 for (const size_t value : values_) {
68 // for all connected domains
69 for (const Key k : keys)
70 // if any domain contains the value we cannot make this domain singleton
71 if (k != j && domains.at(k: k).contains(value)) goto found;
72 // Otherwise: return a singleton:
73 return Domain(this->discreteKey(), value);
74 found:;
75 }
76 return {}; // we did not change it
77}
78
79/* ************************************************************************* */
80Constraint::shared_ptr Domain::partiallyApply(const DiscreteValues& values) const {
81 DiscreteValues::const_iterator it = values.find(x: key());
82 if (it != values.end() && !contains(value: it->second))
83 throw runtime_error("Domain::partiallyApply: unsatisfiable");
84 return std::make_shared<Domain>(args: *this);
85}
86
87/* ************************************************************************* */
88Constraint::shared_ptr Domain::partiallyApply(const Domains& domains) const {
89 const Domain& Dk = domains.at(k: key());
90 if (Dk.isSingleton() && !contains(value: *Dk.begin()))
91 throw runtime_error("Domain::partiallyApply: unsatisfiable");
92 return std::make_shared<Domain>(args: Dk);
93}
94
95/* ************************************************************************* */
96} // namespace gtsam
97