Conversation
| #pragma once | ||
| #include "dwave-optimization/cp/core/index_transform.hpp" | ||
| #include "dwave-optimization/cp/core/propagator.hpp" | ||
| namespace dwave::optimization::cp { |
There was a problem hiding this comment.
Minor but I would prefer constraint_propagation or similar as a "top-level" name instead of cp. Abbreviating it on less public interfaces or within methods is fine.
There was a problem hiding this comment.
to be precise you mean
namespace dwave::optimization::constraint_propagation {?
There was a problem hiding this comment.
Yes. I could be convinced otherwise though!
| #include "dwave-optimization/cp/core/propagator.hpp" | ||
| namespace dwave::optimization::cp { | ||
|
|
||
| /// Utility class to help schedule propagators when variable change their domains |
There was a problem hiding this comment.
| /// Utility class to help schedule propagators when variable change their domains | |
| /// Utility class to help schedule propagators when variables change their domains |
| /// - map variable index to propagator | ||
| class Advisor { | ||
| public: | ||
| Advisor(Propagator* p, ssize_t p_input, std::unique_ptr<IndexTransform> index_transform); |
There was a problem hiding this comment.
p_input is the topological index of a node?
There was a problem hiding this comment.
Actually it seems like it is not used?
There was a problem hiding this comment.
Good catch. I added it in case some propagators need to know which variable triggered the propagator. p_input is which input of that propagator the variable is. I'd wait a bit more to remove it for now, just in case I need it soon.
There was a problem hiding this comment.
Re-explaining this to make sure I get it: each propagator is associated with two or more variables (i.e. CPVars). When the propagator is called, it wants to be efficient in terms of which of its "output" indices need to be re-evaluated (e.g. shrinking bounds of an output index, if it's a bound consistency propagator). This is the role of the Advisor: each propagator adds an Advisor to each of its associated variables, and that Advisor owns an IndexTransform which translates indices of the associated variable to change output indices.
However, it also seems reasonable that a propagator may want to know not just which of its output indices needs to be re-evaluated, but also which of the associated variables that change came from. So you are allowing for that info to be passed through here.
Now correct where I went wrong 😆
There was a problem hiding this comment.
I missed this comment but you are correct!
| ssize_t num_propagators() const { return propagators_.size(); } | ||
|
|
||
| protected: | ||
| bool locked_ = false; |
There was a problem hiding this comment.
Seems like locked_ is never set by anything? Am I missing a lock() method somewhere?
There was a problem hiding this comment.
good catch again, haven't worked on that yet.
And sorry for my work being somewhat nonlinear, I add stuff that I think I need but I don't complete until later..
There was a problem hiding this comment.
No worries. Is the idea here to lock the CP model after parsing the dwopt model, and then we can be sure that the model is not modified during the run?
There was a problem hiding this comment.
yes, that's right!
| virtual ~CPVar() = default; | ||
|
|
||
| // constructor | ||
| CPVar(const CPModel& model, const dwave::optimization::ArrayNode* node_ptr, int index); |
There was a problem hiding this comment.
This index is the topological index of the node_ptr, correct? Why not just derive it from the node_ptr directly in the implementation?
|
|
||
| ssize_t max_size, min_size; | ||
|
|
||
| if (node_->size() > 0) { |
There was a problem hiding this comment.
| if (node_->size() > 0) { | |
| if (not node_->dynamic()) { |
You also want to handle size 0 arrays here, right?
There was a problem hiding this comment.
Yeah good catch!
| assert(this->cp_var_index_ >= 0); | ||
| assert(static_cast<ssize_t>(state.var_state_.size()) > cp_var_index_); | ||
|
|
||
| // TODO: for now we don't handle dynamically sized nodes |
There was a problem hiding this comment.
Seems like this does handle dynamic arrays now, as long as they have bounds on size
There was a problem hiding this comment.
oh yeah, obsolete comment!
| throw std::invalid_argument("Array has no max size available"); | ||
| } | ||
|
|
||
| if (not sizeinfo.min.has_value()) { |
There was a problem hiding this comment.
It should be safe to substitute zero in here, though that may not be desirable
There was a problem hiding this comment.
Good point, I want to check again how sizeinfo works and I'll likely follow your suggestion
|
|
||
| if (node_->size() > 0) { | ||
| // Static array | ||
| max_size = node_->size(); |
There was a problem hiding this comment.
You could use sizeinfo.min/max for these and simplify the logic I think
| namespace dwave::optimization::cp { | ||
| class DomainListener { | ||
| public: | ||
| virtual ~DomainListener() = default; |
There was a problem hiding this comment.
I think if you're defining a virtual destructor like this, you should also declare the copy and move constructors to follow the rule of three, probably as = delete to prevent object slicing.
The plan is to have other types of listeners (other than CPVar::listener) at some point right?
There was a problem hiding this comment.
The point is that if there are other variables types (other than CPVar) then I may need other types of listeners. But to decouple domains from variables, the domains respond to this interface to trigger propagators.
Anyways, yes I need to follow the rule of three! I'll add that!
| /// Return the minimum size of the array | ||
| virtual ssize_t min_size() const = 0; | ||
|
|
||
| /// Return the minimum size of the array |
| IntervalArray(StateManager* sm, ssize_t min_size, ssize_t max_size, double lb, double up); | ||
| IntervalArray(StateManager* sm, ssize_t size, double lb, double up); |
There was a problem hiding this comment.
I think you mean double ub here?
| // Change double do an object that can be backtracked. | ||
| // And maybe get |
There was a problem hiding this comment.
| // Change double do an object that can be backtracked. | |
| // And maybe get |
Looks like an old TODO that has been addressed?
| /// Return the size of the domain of the index-th variable | ||
| virtual double size(int index) const = 0; |
There was a problem hiding this comment.
I might prefer to call this "width" (consistent with the width of a real-valued interval) so that the term "size" is not overloaded so much
There was a problem hiding this comment.
hmm, though if we support sparse set domains, something like "cardinality" might be better, though that would not be accurate for a real-valued interval
Add basic binary ops and reduce
Basic structure for integrating domains and filtering routines.