From 092236ba312b0975cac19566e3bb7af01218b444 Mon Sep 17 00:00:00 2001 From: Alexander Condello Date: Wed, 17 Jun 2026 11:46:35 -0700 Subject: [PATCH 1/5] Refactor graph.hpp and graph.cpp (no functional changes) --- .../include/dwave-optimization/graph.hpp | 284 +++++++----- dwave/optimization/src/graph.cpp | 425 +++++++++--------- 2 files changed, 376 insertions(+), 333 deletions(-) diff --git a/dwave/optimization/include/dwave-optimization/graph.hpp b/dwave/optimization/include/dwave-optimization/graph.hpp index 7b2720b2..9f3e0341 100644 --- a/dwave/optimization/include/dwave-optimization/graph.hpp +++ b/dwave/optimization/include/dwave-optimization/graph.hpp @@ -55,123 +55,143 @@ class Graph { Graph(Graph&&) noexcept = default; Graph& operator=(Graph&&) noexcept = default; + /// Add a constraint node. + void add_constraint(ArrayNode* constraint_ptr); + + /// Call commit on every `Node` in the `Graph`. + void commit(State& state) const; + + /// Commit the changes on each changed node. + void commit(State& state, std::span changed) const; + void commit(State& state, std::vector&& changed) const; + + /// Return the constraints of the graph as a span of nodes. + std::span constraints() noexcept { return constraints_; } + std::span constraints() const noexcept { return constraints_; } + + /// Retrieve all of the decisions in the model + std::span decisions() noexcept { return decisions_; } + std::span decisions() const noexcept { return decisions_; } + + /// Get the descendants of the source nodes, that is, all nodes that can be visited starting + /// from the sources. + static std::vector descendants(State& state, std::vector sources); + std::vector descendants(std::vector sources) const; + + /// Add a new node to the graph. template NodeType* emplace_node(Args&&... args); - State initialize_state() const; - State initialize_state(); // topologically sorts first - void initialize_state(State& state) const; - void initialize_state(State& state); // topologically sorts first + /// Create a new "empty" state, that is a state with no nodes initialized. + /// The `const` version will fail if the model is not topologically sorted, + /// the non-`const` version will topologically sort the model. State empty_state() const; - State empty_state(); // topologically sorts first + State empty_state(); - // Initialize the state of the given node and all predecessors recursively. - static void recursive_initialize(State& state, const Node* ptr); - // Reset the state of the given node and all successors recursively. - static void recursive_reset(State& state, const Node* ptr); + /// Calculate the current energy of the model, that is the output of the + /// objective node. + double energy(const State& state) const; - // Sort the nodes topologically. This "locks" the model in that nodes cannot - // be added to a topologically sorted model without invalidating the topological - // ordering. - void topological_sort(); + /// Return `true` if the graph is feasible. A graph is feasible if all constraints + /// output `true`. + bool feasible(const State& state) const; - // Reset the topological sort. Note that the decision variables will still - // have a topological ordering. - void reset_topological_sort(); + /// Create a new state with all nodes initialized by their default initializer. + /// The `const` version will fail if the model is not topologically sorted, + /// the non-`const` version will topologically sort the model. + State initialize_state() const; + State initialize_state(); - // Whether or not the model is currently topologically sorted. - // Models that are topologically sorted cannot be modified. - bool topologically_sorted() const noexcept { return topologically_sorted_; } + /// Given a state, initialize any nodes that have not already been initialized. + /// The `const` version will fail if the model is not topologically sorted, + /// the non-`const` version will topologically sort the model. + void initialize_state(State& state) const; + void initialize_state(State& state); + /// Return a span over all of the input nodes in the model. + std::span inputs() noexcept { return inputs_; } + std::span inputs() const noexcept { return inputs_; } + + /// All of the nodes in the graph. std::span> nodes() const { return nodes_; } - // Given the source (changing) nodes, update the model incrementally and accept the changes - // according to the accept function. - void propose( - State& state, - std::vector sources, - std::function accept = [](const Graph&, State&) { return true; } - ) const; + /// The number of decision nodes. + ssize_t num_decisions() const noexcept { return decisions_.size(); } - // Get the descendants of the source nodes, that is, all nodes that can be visited starting from - // the sources. - static std::vector descendants(State& state, std::vector sources); - std::vector descendants(std::vector sources) const; + /// The number of nodes in the model. + ssize_t num_nodes() const noexcept { return nodes_.size(); } + + /// The number of constraints in the model. + ssize_t num_constraints() const noexcept { return constraints_.size(); } + + /// The number of input nodes in the model. + ssize_t num_inputs() const noexcept { return inputs_.size(); } + + /// Return a pointer to the node that is the objective of the model. + /// Will return nullptr if there is no objective set. + ArrayNode* objective() noexcept { return objective_ptr_; } + const ArrayNode* objective() const noexcept { return objective_ptr_; } /// Call propagate on every `Node` in the `Graph`. void propagate(State& state) const; - // Call the propagate method on each node in changed. Note this does not call propagate on - // the descendents of changed. + /// Call the propagate method on each node in changed. Note this does not call propagate on + /// the descendents of changed. void propagate(State& state, std::span changed) const; void propagate(State& state, std::vector&& changed) const; - /// Call commit on every `Node` in the `Graph`. - void commit(State& state) const; + /// Given the source (changing) nodes, update the model incrementally and accept the changes + /// according to the accept function. + void propose( + State& state, + std::vector sources, + std::function accept = [](const Graph&, State&) { return true; } + ) const; - // Commit the changes on each changed node. - void commit(State& state, std::span changed) const; - void commit(State& state, std::vector&& changed) const; + /// Initialize the state of the given node and all predecessors recursively. + static void recursive_initialize(State& state, const Node* ptr); + /// Reset the state of the given node and all successors recursively. + static void recursive_reset(State& state, const Node* ptr); + + /// Remove unused nodes from the graph. + /// + /// This method will reset the topological sort if there is one. + /// + /// A node is considered unused if all of the following are true: + /// * It is not a decision. + /// * It is not an ancestor of the objective. + /// * It is not an ancestor of a constraint. + /// * It has no "listeners" on its expired_ptr. Set ``ignore_listeners`` to + /// ``true`` to disable this condition. + /// + /// Returns the number of nodes removed from the graph. + ssize_t remove_unused_nodes(bool ignore_listeners = false); /// Call revert on every `Node` in the `Graph`. void revert(State& state) const; - // Revert the changes on each changed node. + /// Revert the changes on each changed node. void revert(State& state, std::span changed) const; void revert(State& state, std::vector&& changed) const; - // The number of decision nodes. - ssize_t num_decisions() const noexcept { return decisions_.size(); } - - // The number of nodes in the model. - ssize_t num_nodes() const noexcept { return nodes_.size(); } - - // The number of constraints in the model. - ssize_t num_constraints() const noexcept { return constraints_.size(); } - - // The number of input nodes in the model. - ssize_t num_inputs() const noexcept { return inputs_.size(); } + /// Reset the topological sort. Note that the decision variables will still + /// have a topological ordering. + void reset_topological_sort(); - // Specify the objective node. Must be an array with a single element. - // To unset the objective provide nullptr. + /// Specify the objective node. Must be an array with a single element. + /// To unset the objective provide nullptr. void set_objective(ArrayNode* objective_ptr); - // Will return nullptr if there is no objective set. - ArrayNode* objective() noexcept { return objective_ptr_; } - const ArrayNode* objective() const noexcept { return objective_ptr_; } - - // Add a constraint node. - void add_constraint(ArrayNode* constraint_ptr); - std::span constraints() noexcept { return constraints_; } - std::span constraints() const noexcept { return constraints_; } - - double energy(const State& state) const; - bool feasible(const State& state) const; - - // Retrieve all of the decisions in the model - std::span decisions() noexcept { return decisions_; } - std::span decisions() const noexcept { return decisions_; } - - std::span inputs() noexcept { return inputs_; } - std::span inputs() const noexcept { return inputs_; } + /// Sort the nodes topologically. This "locks" the model in that nodes cannot + /// be added to a topologically sorted model without invalidating the topological + /// ordering. + void topological_sort(); - // Remove unused nodes from the graph. - // - // This method will reset the topological sort if there is one. - // - // A node is considered unused if all of the following are true: - // * It is not a decision. - // * It is not an ancestor of the objective. - // * It is not an ancestor of a constraint. - // * It has no "listeners" on its expired_ptr. Set ``ignore_listeners`` to - // ``true`` to disable this condition. - // - // Returns the number of nodes removed from the graph. - ssize_t remove_unused_nodes(bool ignore_listeners = false); + // Whether or not the model is currently topologically sorted. + // Models that are topologically sorted cannot be modified. + bool topologically_sorted() const noexcept { return topologically_sorted_; } private: - static void visit_(Node* n_ptr, int* count_ptr); - std::vector> nodes_; // The nodes with important semantic meanings to the model. @@ -188,6 +208,16 @@ class Graph { class Node { public: struct SuccessorView { + // Cannot construct a SuccessorView without a Node/index + SuccessorView() = delete; + ~SuccessorView() = default; + + // Move/copy work normally + SuccessorView(const SuccessorView&) = default; + SuccessorView(SuccessorView&&) = default; + SuccessorView& operator=(const SuccessorView&) = default; + SuccessorView& operator=(SuccessorView&&) = default; + SuccessorView(Node* ptr, int index) noexcept : ptr(ptr), index(index) {} // Can dereference just like a pointer @@ -208,44 +238,71 @@ class Node { Node() noexcept : expired_ptr_(new bool(false)) {} virtual ~Node() { *expired_ptr_ = true; } - const std::vector& predecessors() const { return predecessors_; } - const std::vector& successors() const { return successors_; } + // Nodes cannot be moved or copied. + Node(const Node&) = delete; + Node(Node&&) noexcept = delete; + Node& operator=(const Node&) = delete; + Node& operator=(Node&&) noexcept = delete; - virtual void initialize_state(State& state) const; + /// Methods for interrogating nodes as strings. Useful for error messages + /// and debugging. We roughly follow Python's scheme of repr() and str() + /// printing different information. + virtual std::string classname() const; + + /// Commit any changing updates to the node. + virtual void commit(State& state) const = 0; /// Return true if the node's state is deterministic - that is it's uniquely /// derived from its predecessors. Defaults to `true`, except for decisions. virtual bool deterministic_state() const { return true; } - // The current topological index. Will be negative if unsorted. - ssize_t topological_index() const { return topological_index_; } + /// Return a shared pointer to a bool value. When the node is destructed + /// the bool will be set to True + std::shared_ptr expired_ptr() const { return expired_ptr_; } + + /// Initialize the state of the node. + virtual void initialize_state(State& state) const; - // Incorporate any update(s) from predecessor nodes and then call the update() - // method of any successors. - // Note that calling update() on successors must happen *AFTER* the state - // has been updated. - // By default, this method calls the update() method of all succesors. - // Subclasses will in general want to update their state and/or filter - // the list of successors that need to be updated. + /// Return predecessors of the node. + const std::vector& predecessors() const { return predecessors_; } + + /// Incorporate any update(s) from predecessor nodes and then call the update() + /// method of any successors. + /// Note that calling update() on successors must happen *AFTER* the state + /// has been updated. + /// By default, this method calls the update() method of all succesors. + /// Subclasses will in general want to update their state and/or filter + /// the list of successors that need to be updated. virtual void propagate(State& state) const { for (const auto& sv : successors()) { sv->update(state, sv.index); } } - virtual void commit(State& state) const = 0; + /// @copydoc Node::classname() + virtual std::string repr() const; + + /// Revert any pending changes to the node. virtual void revert(State& state) const = 0; - // Called by predecessor nodes to signal that they have changes that need - // to be incorporated into this node's state. - // By default this method does nothing. - // Subclasses will in general want to track which predececessors have been - // updated and may even want to eagerly incorporate changes. + /// @copydoc Node::classname() + virtual std::string str() const; + + /// Return the successors of the node. + const std::vector& successors() const { return successors_; } + + /// The current topological index. Will be negative if unsorted. + ssize_t topological_index() const { return topological_index_; } + + /// Called by predecessor nodes to signal that they have changes that need + /// to be incorporated into this node's state. + /// By default this method does nothing. + /// Subclasses will in general want to track which predececessors have been + /// updated and may even want to eagerly incorporate changes. virtual void update(State& state, int index) const {} - // Return a shared pointer to a bool value. When the node is destructed - // the bool will be set to True - std::shared_ptr expired_ptr() const { return expired_ptr_; } + /// Nodes are printable + friend std::ostream& operator<<(std::ostream& os, const Node& node); friend void Graph::topological_sort(); friend void Graph::reset_topological_sort(); @@ -253,15 +310,6 @@ class Node { friend NodeType* Graph::emplace_node(Args&&... args); friend ssize_t Graph::remove_unused_nodes(bool ignore_listeners); - // Methods for interrogating nodes as strings. Useful for error messages - // and debugging. We roughly follow Python's scheme of repr() and str() - // printing different information. - virtual std::string classname() const; - virtual std::string repr() const; - virtual std::string str() const; - - friend std::ostream& operator<<(std::ostream& os, const Node& node); - protected: // For use by non-dynamic node constructors. Node(std::initializer_list nodes) noexcept : @@ -326,7 +374,7 @@ class Node { ssize_t topological_index_ = -1; // negative is unset std::vector predecessors_; - std::vector successors_; // todo: successor view + std::vector successors_; // Used to signal whether the node is expired to observers. Should be set // to true when the Node is deallocated. @@ -368,12 +416,12 @@ class DecisionNode : public Decision, public virtual Node { /// Decision nodes by definition do not have a deterministic state. bool deterministic_state() const final { return false; } - // Decisions don't have predecessors so no one should be calling update(). - // Always throws a logic_error. + /// Decisions don't have predecessors so no one should be calling update(). + /// Always throws a logic_error. [[noreturn]] void update(State& state, int index) const override; protected: - // In general we do not allow decisions to be removed from models. + /// In general we do not allow decisions to be removed from models. bool removable() const override { return false; } }; diff --git a/dwave/optimization/src/graph.cpp b/dwave/optimization/src/graph.cpp index 446cff65..551a3a5a 100644 --- a/dwave/optimization/src/graph.cpp +++ b/dwave/optimization/src/graph.cpp @@ -30,162 +30,6 @@ namespace dwave::optimization { -// Graph ********************************************************************** - -void Graph::topological_sort() { - if (topologically_sorted_) return; - - // The decisions already have their topological index assigned - - // Find a topological ordering of all of the non-decisions - // The extra `visit` parameter is to allow for recursive lambdas - // We iterate over successors in reverse order to preserve their original ordering - // after sorting based on the topological index (which is counting down during DFS). - auto visit = [](Node* n_ptr, int* count_ptr, auto&& visit) -> void { - if (n_ptr->topological_index_ >= 0) return; - if (n_ptr->topological_index_ == -2) throw std::logic_error("has cycles"); - - // decisions should already be sorted - assert(dynamic_cast(n_ptr) == nullptr && "unsorted decisions node"); - - n_ptr->topological_index_ = -2; - - for (Node* m_ptr : n_ptr->successors() | std::views::reverse) { - visit(m_ptr, count_ptr, visit); - } - - n_ptr->topological_index_ = *count_ptr; - *count_ptr -= 1; - }; - - int count = num_nodes() - 1; - for (const std::unique_ptr& node_ptr : nodes_ | std::views::reverse) { - // todo: iterative version - visit(node_ptr.get(), &count, visit); - } - - // Check that we have no gaps in our range. - // Because the decisions were already sorted, that should determine the - // count after assigning all others - assert(count == num_decisions() - 1); - - // for later convenience, we sort the nodes_ by index - // This moves all of the decisions to the front - std::sort( - nodes_.begin(), - nodes_.end(), - [](const std::unique_ptr& n_ptr, const std::unique_ptr& m_ptr) { - return n_ptr->topological_index_ < m_ptr->topological_index_; - } - ); - - topologically_sorted_ = true; -} - -void Graph::reset_topological_sort() { - if (!topologically_sorted_) return; // already unsorted - - // The decisions must have a consistent topological index, so we don't reset them - std::for_each( - // std::execution::par_unseq, // todo: performance testing. Probably won't help - nodes_.begin() + num_decisions(), - nodes_.end(), - [](const std::unique_ptr& n_ptr) { - assert(dynamic_cast(n_ptr.get()) == nullptr); // not a decision - n_ptr->topological_index_ = -1; - } - ); - - topologically_sorted_ = false; -} - -State Graph::initialize_state() const { - auto state = empty_state(); - initialize_state(state); - return state; -} - -State Graph::initialize_state() { - topological_sort(); - return static_cast(this)->initialize_state(); -} - -void Graph::initialize_state(State& state) const { - assert(static_cast(state.size()) == num_nodes() && "unexpected state length"); - assert(topologically_sorted_ && "graph must be topologically sorted"); - - for (int i = 0, end = num_nodes(); i < end; ++i) { - if (state[i]) continue; // should this clear any pending changes? - - nodes_[i]->initialize_state(state); - } -} - -void Graph::recursive_initialize(State& state, const Node* ptr) { - ssize_t index = ptr->topological_index(); - - if (index < 0) { - throw std::logic_error("cannot initialize a node that has not been topologically sorted"); - } - - // make sure that the state is large enough - if (index >= static_cast(state.size())) { - state.resize(index + 1); - } - - if (state[index]) return; // it's been created already - - // otherwise, make sure all predecessors are initialized - for (const dwave::optimization::Node* pred_ptr : ptr->predecessors()) { - recursive_initialize(state, pred_ptr); - } - - ptr->initialize_state(state); -} - -void Graph::recursive_reset(State& state, const Node* ptr) { - ssize_t index = ptr->topological_index(); - - if (index < 0) { - throw std::logic_error("cannot reset a node that has not been topologically sorted"); - } - - // In the case that we're past the end of the state, we're by definition reset! - if (index >= static_cast(state.size())) { - return; - } - - // We've already been reset so nothing to do - if (!state[index]) return; - - // Otherwise, reset our own state and then all of our successors - state[index].reset(); - - for (const dwave::optimization::Node* successor_ptr : ptr->successors()) { - if (successor_ptr->topological_index() < 0) continue; // nothing to reset - recursive_reset(state, successor_ptr); - } -} - -void Graph::initialize_state(State& state) { - topological_sort(); - static_cast(this)->initialize_state(state); -} - -State Graph::empty_state() const { return State(num_nodes()); } -State Graph::empty_state() { - topological_sort(); - return static_cast(this)->empty_state(); -} - -void Graph::set_objective(ArrayNode* objective_ptr) { - // nullptr is an unset objective, so we allow it. - if (objective_ptr != nullptr && objective_ptr->size() != 1) { - throw std::invalid_argument("objective must have a single output"); - } - this->objective_ptr_ = objective_ptr; -} - void Graph::add_constraint(ArrayNode* constraint_ptr) { if (!constraint_ptr->logical()) { throw std::invalid_argument("constraint must have a logical output"); @@ -201,16 +45,29 @@ void Graph::add_constraint(ArrayNode* constraint_ptr) { constraints_.emplace_back(constraint_ptr); } -double Graph::energy(const State& state) const { - if (objective_ptr_ == nullptr) return 0; - return objective_ptr_->view(state).front(); +void Graph::commit(State& state) const { + std::ranges::for_each(nodes(), [&state](const auto& ptr) { ptr->commit(state); }); } -bool Graph::feasible(const State& state) const { - for (const Array* ptr : constraints_) { - assert(ptr->size(state) == 1); - if (!(ptr->view(state)[0])) return false; - } - return true; + +void Graph::commit(State& state, std::span changed) const { + std::for_each( + // std::execution::par_unseq, // todo: test performance. Might help! + changed.begin(), + changed.end(), + [&state](const Node* n_ptr) { n_ptr->commit(state); } + ); + + assert(([&state, &changed]() -> bool { + for (const Node* n_ptr : changed) { + if (dynamic_cast(n_ptr) == nullptr) continue; + if (!dynamic_cast(n_ptr)->diff(state).empty()) return false; + } + return true; + })()); +} + +void Graph::commit(State& state, std::vector&& changed) const { + commit(state, std::span(changed)); } // Performs Breadth First Search and sort the nodes visited according to their topological number. @@ -251,72 +108,68 @@ std::vector Graph::descendants(std::vector sources) co return descendants(state, sources); } -void Graph::propagate(State& state) const { - std::ranges::for_each(nodes(), [&state](const auto& ptr) { ptr->propagate(state); }); -} +State Graph::empty_state() const { return State(num_nodes()); } -void Graph::propagate(State& state, std::span queue_to_update) const { - for (const Node* node_ptr : queue_to_update) { - node_ptr->propagate(state); +State Graph::empty_state() { + topological_sort(); + return static_cast(this)->empty_state(); +} - // Note: commented because we split the methods. - // We might incur in a small performance degradation. - // state[node_ptr->topological_index()]->mark = false; +double Graph::energy(const State& state) const { + if (objective_ptr_ == nullptr) return 0; + return objective_ptr_->view(state).front(); +} +bool Graph::feasible(const State& state) const { + for (const Array* ptr : constraints_) { + assert(ptr->size(state) == 1); + if (!(ptr->view(state)[0])) return false; } + return true; } -void Graph::propagate(State& state, std::vector&& changed) const { - return propagate(state, std::span(changed)); +State Graph::initialize_state() const { + auto state = empty_state(); + initialize_state(state); + return state; } -void Graph::commit(State& state) const { - std::ranges::for_each(nodes(), [&state](const auto& ptr) { ptr->commit(state); }); +State Graph::initialize_state() { + topological_sort(); + return static_cast(this)->initialize_state(); } -void Graph::commit(State& state, std::span changed) const { - std::for_each( - // std::execution::par_unseq, // todo: test performance. Might help! - changed.begin(), - changed.end(), - [&state](const Node* n_ptr) { n_ptr->commit(state); } - ); +void Graph::initialize_state(State& state) const { + assert(static_cast(state.size()) == num_nodes() && "unexpected state length"); + assert(topologically_sorted_ && "graph must be topologically sorted"); - assert(([&state, &changed]() -> bool { - for (const Node* n_ptr : changed) { - if (dynamic_cast(n_ptr) == nullptr) continue; - if (!dynamic_cast(n_ptr)->diff(state).empty()) return false; - } - return true; - })()); + for (int i = 0, end = num_nodes(); i < end; ++i) { + if (state[i]) continue; // should this clear any pending changes? + + nodes_[i]->initialize_state(state); + } } -void Graph::commit(State& state, std::vector&& changed) const { - commit(state, std::span(changed)); +void Graph::initialize_state(State& state) { + topological_sort(); + static_cast(this)->initialize_state(state); } -void Graph::revert(State& state) const { - std::ranges::for_each(nodes(), [&state](const auto& ptr) { ptr->revert(state); }); +void Graph::propagate(State& state) const { + std::ranges::for_each(nodes(), [&state](const auto& ptr) { ptr->propagate(state); }); } -void Graph::revert(State& state, std::span changed) const { - std::for_each( - // std::execution::par_unseq, // todo: test performance. Might help! - changed.begin(), - changed.end(), - [&state](const Node* n_ptr) { n_ptr->revert(state); } - ); +void Graph::propagate(State& state, std::span queue_to_update) const { + for (const Node* node_ptr : queue_to_update) { + node_ptr->propagate(state); - assert(([&state, &changed]() -> bool { - for (const Node* n_ptr : changed) { - if (dynamic_cast(n_ptr) == nullptr) continue; - if (!dynamic_cast(n_ptr)->diff(state).empty()) return false; - } - return true; - })()); + // Note: commented because we split the methods. + // We might incur in a small performance degradation. + // state[node_ptr->topological_index()]->mark = false; + } } -void Graph::revert(State& state, std::vector&& changed) const { - revert(state, std::span(changed)); +void Graph::propagate(State& state, std::vector&& changed) const { + return propagate(state, std::span(changed)); } // Note: we pass the vector of changed nodes by value as we expect it to be rather small. Revisit if @@ -340,6 +193,52 @@ void Graph::propose( } } +void Graph::recursive_initialize(State& state, const Node* ptr) { + ssize_t index = ptr->topological_index(); + + if (index < 0) { + throw std::logic_error("cannot initialize a node that has not been topologically sorted"); + } + + // make sure that the state is large enough + if (index >= static_cast(state.size())) { + state.resize(index + 1); + } + + if (state[index]) return; // it's been created already + + // otherwise, make sure all predecessors are initialized + for (const dwave::optimization::Node* pred_ptr : ptr->predecessors()) { + recursive_initialize(state, pred_ptr); + } + + ptr->initialize_state(state); +} + +void Graph::recursive_reset(State& state, const Node* ptr) { + ssize_t index = ptr->topological_index(); + + if (index < 0) { + throw std::logic_error("cannot reset a node that has not been topologically sorted"); + } + + // In the case that we're past the end of the state, we're by definition reset! + if (index >= static_cast(state.size())) { + return; + } + + // We've already been reset so nothing to do + if (!state[index]) return; + + // Otherwise, reset our own state and then all of our successors + state[index].reset(); + + for (const dwave::optimization::Node* successor_ptr : ptr->successors()) { + if (successor_ptr->topological_index() < 0) continue; // nothing to reset + recursive_reset(state, successor_ptr); + } +} + ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { // Establish a topological ordering. We'll use the fact that the node list // is ordered, but we're going to mess with the topological indices! @@ -407,7 +306,105 @@ ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { return num_nodes_before - this->num_nodes(); } -// Node *********************************************************************** +void Graph::reset_topological_sort() { + if (!topologically_sorted_) return; // already unsorted + + // The decisions must have a consistent topological index, so we don't reset them + std::for_each( + // std::execution::par_unseq, // todo: performance testing. Probably won't help + nodes_.begin() + num_decisions(), + nodes_.end(), + [](const std::unique_ptr& n_ptr) { + assert(dynamic_cast(n_ptr.get()) == nullptr); // not a decision + n_ptr->topological_index_ = -1; + } + ); + + topologically_sorted_ = false; +} + +void Graph::revert(State& state) const { + std::ranges::for_each(nodes(), [&state](const auto& ptr) { ptr->revert(state); }); +} + +void Graph::revert(State& state, std::span changed) const { + std::for_each( + // std::execution::par_unseq, // todo: test performance. Might help! + changed.begin(), + changed.end(), + [&state](const Node* n_ptr) { n_ptr->revert(state); } + ); + + assert(([&state, &changed]() -> bool { + for (const Node* n_ptr : changed) { + if (dynamic_cast(n_ptr) == nullptr) continue; + if (!dynamic_cast(n_ptr)->diff(state).empty()) return false; + } + return true; + })()); +} + +void Graph::revert(State& state, std::vector&& changed) const { + revert(state, std::span(changed)); +} + +void Graph::set_objective(ArrayNode* objective_ptr) { + // nullptr is an unset objective, so we allow it. + if (objective_ptr != nullptr && objective_ptr->size() != 1) { + throw std::invalid_argument("objective must have a single output"); + } + this->objective_ptr_ = objective_ptr; +} + +void Graph::topological_sort() { + if (topologically_sorted_) return; + + // The decisions already have their topological index assigned + + // Find a topological ordering of all of the non-decisions + // The extra `visit` parameter is to allow for recursive lambdas + // We iterate over successors in reverse order to preserve their original ordering + // after sorting based on the topological index (which is counting down during DFS). + auto visit = [](Node* n_ptr, int* count_ptr, auto&& visit) -> void { + if (n_ptr->topological_index_ >= 0) return; + if (n_ptr->topological_index_ == -2) throw std::logic_error("has cycles"); + + // decisions should already be sorted + assert(dynamic_cast(n_ptr) == nullptr && "unsorted decisions node"); + + n_ptr->topological_index_ = -2; + + for (Node* m_ptr : n_ptr->successors() | std::views::reverse) { + visit(m_ptr, count_ptr, visit); + } + + n_ptr->topological_index_ = *count_ptr; + *count_ptr -= 1; + }; + + int count = num_nodes() - 1; + for (const std::unique_ptr& node_ptr : nodes_ | std::views::reverse) { + // todo: iterative version + visit(node_ptr.get(), &count, visit); + } + + // Check that we have no gaps in our range. + // Because the decisions were already sorted, that should determine the + // count after assigning all others + assert(count == num_decisions() - 1); + + // for later convenience, we sort the nodes_ by index + // This moves all of the decisions to the front + std::sort( + nodes_.begin(), + nodes_.end(), + [](const std::unique_ptr& n_ptr, const std::unique_ptr& m_ptr) { + return n_ptr->topological_index_ < m_ptr->topological_index_; + } + ); + + topologically_sorted_ = true; +} void Node::initialize_state(State& state) const { assert(topological_index_ >= 0 && "must be topologically sorted"); @@ -473,8 +470,6 @@ std::string Node::str() const { return classname(); } std::ostream& operator<<(std::ostream& os, const Node& node) { return os << node.repr(); } -// DecisionNode *************************************************************** - [[noreturn]] void DecisionNode::update(State& state, int index) const { throw std::logic_error("update() called on a decisison variable"); } From 78f9e2f8f72fcd1dd30fb952ddf3812ced999b16 Mon Sep 17 00:00:00 2001 From: Alexander Condello Date: Wed, 17 Jun 2026 11:51:51 -0700 Subject: [PATCH 2/5] Rename Graph protected members --- .../include/dwave-optimization/array.hpp | 12 +- .../include/dwave-optimization/graph.hpp | 14 +- .../dwave-optimization/nodes/collections.hpp | 4 +- dwave/optimization/src/graph.cpp | 2 +- dwave/optimization/src/nodes/binaryop.cpp | 18 +-- dwave/optimization/src/nodes/collections.cpp | 76 +++++----- dwave/optimization/src/nodes/creation.cpp | 42 +++--- dwave/optimization/src/nodes/flow.cpp | 48 +++--- dwave/optimization/src/nodes/indexing.cpp | 66 +++++---- dwave/optimization/src/nodes/inputs.cpp | 12 +- .../optimization/src/nodes/interpolation.cpp | 14 +- dwave/optimization/src/nodes/lambda.cpp | 16 +- .../optimization/src/nodes/linear_algebra.cpp | 24 +-- dwave/optimization/src/nodes/lp.cpp | 44 +++--- dwave/optimization/src/nodes/manipulation.cpp | 138 +++++++++--------- dwave/optimization/src/nodes/naryop.cpp | 14 +- dwave/optimization/src/nodes/numbers.cpp | 44 +++--- .../src/nodes/quadratic_model.cpp | 14 +- dwave/optimization/src/nodes/reduce.cpp | 22 +-- dwave/optimization/src/nodes/set_routines.cpp | 24 +-- dwave/optimization/src/nodes/softmax.cpp | 18 +-- dwave/optimization/src/nodes/sorting.cpp | 18 +-- dwave/optimization/src/nodes/statistics.cpp | 4 +- dwave/optimization/src/nodes/testing.cpp | 32 ++-- dwave/optimization/src/nodes/unaryop.cpp | 18 +-- ...ph-protected-members-717df2da46c2db7f.yaml | 5 + 26 files changed, 379 insertions(+), 364 deletions(-) create mode 100644 releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml diff --git a/dwave/optimization/include/dwave-optimization/array.hpp b/dwave/optimization/include/dwave-optimization/array.hpp index a4e6f7eb..7182b3af 100644 --- a/dwave/optimization/include/dwave-optimization/array.hpp +++ b/dwave/optimization/include/dwave-optimization/array.hpp @@ -654,22 +654,22 @@ class ScalarOutputMixin : public ScalarOutputMixin { /// @copydoc Array::buff() double const* buff(const State& state) const final { - return this->template data_ptr(state)->buff(); + return this->template data_ptr_(state)->buff(); } /// @copydoc Node::commit() void commit(State& state) const final { - this->template data_ptr(state)->commit(); + this->template data_ptr_(state)->commit(); } /// @copydoc Array::diff() std::span diff(const State& state) const final { - return this->template data_ptr(state)->diff(); + return this->template data_ptr_(state)->diff(); } /// @copydoc Node::revert() void revert(State& state) const final { - this->template data_ptr(state)->revert(); + this->template data_ptr_(state)->revert(); } protected: @@ -677,12 +677,12 @@ class ScalarOutputMixin : public ScalarOutputMixin { /// Emplace a state with the given scalar value. void emplace_state(State& state, double value) const { - this->template emplace_data_ptr(state, value); + this->template emplace_data_ptr_(state, value); } /// Update the state value with the given value void set_state(State& state, double value) const { - this->template data_ptr(state)->set(value); + this->template data_ptr_(state)->set(value); } }; diff --git a/dwave/optimization/include/dwave-optimization/graph.hpp b/dwave/optimization/include/dwave-optimization/graph.hpp index 9f3e0341..2fa0d1eb 100644 --- a/dwave/optimization/include/dwave-optimization/graph.hpp +++ b/dwave/optimization/include/dwave-optimization/graph.hpp @@ -322,7 +322,7 @@ class Node { } /// Add a predecessor node. Adds itself to the predecessor as a successor. - void add_predecessor(Node* predecessor) { + void add_predecessor_(Node* predecessor) { assert( this->topological_index_ <= 0 && "cannot add a predecessor to a topologically sorted node" @@ -332,14 +332,14 @@ class Node { } /// Add a successor node. Adds itself to the successor as a predecessor. - void add_successor(Node* successor) { + void add_successor_(Node* successor) { assert(successor->topological_index_ <= 0 && "cannot add a topologically sorted successor"); this->successors_.emplace_back(successor, successor->predecessors_.size()); successor->predecessors_.emplace_back(this); } template StateData> - StateData* data_ptr(State& state) const { + StateData* data_ptr_(State& state) const { const ssize_t index = topological_index(); assert(index >= 0 && "must be topologically sorted"); assert(state.size() > static_cast(index) && "unexpected state length"); @@ -348,7 +348,7 @@ class Node { return static_cast(state[index].get()); } template StateData> - const StateData* data_ptr(const State& state) const { + const StateData* data_ptr_(const State& state) const { const ssize_t index = topological_index(); assert(index >= 0 && "must be topologically sorted"); assert(state.size() > static_cast(index) && "unexpected state length"); @@ -358,7 +358,7 @@ class Node { } template StateData, class... Args> - void emplace_data_ptr(State& state, Args&&... args) const { + void emplace_data_ptr_(State& state, Args&&... args) const { const ssize_t index = topological_index(); assert(index >= 0 && "must be topologically sorted"); assert(state.size() > static_cast(index) && "unexpected state length"); @@ -368,7 +368,7 @@ class Node { } // Whether this node type is elegible to be removed from the model - virtual bool removable() const { return true; } + virtual bool removable_() const { return true; } private: ssize_t topological_index_ = -1; // negative is unset @@ -422,7 +422,7 @@ class DecisionNode : public Decision, public virtual Node { protected: /// In general we do not allow decisions to be removed from models. - bool removable() const override { return false; } + bool removable_() const override { return false; } }; } // namespace dwave::optimization diff --git a/dwave/optimization/include/dwave-optimization/nodes/collections.hpp b/dwave/optimization/include/dwave-optimization/nodes/collections.hpp index 5b28d011..48b20119 100644 --- a/dwave/optimization/include/dwave-optimization/nodes/collections.hpp +++ b/dwave/optimization/include/dwave-optimization/nodes/collections.hpp @@ -155,7 +155,7 @@ class DisjointBitSetNode : public ArrayOutputMixin { protected: // This node is a pseudo-decision, so it is not removeable - bool removable() const override { return false; } + bool removable_() const override { return false; } const DisjointBitSetsNode* disjoint_bit_sets_node_; const ssize_t set_index_; @@ -256,7 +256,7 @@ class DisjointListNode : public ArrayOutputMixin { protected: // This node is a pseudo-decision, so it is not removeable - bool removable() const override { return false; } + bool removable_() const override { return false; } const DisjointListsNode* disjoint_list_node_ptr_; const ssize_t list_index_; diff --git a/dwave/optimization/src/graph.cpp b/dwave/optimization/src/graph.cpp index 551a3a5a..89a194af 100644 --- a/dwave/optimization/src/graph.cpp +++ b/dwave/optimization/src/graph.cpp @@ -279,7 +279,7 @@ ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { // Now walk backwards through the topologically sorted node list // removing any nodes with no successors that we haven't marked. for (auto& ptr : nodes_ | std::views::drop(num_decisions) | std::views::reverse) { - if (!ptr->removable()) continue; // some nodes can never be removed + if (!ptr->removable_()) continue; // some nodes can never be removed if (ptr->topological_index_ == keep) continue; // we marked these to keep if (ptr->successors().size() > 0) continue; // this node is used by other nodes diff --git a/dwave/optimization/src/nodes/binaryop.cpp b/dwave/optimization/src/nodes/binaryop.cpp index 70084906..2241cc92 100644 --- a/dwave/optimization/src/nodes/binaryop.cpp +++ b/dwave/optimization/src/nodes/binaryop.cpp @@ -194,23 +194,23 @@ BinaryOpNode::BinaryOpNode(ArrayNode* a_ptr, ArrayNode* b_ptr) : calculate_integral(operands_[0], operands_[1]) ), sizeinfo_(binaryop_calculate_sizeinfo(this, operands_[0], operands_[1])) { - this->add_predecessor(a_ptr); - this->add_predecessor(b_ptr); + this->add_predecessor_(a_ptr); + this->add_predecessor_(b_ptr); } template double const* BinaryOpNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } template std::span BinaryOpNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } template void BinaryOpNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } template @@ -254,7 +254,7 @@ void BinaryOpNode::initialize_state(State& state) const { unreachable(); } - emplace_data_ptr(state, std::move(values)); + emplace_data_ptr_(state, std::move(values)); } template @@ -274,7 +274,7 @@ double BinaryOpNode::min() const { template void BinaryOpNode::propagate(State& state) const { - auto ptr = data_ptr(state); + auto ptr = data_ptr_(state); const Array* lhs_ptr = operands_[0]; const Array* rhs_ptr = operands_[1]; @@ -389,7 +389,7 @@ void BinaryOpNode::propagate(State& state) const { template void BinaryOpNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } template @@ -434,7 +434,7 @@ ssize_t BinaryOpNode::size(const State& state) const { template ssize_t BinaryOpNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo binaryop_calculate_sizeinfo( diff --git a/dwave/optimization/src/nodes/collections.cpp b/dwave/optimization/src/nodes/collections.cpp index 1a38942e..0ea4f805 100644 --- a/dwave/optimization/src/nodes/collections.cpp +++ b/dwave/optimization/src/nodes/collections.cpp @@ -239,33 +239,35 @@ void CollectionNode::assign(State& state, std::vector values) const { // Check that the values are a proper subset and fill out the invisible part auto augemented = augment_collection_(std::move(values), max_value_); - data_ptr(state)->assign(std::move(augemented), size); + data_ptr_(state)->assign(std::move(augemented), size); } -void CollectionNode::commit(State& state) const { data_ptr(state)->commit(); } +void CollectionNode::commit(State& state) const { + data_ptr_(state)->commit(); +} const double* CollectionNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } std::span CollectionNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void CollectionNode::exchange(State& state, ssize_t i, ssize_t j) const { if (i == j) return; - data_ptr(state)->exchange(i, j); // handles the asserts + data_ptr_(state)->exchange(i, j); // handles the asserts } void CollectionNode::rotate(State& state, ssize_t dest_idx, ssize_t src_idx) const { if (src_idx == dest_idx) return; - data_ptr(state)->rotate(dest_idx, src_idx); // handles the asserts + data_ptr_(state)->rotate(dest_idx, src_idx); // handles the asserts } void CollectionNode::grow(State& state) const { assert(this->dynamic()); - assert(data_ptr(state)->size() < max_size_); - data_ptr(state)->grow(); + assert(data_ptr_(state)->size() < max_size_); + data_ptr_(state)->grow(); } void CollectionNode::initialize_state(State& state, std::vector values) const { @@ -276,7 +278,7 @@ void CollectionNode::initialize_state(State& state, std::vector values) // Check that the values are a proper subset and fill out the invisible part auto augemented = augment_collection_(std::move(values), max_value_); - emplace_data_ptr(state, std::move(augemented), size); + emplace_data_ptr_(state, std::move(augemented), size); } bool CollectionNode::integral() const { return true; } @@ -288,28 +290,30 @@ double CollectionNode::max() const { return max_value_ - 1; } -void CollectionNode::revert(State& state) const { data_ptr(state)->revert(); } +void CollectionNode::revert(State& state) const { + data_ptr_(state)->revert(); +} std::span CollectionNode::shape(const State& state) const { if (not dynamic()) { assert(min_size_ == max_size_); return std::span(&min_size_, 1); } - return data_ptr(state)->shape(); + return data_ptr_(state)->shape(); } void CollectionNode::shrink(State& state) const { assert(dynamic()); assert(size(state) > min_size_); - data_ptr(state)->shrink(); + data_ptr_(state)->shrink(); } ssize_t CollectionNode::size(const State& state) const { if (ssize_t size = this->size(); size >= 0) { - assert(data_ptr(state)->size() == size); + assert(data_ptr_(state)->size() == size); return size; } - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } SizeInfo CollectionNode::sizeinfo() const { @@ -319,10 +323,10 @@ SizeInfo CollectionNode::sizeinfo() const { ssize_t CollectionNode::size_diff(const State& state) const { if (not dynamic()) { - assert(data_ptr(state)->size_diff() == 0); + assert(data_ptr_(state)->size_diff() == 0); return 0; } - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } struct DisjointBitSetsNodeData_ : NodeStateData { @@ -429,24 +433,24 @@ DisjointBitSetsNode::DisjointBitSetsNode(ssize_t primary_set_size, ssize_t num_d } void DisjointBitSetsNode::initialize_state(State& state) const { - emplace_data_ptr(state, primary_set_size_, num_disjoint_sets_); + emplace_data_ptr_(state, primary_set_size_, num_disjoint_sets_); } void DisjointBitSetsNode::initialize_state( State& state, const std::vector>& contents ) const { - emplace_data_ptr( + emplace_data_ptr_( state, primary_set_size_, num_disjoint_sets_, contents ); } void DisjointBitSetsNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } void DisjointBitSetsNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } void DisjointBitSetsNode::swap_between_sets( @@ -455,13 +459,13 @@ void DisjointBitSetsNode::swap_between_sets( ssize_t to_disjoint_set, ssize_t element ) const { - data_ptr(state)->swap_between_sets( + data_ptr_(state)->swap_between_sets( from_disjoint_set, to_disjoint_set, element ); } ssize_t DisjointBitSetsNode::get_containing_set_index(State& state, ssize_t element) const { - return data_ptr(state)->get_containing_set_index(element); + return data_ptr_(state)->get_containing_set_index(element); } DisjointBitSetNode::DisjointBitSetNode(DisjointBitSetsNode* disjoint_bit_sets_node) : @@ -472,7 +476,7 @@ DisjointBitSetNode::DisjointBitSetNode(DisjointBitSetsNode* disjoint_bit_sets_no if (set_index_ >= disjoint_bit_sets_node_->num_disjoint_sets()) { throw std::length_error("disjoint-bit-set node already has all output nodes"); } - add_predecessor(disjoint_bit_sets_node); + add_predecessor_(disjoint_bit_sets_node); } const double* DisjointBitSetNode::buff(const State& state) const { @@ -726,7 +730,7 @@ DisjointListsNode::DisjointListsNode(ssize_t primary_set_size, ssize_t num_disjo } void DisjointListsNode::initialize_state(State& state) const { - emplace_data_ptr( + emplace_data_ptr_( state, this->primary_set_size(), this->num_disjoint_lists() ); } @@ -735,22 +739,22 @@ void DisjointListsNode::initialize_state( State& state, std::vector> contents ) const { - emplace_data_ptr( + emplace_data_ptr_( state, this->primary_set_size(), this->num_disjoint_lists(), std::move(contents) ); } void DisjointListsNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } void DisjointListsNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } void DisjointListsNode::propagate(State& state) const { #ifndef NDEBUG - auto data = data_ptr(state); + auto data = data_ptr_(state); std::vector items(this->primary_set_size()); for (auto const& list : data->lists) { for (const auto& item : list) { @@ -770,7 +774,7 @@ void DisjointListsNode::propagate(State& state) const { } ssize_t DisjointListsNode::get_disjoint_list_size(State& state, ssize_t list_index) const { - auto data = data_ptr(state); + auto data = data_ptr_(state); auto size = data->lists[list_index].size(); return size; } @@ -782,7 +786,7 @@ void DisjointListsNode::rotate_in_list( ssize_t dest_idx ) const { if (src_idx == dest_idx) return; - data_ptr(state)->rotate_in_list(list_index, src_idx, dest_idx); + data_ptr_(state)->rotate_in_list(list_index, src_idx, dest_idx); } void DisjointListsNode::set_state( @@ -790,7 +794,7 @@ void DisjointListsNode::set_state( ssize_t list_index, const std::span& new_values ) const { - data_ptr(state)->set_state(list_index, new_values); + data_ptr_(state)->set_state(list_index, new_values); } void DisjointListsNode::swap_in_list( @@ -801,7 +805,7 @@ void DisjointListsNode::swap_in_list( ) const { if (element_i == element_j) return; - data_ptr(state)->swap_in_list(list_index, element_i, element_j); + data_ptr_(state)->swap_in_list(list_index, element_i, element_j); } void DisjointListsNode::pop_to_list( @@ -811,7 +815,7 @@ void DisjointListsNode::pop_to_list( ssize_t to_list_index, ssize_t element_j ) const { - data_ptr(state)->pop_to_list( + data_ptr_(state)->pop_to_list( from_list_index, element_i, to_list_index, element_j ); } @@ -825,7 +829,7 @@ DisjointListNode::DisjointListNode(DisjointListsNode* disjoint_list_node) : throw std::length_error("disjoint-list node already has all output nodes"); } - add_predecessor(disjoint_list_node); + add_predecessor_(disjoint_list_node); } const double* DisjointListNode::buff(const State& state) const { @@ -871,11 +875,11 @@ ssize_t DisjointListNode::size_diff(const State& state) const { } void ListNode::initialize_state(State& state) const { - emplace_data_ptr(state, max_value_, min_size_); + emplace_data_ptr_(state, max_value_, min_size_); } void SetNode::initialize_state(State& state) const { - emplace_data_ptr(state, max_value_, min_size_); + emplace_data_ptr_(state, max_value_, min_size_); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/creation.cpp b/dwave/optimization/src/nodes/creation.cpp index c6976204..31860722 100644 --- a/dwave/optimization/src/nodes/creation.cpp +++ b/dwave/optimization/src/nodes/creation.cpp @@ -282,7 +282,7 @@ ARangeNode::ARangeNode(ssize_t start, ssize_t stop, ArrayNode* step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(step); + add_predecessor_(step); } ARangeNode::ARangeNode(ssize_t start, ArrayNode* stop, ssize_t step) : ArrayOutputMixin(range_shape(start, stop, step)), @@ -291,7 +291,7 @@ ARangeNode::ARangeNode(ssize_t start, ArrayNode* stop, ssize_t step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(stop); + add_predecessor_(stop); } ARangeNode::ARangeNode(ssize_t start, ArrayNode* stop, ArrayNode* step) : ArrayOutputMixin(range_shape(start, stop, step)), @@ -300,8 +300,8 @@ ARangeNode::ARangeNode(ssize_t start, ArrayNode* stop, ArrayNode* step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(stop); - add_predecessor(step); + add_predecessor_(stop); + add_predecessor_(step); } ARangeNode::ARangeNode(ArrayNode* start, ssize_t stop, ssize_t step) : ArrayOutputMixin(range_shape(start, stop, step)), @@ -310,7 +310,7 @@ ARangeNode::ARangeNode(ArrayNode* start, ssize_t stop, ssize_t step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(start); + add_predecessor_(start); } ARangeNode::ARangeNode(ArrayNode* start, ssize_t stop, ArrayNode* step) : ArrayOutputMixin(range_shape(start, stop, step)), @@ -319,8 +319,8 @@ ARangeNode::ARangeNode(ArrayNode* start, ssize_t stop, ArrayNode* step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(start); - add_predecessor(step); + add_predecessor_(start); + add_predecessor_(step); } ARangeNode::ARangeNode(ArrayNode* start, ArrayNode* stop, ssize_t step) : ArrayOutputMixin(range_shape(start, stop, step)), @@ -329,8 +329,8 @@ ARangeNode::ARangeNode(ArrayNode* start, ArrayNode* stop, ssize_t step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(start); - add_predecessor(stop); + add_predecessor_(start); + add_predecessor_(stop); } ARangeNode::ARangeNode(ArrayNode* start, ArrayNode* stop, ArrayNode* step) : ArrayOutputMixin(range_shape(start, stop, step)), @@ -339,25 +339,25 @@ ARangeNode::ARangeNode(ArrayNode* start, ArrayNode* stop, ArrayNode* step) : step_(step), values_minmax_(calculate_values_minmax(start, stop, step)), sizeinfo_(calculate_arange_sizeinfo(this, start, stop, step)) { - add_predecessor(start); - add_predecessor(stop); - add_predecessor(step); + add_predecessor_(start); + add_predecessor_(stop); + add_predecessor_(step); } double const* ARangeNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void ARangeNode::commit(State& state) const { data_ptr(state)->commit(); } +void ARangeNode::commit(State& state) const { data_ptr_(state)->commit(); } std::span ARangeNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } bool ARangeNode::integral() const { return true; } void ARangeNode::initialize_state(State& state) const { - emplace_data_ptr(state, arange(state, start_, stop_, step_)); + emplace_data_ptr_(state, arange(state, start_, stop_, step_)); } double ARangeNode::min() const { return values_minmax_.first; } @@ -370,7 +370,7 @@ void ARangeNode::propagate(State& state) const { const auto [stop_old, stop_new] = std::visit(visitor, stop_); const auto [step_old, step_new] = std::visit(visitor, step_); - ArrayNodeStateData* ptr = data_ptr(state); + ArrayNodeStateData* ptr = data_ptr_(state); // If the start or the step has changed, we need to change everything // Alternatively if there is currently nothing in the buffer at all, we might @@ -422,18 +422,18 @@ void ARangeNode::propagate(State& state) const { if (ptr->diff().size()) Node::propagate(state); } -void ARangeNode::revert(State& state) const { data_ptr(state)->revert(); } +void ARangeNode::revert(State& state) const { data_ptr_(state)->revert(); } std::span ARangeNode::shape(const State& state) const { - return std::span(&(data_ptr(state)->size()), 1); + return std::span(&(data_ptr_(state)->size()), 1); } ssize_t ARangeNode::size(const State& state) const { - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } ssize_t ARangeNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/flow.cpp b/dwave/optimization/src/nodes/flow.cpp index 73e3da2d..ebd464b2 100644 --- a/dwave/optimization/src/nodes/flow.cpp +++ b/dwave/optimization/src/nodes/flow.cpp @@ -59,18 +59,18 @@ ExtractNode::ExtractNode(ArrayNode* condition_ptr, ArrayNode* arr_ptr) : throw std::invalid_argument("condition and arr must have the same size"); } - add_predecessor(condition_ptr); - add_predecessor(arr_ptr); + add_predecessor_(condition_ptr); + add_predecessor_(arr_ptr); } double const* ExtractNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void ExtractNode::commit(State& state) const { data_ptr(state)->commit(); } +void ExtractNode::commit(State& state) const { data_ptr_(state)->commit(); } std::span ExtractNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void ExtractNode::initialize_state(State& state) const { @@ -89,7 +89,7 @@ void ExtractNode::initialize_state(State& state) const { } } - emplace_data_ptr(state, std::move(values)); + emplace_data_ptr_(state, std::move(values)); } bool ExtractNode::integral() const { return values_info_.integral; } @@ -99,7 +99,7 @@ double ExtractNode::max() const { return values_info_.max; } double ExtractNode::min() const { return values_info_.min; } void ExtractNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); // Nothing to do in this case if (condition_ptr_->diff(state).empty() && arr_ptr_->diff(state).empty()) return; @@ -143,18 +143,18 @@ void ExtractNode::propagate(State& state) const { node_data->assign(std::move(new_values), count); } -void ExtractNode::revert(State& state) const { data_ptr(state)->revert(); } +void ExtractNode::revert(State& state) const { data_ptr_(state)->revert(); } std::span ExtractNode::shape(const State& state) const { - return std::span(&data_ptr(state)->size(), 1); + return std::span(&data_ptr_(state)->size(), 1); } ssize_t ExtractNode::size(const State& state) const { - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } ssize_t ExtractNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo ExtractNode::sizeinfo() const { return this->sizeinfo_; } @@ -261,19 +261,19 @@ WhereNode::WhereNode(ArrayNode* condition_ptr, ArrayNode* x_ptr, ArrayNode* y_pt } } - add_predecessor(condition_ptr); - add_predecessor(x_ptr); - add_predecessor(y_ptr); + add_predecessor_(condition_ptr); + add_predecessor_(x_ptr); + add_predecessor_(y_ptr); } double const* WhereNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void WhereNode::commit(State& state) const { data_ptr(state)->commit(); } +void WhereNode::commit(State& state) const { data_ptr_(state)->commit(); } std::span WhereNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void WhereNode::initialize_state(State& state) const { @@ -295,15 +295,15 @@ void WhereNode::initialize_state(State& state) const { values.emplace_back((*cit) ? *xit : *yit); } - emplace_data_ptr(state, std::move(values)); + emplace_data_ptr_(state, std::move(values)); } else if (condition_ptr_->buff(state)[0]) { // `condition` is a single value and is currently selecting x // so our state is just a copy of x's - emplace_data_ptr(state, x_ptr_->view(state)); + emplace_data_ptr_(state, x_ptr_->view(state)); } else { // `condition` is a single value and is currently selecting y // so our state is just a copy of y's - emplace_data_ptr(state, y_ptr_->view(state)); + emplace_data_ptr_(state, y_ptr_->view(state)); } } @@ -324,7 +324,7 @@ bool _flipped(std::span diff) { } void WhereNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); if (condition_ptr_->size() != 1) { // `condition` is an array @@ -364,7 +364,7 @@ void WhereNode::propagate(State& state) const { } } -void WhereNode::revert(State& state) const { data_ptr(state)->revert(); } +void WhereNode::revert(State& state) const { data_ptr_(state)->revert(); } std::span WhereNode::shape(const State& state) const { if (!this->dynamic()) return this->shape(); @@ -391,14 +391,14 @@ ssize_t WhereNode::size(const State& state) const { } // should match our current buffer - assert(static_cast(data_ptr(state)->size()) == size); + assert(static_cast(data_ptr_(state)->size()) == size); return size; } ssize_t WhereNode::size_diff(const State& state) const { if (!this->dynamic()) return 0; - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo WhereNode::sizeinfo() const { return this->sizeinfo_; } diff --git a/dwave/optimization/src/nodes/indexing.cpp b/dwave/optimization/src/nodes/indexing.cpp index 8b2f8f4e..cb753b57 100644 --- a/dwave/optimization/src/nodes/indexing.cpp +++ b/dwave/optimization/src/nodes/indexing.cpp @@ -511,20 +511,20 @@ AdvancedIndexingNode::AdvancedIndexingNode(ArrayNode* array_ptr, IndexParser_&& // Now actually add them. This way if there is an error thrown we're not // causing segfaults - add_predecessor(array_ptr); + add_predecessor_(array_ptr); for (const array_or_slice& index : indices_) { if (std::holds_alternative(index)) { - add_predecessor(std::get(index)); + add_predecessor_(std::get(index)); } } } double const* AdvancedIndexingNode::buff(const State& state) const { - return data_ptr(state)->data.data(); + return data_ptr_(state)->data.data(); } std::span AdvancedIndexingNode::diff(const State& state) const { - return data_ptr(state)->diff; + return data_ptr_(state)->diff; } void AdvancedIndexingNode::fill_subspace( @@ -733,18 +733,18 @@ void AdvancedIndexingNode::initialize_state(State& state) const { bool main_array_is_constant_node = dynamic_cast(array_ptr_) != nullptr; - emplace_data_ptr( + emplace_data_ptr_( state, this, std::move(offsets), std::move(data), !main_array_is_constant_node ); if (dynamic()) update_dynamic_shape(state); } void AdvancedIndexingNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } void AdvancedIndexingNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); if (dynamic()) update_dynamic_shape(state); } @@ -756,7 +756,7 @@ double AdvancedIndexingNode::min() const { return this->values_info_.min; } double AdvancedIndexingNode::max() const { return this->values_info_.max; } ssize_t AdvancedIndexingNode::size(const State& state) const { - return dynamic() ? data_ptr(state)->data.size() : this->size(); + return dynamic() ? data_ptr_(state)->data.size() : this->size(); } SizeInfo AdvancedIndexingNode::sizeinfo() const { @@ -813,7 +813,7 @@ SizeInfo AdvancedIndexingNode::sizeinfo() const { std::span AdvancedIndexingNode::shape(const State& state) const { if (!dynamic()) return shape(); return std::span( - data_ptr(state)->dynamic_shape.get(), ndim_ + data_ptr_(state)->dynamic_shape.get(), ndim_ ); } @@ -854,7 +854,7 @@ std::pair get_mapped_index( void AdvancedIndexingNode::propagate(State& state) const { // Pull the data into this namespce - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); auto& data = node_data->data; auto& diff = node_data->diff; auto& offsets_diff = node_data->offsets_diff; @@ -1095,7 +1095,7 @@ void AdvancedIndexingNode::propagate(State& state) const { ssize_t AdvancedIndexingNode::size_diff(const State& state) const { if (this->dynamic()) { - auto ptr = data_ptr(state); + auto ptr = data_ptr_(state); return static_cast(ptr->data.size()) - ptr->old_data_size; } @@ -1106,7 +1106,7 @@ void AdvancedIndexingNode::update_dynamic_shape(State& state) const { assert(dynamic()); assert(array_ptr_->ndim() >= 1); - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->dynamic_shape[0] = this->size(state) / (strides()[0] / itemsize()); } @@ -1384,7 +1384,7 @@ BasicIndexingNode::BasicIndexingNode(ArrayNode* array_ptr, IndexParser_&& parser "stops in the first dimension, are not currently supported" ); } - add_predecessor(array_ptr); + add_predecessor_(array_ptr); } struct BasicIndexingNodeData : NodeStateData { @@ -1429,7 +1429,7 @@ void BasicIndexingNode::update_dynamic_shape(State& state) const { const Slice& slice = axis0_slice_.value(); const ssize_t& first_dim_size = array_ptr_->shape(state)[0]; - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->fitted_first_slice = slice.fit(first_dim_size); @@ -1443,12 +1443,12 @@ double const* BasicIndexingNode::buff(const State& state) const { return array_ptr_->buff(state) + start_; } - const auto node_data = data_ptr(state); + const auto node_data = data_ptr_(state); return array_ptr_->buff(state) + start_ + dynamic_start(node_data->fitted_first_slice.start); } void BasicIndexingNode::commit(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->diff.clear(); node_data->previous_size = size(state); if (dynamic() && axis0_slice_.value().start < 0) { @@ -1458,7 +1458,7 @@ void BasicIndexingNode::commit(State& state) const { } std::span BasicIndexingNode::diff(const State& state) const { - return data_ptr(state)->diff; + return data_ptr_(state)->diff; } std::vector BasicIndexingNode::infer_indices() const { @@ -1521,10 +1521,10 @@ std::vector BasicIndexingNode::infer_indices() void BasicIndexingNode::initialize_state(State& state) const { // we're a view, so we don't really need state other than for the updates - emplace_data_ptr(state, this); + emplace_data_ptr_(state, this); if (this->dynamic()) { update_dynamic_shape(state); - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->previous_size = size(state); if (axis0_slice_.value().start < 0) { @@ -1561,7 +1561,7 @@ double BasicIndexingNode::min() const { return this->values_info_.min; } double BasicIndexingNode::max() const { return this->values_info_.max; } void BasicIndexingNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); auto& diff = node_data->diff; assert(diff.size() == 0 && "calling propagate on an node with pending updates"); @@ -1890,7 +1890,7 @@ void BasicIndexingNode::propagate(State& state) const { } void BasicIndexingNode::revert(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->diff.clear(); if (dynamic()) { // todo this is only safe if revert() has been called on the predecessor array @@ -1906,7 +1906,9 @@ void BasicIndexingNode::revert(State& state) const { ssize_t BasicIndexingNode::size(const State& state) const { if (not dynamic()) return size_; - return Array::shape_to_size(ndim_, data_ptr(state)->dynamic_shape.get()); + return Array::shape_to_size( + ndim_, data_ptr_(state)->dynamic_shape.get() + ); } SizeInfo BasicIndexingNode::sizeinfo() const { return this->sizeinfo_; } @@ -1914,7 +1916,7 @@ SizeInfo BasicIndexingNode::sizeinfo() const { return this->sizeinfo_; } ssize_t BasicIndexingNode::size_diff(const State& state) const { if (size_ >= 0) return 0; - auto ptr = data_ptr(state); + auto ptr = data_ptr_(state); return size(state) - ptr->previous_size; } @@ -1922,7 +1924,7 @@ std::span BasicIndexingNode::shape(const State& state) const { if (not dynamic()) return BasicIndexingNode::shape(); return std::span( - data_ptr(state)->dynamic_shape.get(), ndim_ + data_ptr_(state)->dynamic_shape.get(), ndim_ ); } @@ -1965,18 +1967,18 @@ PermutationNode::PermutationNode(ArrayNode* array_ptr, ArrayNode* order_ptr) : throw std::invalid_argument("order may have values out of range"); } - this->add_predecessor(array_ptr); - this->add_predecessor(order_ptr); + this->add_predecessor_(array_ptr); + this->add_predecessor_(order_ptr); } -void PermutationNode::commit(State& state) const { data_ptr(state)->commit(); } +void PermutationNode::commit(State& state) const { data_ptr_(state)->commit(); } double const* PermutationNode::buff(const State& state) const { - return data_ptr(state)->data.data(); + return data_ptr_(state)->data.data(); } std::span PermutationNode::diff(const State& state) const { - return data_ptr(state)->diff; + return data_ptr_(state)->diff; } bool PermutationNode::integral() const { return values_info_.integral; } @@ -2029,11 +2031,11 @@ void PermutationNode::initialize_state(State& state) const { } } - emplace_data_ptr(state, std::move(offsets), std::move(values)); + emplace_data_ptr_(state, std::move(offsets), std::move(values)); } void PermutationNode::propagate(State& state) const { - auto ptr = data_ptr(state); + auto ptr = data_ptr_(state); auto& offsets = ptr->offsets; auto& values = ptr->data; @@ -2086,6 +2088,6 @@ void PermutationNode::propagate(State& state) const { if (updates.size()) Node::propagate(state); } -void PermutationNode::revert(State& state) const { data_ptr(state)->revert(); } +void PermutationNode::revert(State& state) const { data_ptr_(state)->revert(); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/inputs.cpp b/dwave/optimization/src/nodes/inputs.cpp index 43c036f4..ba0967be 100644 --- a/dwave/optimization/src/nodes/inputs.cpp +++ b/dwave/optimization/src/nodes/inputs.cpp @@ -51,11 +51,11 @@ void InputNode::assign(State& state, std::initializer_list new_values) c void InputNode::assign(State& state, std::span new_values) const { check_values(new_values); - data_ptr(state)->assign(new_values); + data_ptr_(state)->assign(new_values); } double const* InputNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void InputNode::check_values(std::span new_values) const { @@ -77,11 +77,11 @@ void InputNode::check_values(std::span new_values) const { } void InputNode::commit(State& state) const noexcept { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } std::span InputNode::diff(const State& state) const noexcept { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void InputNode::initialize_state(State& state, std::initializer_list data) const { @@ -96,11 +96,11 @@ void InputNode::initialize_state(State& state, std::span data) con std::vector copy(data.begin(), data.end()); - emplace_data_ptr(state, std::move(copy)); + emplace_data_ptr_(state, std::move(copy)); } void InputNode::revert(State& state) const noexcept { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/interpolation.cpp b/dwave/optimization/src/nodes/interpolation.cpp index 2f4c3eeb..45bc9f0f 100644 --- a/dwave/optimization/src/nodes/interpolation.cpp +++ b/dwave/optimization/src/nodes/interpolation.cpp @@ -69,7 +69,7 @@ BSplineNode::BSplineNode( ); } - this->add_predecessor(array_ptr); + this->add_predecessor_(array_ptr); } std::vector BSplineNode::bspline_basis(double state) const { @@ -117,20 +117,20 @@ const std::vector& BSplineNode::c() const { return c_; } ssize_t BSplineNode::size(const State& state) const { return array_ptr_->size(state); } double const* BSplineNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void BSplineNode::commit(State& state) const { - return data_ptr(state)->commit(); + return data_ptr_(state)->commit(); } std::span BSplineNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } bool BSplineNode::integral() const { return false; } void BSplineNode::revert(State& state) const { - return data_ptr(state)->revert(); + return data_ptr_(state)->revert(); } double BSplineNode::max() const { return minmax_.second; } @@ -144,7 +144,7 @@ void BSplineNode::initialize_state(State& state) const { for (int i = 0, stop = array_ptr_->size(); i < stop; ++i) { bspline_values.push_back(compute_value(state_data[i])); } - emplace_data_ptr(state, std::move(bspline_values)); + emplace_data_ptr_(state, std::move(bspline_values)); } void BSplineNode::propagate(State& state) const { @@ -153,7 +153,7 @@ void BSplineNode::propagate(State& state) const { auto state_data = node_data_ptr->view(state); for (const auto& [index, _, __] : diff) { - data_ptr(state)->set(index, compute_value(state_data[index])); + data_ptr_(state)->set(index, compute_value(state_data[index])); } } diff --git a/dwave/optimization/src/nodes/lambda.cpp b/dwave/optimization/src/nodes/lambda.cpp index 3c3f756e..bdb0bd4d 100644 --- a/dwave/optimization/src/nodes/lambda.cpp +++ b/dwave/optimization/src/nodes/lambda.cpp @@ -52,15 +52,15 @@ AccumulateZipNode::AccumulateZipNode( if (std::holds_alternative(initial)) { // was checked in check() method - add_predecessor(std::get(initial)); + add_predecessor_(std::get(initial)); } for (const auto& op : operands_) { - add_predecessor(op); + add_predecessor_(op); } } double const* AccumulateZipNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void AccumulateZipNode::check( @@ -222,11 +222,11 @@ void AccumulateZipNode::check( } void AccumulateZipNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } std::span AccumulateZipNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } double AccumulateZipNode::evaluate_expression(State& register_) const { @@ -312,7 +312,7 @@ std::span AccumulateZipNode::operand_inputs() const { } void AccumulateZipNode::propagate(State& state) const { - AccumulateZipNodeData* data = data_ptr(state); + AccumulateZipNodeData* data = data_ptr_(state); ssize_t new_size = this->size(state); ssize_t num_args = operands_.size(); @@ -355,7 +355,7 @@ const InputNode* const AccumulateZipNode::accumulate_input() const { } void AccumulateZipNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } std::span AccumulateZipNode::shape(const State& state) const { @@ -367,7 +367,7 @@ ssize_t AccumulateZipNode::size(const State& state) const { return operands_[0]- SizeInfo AccumulateZipNode::sizeinfo() const { return this->sizeinfo_; } ssize_t AccumulateZipNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/linear_algebra.cpp b/dwave/optimization/src/nodes/linear_algebra.cpp index 3a17f2eb..267b0793 100644 --- a/dwave/optimization/src/nodes/linear_algebra.cpp +++ b/dwave/optimization/src/nodes/linear_algebra.cpp @@ -385,8 +385,8 @@ MatrixMultiplyNode::MatrixMultiplyNode(ArrayNode* x_ptr, ArrayNode* y_ptr) : y_ptr_(y_ptr), sizeinfo_(get_sizeinfo(x_ptr, y_ptr)), values_info_(get_values_info(x_ptr, y_ptr)) { - add_predecessor(x_ptr); - add_predecessor(y_ptr); + add_predecessor_(x_ptr); + add_predecessor_(y_ptr); } ssize_t get_leading_leap(std::span shape) { @@ -500,19 +500,19 @@ void MatrixMultiplyNode::initialize_state(State& state) const { std::vector data(start_size); matmul_(state, data, shape); - emplace_data_ptr(state, std::move(data), shape); + emplace_data_ptr_(state, std::move(data), shape); } double const* MatrixMultiplyNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void MatrixMultiplyNode::commit(State& state) const { - return data_ptr(state)->commit(); + return data_ptr_(state)->commit(); } std::span MatrixMultiplyNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } bool MatrixMultiplyNode::integral() const { return values_info_.integral; } @@ -523,14 +523,14 @@ double MatrixMultiplyNode::min() const { return values_info_.min; } void MatrixMultiplyNode::update_shape_(State& state) const { if (this->dynamic()) { - data_ptr(state)->shape[0] = x_ptr_->shape(state)[0]; + data_ptr_(state)->shape[0] = x_ptr_->shape(state)[0]; } } void MatrixMultiplyNode::propagate(State& state) const { if (x_ptr_->diff(state).size() == 0 and y_ptr_->diff(state).size() == 0) return; - auto data = data_ptr(state); + auto data = data_ptr_(state); this->update_shape_(state); const ssize_t new_size = Array::shape_to_size(data->shape); @@ -542,24 +542,24 @@ void MatrixMultiplyNode::propagate(State& state) const { } void MatrixMultiplyNode::revert(State& state) const { - auto data = data_ptr(state); + auto data = data_ptr_(state); data->revert(); this->update_shape_(state); } std::span MatrixMultiplyNode::shape(const State& state) const { if (not this->dynamic()) return this->shape(); - return data_ptr(state)->shape; + return data_ptr_(state)->shape; } ssize_t MatrixMultiplyNode::size(const State& state) const { if (not this->dynamic()) return this->size(); - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } ssize_t MatrixMultiplyNode::size_diff(const State& state) const { if (not this->dynamic()) return 0; - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo MatrixMultiplyNode::sizeinfo() const { return sizeinfo_; } diff --git a/dwave/optimization/src/nodes/lp.cpp b/dwave/optimization/src/nodes/lp.cpp index 9fa1a066..b7ea1714 100644 --- a/dwave/optimization/src/nodes/lp.cpp +++ b/dwave/optimization/src/nodes/lp.cpp @@ -43,7 +43,7 @@ struct LinearProgramNodeData : NodeStateData { LinearProgramFeasibleNode::LinearProgramFeasibleNode(LinearProgramNodeBase* lp_ptr) : lp_ptr_(lp_ptr) { - add_predecessor(lp_ptr); + add_predecessor_(lp_ptr); } void LinearProgramFeasibleNode::initialize_state(State& state) const { @@ -193,14 +193,14 @@ LinearProgramNode::LinearProgramNode( // Finally, add the nodes (if they were passed in) as predecessors. This does // mean that we can't access them by index within the predecessor list, so // we save them as ArrayNode* on the class rather than just as Array*. - add_predecessor(c_ptr); - if (b_lb_ptr) add_predecessor(b_lb_ptr); - if (A_ptr) add_predecessor(A_ptr); - if (b_ub_ptr) add_predecessor(b_ub_ptr); - if (A_eq_ptr) add_predecessor(A_eq_ptr); - if (b_eq_ptr) add_predecessor(b_eq_ptr); - if (lb_ptr) add_predecessor(lb_ptr); - if (ub_ptr) add_predecessor(ub_ptr); + add_predecessor_(c_ptr); + if (b_lb_ptr) add_predecessor_(b_lb_ptr); + if (A_ptr) add_predecessor_(A_ptr); + if (b_ub_ptr) add_predecessor_(b_ub_ptr); + if (A_eq_ptr) add_predecessor_(A_eq_ptr); + if (b_eq_ptr) add_predecessor_(b_eq_ptr); + if (lb_ptr) add_predecessor_(lb_ptr); + if (ub_ptr) add_predecessor_(ub_ptr); } void LinearProgramNode::commit(State& state) const {}; @@ -208,7 +208,7 @@ void LinearProgramNode::commit(State& state) const {}; bool LinearProgramNode::deterministic_state() const { return false; } bool LinearProgramNode::feasible(const State& state) const { - return data_ptr(state)->result.feasible(); + return data_ptr_(state)->result.feasible(); } std::unordered_map LinearProgramNode::get_arguments() const { @@ -290,7 +290,7 @@ void LinearProgramNode::initialize_state(State& state) const { lp.c, lp.b_lb, lp.A, lp.b_ub, lp.A_eq, lp.b_eq, lp.lb, lp.ub, FEASIBILITY_TOLERANCE ); - emplace_data_ptr(state, std::move(result)); + emplace_data_ptr_(state, std::move(result)); } void LinearProgramNode::initialize_state( @@ -314,15 +314,15 @@ void LinearProgramNode::initialize_state( FEASIBILITY_TOLERANCE ); - emplace_data_ptr(state, std::move(result)); + emplace_data_ptr_(state, std::move(result)); } double LinearProgramNode::objective_value(const dwave::optimization::State& state) const { - return data_ptr(state)->result.objective(); + return data_ptr_(state)->result.objective(); } void LinearProgramNode::propagate(State& state) const { - auto data = data_ptr(state); + auto data = data_ptr_(state); readout_predecessor_data(state, data->lp); data->result = linprog( @@ -345,7 +345,7 @@ void LinearProgramNode::revert(State& state) const { } std::span LinearProgramNode::solution(const State& state) const { - return data_ptr(state)->result.solution(); + return data_ptr_(state)->result.solution(); } std::pair LinearProgramNode::variables_minmax() const { return variables_minmax_; } @@ -354,7 +354,7 @@ std::span LinearProgramNode::variables_shape() const { return c_p LinearProgramObjectiveValueNode::LinearProgramObjectiveValueNode(LinearProgramNodeBase* lp_ptr) : lp_ptr_(lp_ptr) { - add_predecessor(lp_ptr); + add_predecessor_(lp_ptr); } void LinearProgramObjectiveValueNode::initialize_state(State& state) const { @@ -375,19 +375,19 @@ void LinearProgramObjectiveValueNode::propagate(State& state) const { LinearProgramSolutionNode::LinearProgramSolutionNode(LinearProgramNodeBase* lp_ptr) : ArrayOutputMixin(lp_ptr->variables_shape()), lp_ptr_(lp_ptr) { - add_predecessor(lp_ptr); + add_predecessor_(lp_ptr); } double const* LinearProgramSolutionNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void LinearProgramSolutionNode::commit(State& state) const { - return data_ptr(state)->commit(); + return data_ptr_(state)->commit(); } std::span LinearProgramSolutionNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void LinearProgramSolutionNode::initialize_state(State& state) const { @@ -433,14 +433,14 @@ void LinearProgramSolutionNode::propagate(State& state) const { auto clipped_view = std::views::transform(sol, [&min_lb, &max_ub](double v) { return std::clamp(v, min_lb, max_ub); }); - data_ptr(state)->assign(clipped_view); + data_ptr_(state)->assign(clipped_view); Node::propagate(state); } } void LinearProgramSolutionNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/manipulation.cpp b/dwave/optimization/src/nodes/manipulation.cpp index 48116a7b..7260c123 100644 --- a/dwave/optimization/src/nodes/manipulation.cpp +++ b/dwave/optimization/src/nodes/manipulation.cpp @@ -191,17 +191,19 @@ BroadcastToNode::BroadcastToNode(ArrayNode* array_ptr, std::span // Track whether we're contiguous contiguous_ = is_contiguous(ndim_, shape_.get(), strides_.get()); - add_predecessor(array_ptr); + add_predecessor_(array_ptr); } double const* BroadcastToNode::buff(const State& state) const { return array_ptr_->buff(state); } -void BroadcastToNode::commit(State& state) const { data_ptr(state)->commit(); } +void BroadcastToNode::commit(State& state) const { + data_ptr_(state)->commit(); +} bool BroadcastToNode::contiguous() const { return contiguous_; } std::span BroadcastToNode::diff(const State& state) const { - return data_ptr(state)->diff; + return data_ptr_(state)->diff; } void BroadcastToNode::initialize_state(State& state) const { @@ -224,10 +226,10 @@ void BroadcastToNode::initialize_state(State& state) const { shape[0] = array_ptr_->shape(state)[0]; assert(shape[0] >= 0); - emplace_data_ptr(state, std::move(offsets), std::move(shape)); + emplace_data_ptr_(state, std::move(offsets), std::move(shape)); } else { // `this` has a fixed shape - emplace_data_ptr(state, std::move(offsets)); + emplace_data_ptr_(state, std::move(offsets)); } } @@ -240,7 +242,7 @@ double BroadcastToNode::max() const { return values_info_.max; } ssize_t BroadcastToNode::ndim() const { return ndim_; } void BroadcastToNode::propagate(State& state) const { - BroadcastToNodeData* data_ptr = this->data_ptr(state); + BroadcastToNodeData* data_ptr = this->data_ptr_(state); const auto from_diff = array_ptr_->diff(state); if (from_diff.empty()) return; // exit early if nothing to propagate @@ -289,7 +291,7 @@ void BroadcastToNode::propagate(State& state) const { // we also need to update the shape/sizediff, if we're dynamic if (dynamic()) { - auto* dynamic_data_ptr = this->data_ptr(state); + auto* dynamic_data_ptr = this->data_ptr_(state); dynamic_data_ptr->shape[0] = array_ptr_->shape(state)[0]; dynamic_data_ptr->size_diff = size_diff; } @@ -353,7 +355,9 @@ ssize_t BroadcastToNode::convert_predecessor_index_(ssize_t index) const { return flat_index; } -void BroadcastToNode::revert(State& state) const { data_ptr(state)->revert(); } +void BroadcastToNode::revert(State& state) const { + data_ptr_(state)->revert(); +} std::span BroadcastToNode::shape() const { return std::span(shape_.get(), ndim_); @@ -361,7 +365,7 @@ std::span BroadcastToNode::shape() const { std::span BroadcastToNode::shape(const State& state) const { if (!ndim_ || shape_[0] >= 0) return shape(); // not dynamic - return data_ptr(state)->shape; + return data_ptr_(state)->shape; } ssize_t BroadcastToNode::size() const { @@ -374,14 +378,14 @@ ssize_t BroadcastToNode::size() const { ssize_t BroadcastToNode::size(const State& state) const { if (const ssize_t size = this->size(); size >= 0) return size; // size is not state-dependent - const auto& shape = data_ptr(state)->shape; + const auto& shape = data_ptr_(state)->shape; assert(shape.size() > 0 && shape[0] >= 0); return std::reduce(shape.begin(), shape.end(), 1, std::multiplies()); } ssize_t BroadcastToNode::size_diff(const State& state) const { if (this->size() >= 0) return 0; // size is not state-dependent - return data_ptr(state)->size_diff; + return data_ptr_(state)->size_diff; } std::span BroadcastToNode::strides() const { @@ -391,10 +395,10 @@ std::span BroadcastToNode::strides() const { std::vector make_concatenate_shape(std::span array_ptrs, ssize_t axis); double const* ConcatenateNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void ConcatenateNode::commit(State& state) const { data_ptr(state)->commit(); } +void ConcatenateNode::commit(State& state) const { data_ptr_(state)->commit(); } ConcatenateNode::ConcatenateNode(std::span array_ptrs, const ssize_t axis) : ArrayOutputMixin(make_concatenate_shape(array_ptrs, axis)), @@ -418,12 +422,12 @@ ConcatenateNode::ConcatenateNode(std::span array_ptrs, const ssize_t throw std::invalid_argument("concatenate input arrays cannot be dynamic"); } - this->add_predecessor((*it)); + this->add_predecessor_((*it)); } } std::span ConcatenateNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void ConcatenateNode::initialize_state(State& state) const { @@ -443,7 +447,7 @@ void ConcatenateNode::initialize_state(State& state) const { std::copy(array_ptrs_[arr_i]->begin(state), array_ptrs_[arr_i]->end(state), view_it); } - emplace_data_ptr(state, std::move(values)); + emplace_data_ptr_(state, std::move(values)); } std::vector make_concatenate_shape(std::span array_ptrs, ssize_t axis) { @@ -515,7 +519,7 @@ double ConcatenateNode::min() const { return values_info_.min; } double ConcatenateNode::max() const { return values_info_.max; } void ConcatenateNode::propagate(State& state) const { - auto ptr = data_ptr(state); + auto ptr = data_ptr_(state); for (ssize_t arr_i = 0, stop = array_ptrs_.size(); arr_i < stop; ++arr_i) { auto view_it = Array::const_iterator( @@ -535,25 +539,25 @@ void ConcatenateNode::propagate(State& state) const { } } -void ConcatenateNode::revert(State& state) const { data_ptr(state)->revert(); } +void ConcatenateNode::revert(State& state) const { data_ptr_(state)->revert(); } CopyNode::CopyNode(ArrayNode* array_ptr) : ArrayOutputMixin(array_ptr->shape()), array_ptr_(array_ptr), values_info_(array_ptr_) { - this->add_predecessor(array_ptr); + this->add_predecessor_(array_ptr); } double const* CopyNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void CopyNode::commit(State& state) const { data_ptr(state)->commit(); } +void CopyNode::commit(State& state) const { data_ptr_(state)->commit(); } std::span CopyNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void CopyNode::initialize_state(State& state) const { - emplace_data_ptr(state, array_ptr_->view(state)); + emplace_data_ptr_(state, array_ptr_->view(state)); } bool CopyNode::integral() const { return values_info_.integral; } @@ -563,10 +567,10 @@ double CopyNode::min() const { return values_info_.min; } double CopyNode::max() const { return values_info_.max; } void CopyNode::propagate(State& state) const { - data_ptr(state)->update(array_ptr_->diff(state)); + data_ptr_(state)->update(array_ptr_->diff(state)); } -void CopyNode::revert(State& state) const { data_ptr(state)->revert(); } +void CopyNode::revert(State& state) const { data_ptr_(state)->revert(); } std::span CopyNode::shape(const State& state) const { return array_ptr_->shape(state); @@ -733,19 +737,19 @@ PutNode::PutNode(ArrayNode* array_ptr, ArrayNode* indices_ptr, ArrayNode* values throw std::out_of_range("indices may not exceed the size of the array"); } - add_predecessor(array_ptr); - add_predecessor(indices_ptr); - add_predecessor(values_ptr); + add_predecessor_(array_ptr); + add_predecessor_(indices_ptr); + add_predecessor_(values_ptr); } double const* PutNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void PutNode::commit(State& state) const { return data_ptr(state)->commit(); } +void PutNode::commit(State& state) const { return data_ptr_(state)->commit(); } std::span PutNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void PutNode::initialize_state(State& state) const { @@ -770,11 +774,11 @@ void PutNode::initialize_state(State& state) const { } } - emplace_data_ptr(state, std::move(values), std::move(mask)); + emplace_data_ptr_(state, std::move(values), std::move(mask)); } std::span PutNode::mask(const State& state) const { - return data_ptr(state)->mask(); + return data_ptr_(state)->mask(); } bool PutNode::integral() const { return values_info_.integral; } @@ -784,7 +788,7 @@ double PutNode::min() const { return values_info_.min; } double PutNode::max() const { return values_info_.max; } void PutNode::propagate(State& state) const { - auto ptr = data_ptr(state); + auto ptr = data_ptr_(state); // these should always be synced assert(indices_ptr_->size(state) == values_ptr_->size(state)); @@ -856,7 +860,7 @@ void PutNode::propagate(State& state) const { if (ptr->diff().size()) Node::propagate(state); } -void PutNode::revert(State& state) const { return data_ptr(state)->revert(); } +void PutNode::revert(State& state) const { return data_ptr_(state)->revert(); } // Reshape allows one shape dimension to be -1. In that case the size is inferred. // We do that inference here. @@ -984,14 +988,14 @@ ReshapeNode::ReshapeNode(ArrayNode* node_ptr, std::vector&& shape) : ); } - this->add_predecessor(node_ptr); + this->add_predecessor_(node_ptr); } double const* ReshapeNode::buff(const State& state) const { return array_ptr_->buff(state); } void ReshapeNode::commit(State& state) const { if (!this->dynamic()) return; // stateless - return data_ptr(state)->commit(); + return data_ptr_(state)->commit(); } std::span ReshapeNode::diff(const State& state) const { @@ -1000,7 +1004,7 @@ std::span ReshapeNode::diff(const State& state) const { void ReshapeNode::initialize_state(State& state) const { if (!this->dynamic()) return Node::initialize_state(state); // stateless - emplace_data_ptr(state, this->shape(), array_ptr_->size(state)); + emplace_data_ptr_(state, this->shape(), array_ptr_->size(state)); } bool ReshapeNode::integral() const { return values_info_.integral; } @@ -1011,29 +1015,29 @@ double ReshapeNode::max() const { return values_info_.max; } void ReshapeNode::propagate(State& state) const { if (!this->dynamic()) return; // stateless - data_ptr(state)->set_size(array_ptr_->size(state)); + data_ptr_(state)->set_size(array_ptr_->size(state)); } void ReshapeNode::revert(State& state) const { if (!this->dynamic()) return; // stateless - return data_ptr(state)->revert(); + return data_ptr_(state)->revert(); } std::span ReshapeNode::shape(const State& state) const { if (!this->dynamic()) return this->shape(); // stateless - return data_ptr(state)->shape(); + return data_ptr_(state)->shape(); } ssize_t ReshapeNode::size(const State& state) const { if (!this->dynamic()) return this->size(); // stateless - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } SizeInfo ReshapeNode::sizeinfo() const { return this->sizeinfo_; } ssize_t ReshapeNode::size_diff(const State& state) const { if (!this->dynamic()) return 0; // stateless - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } bool is_fill_never_used(const Array* array_ptr, ssize_t this_size) { @@ -1075,19 +1079,19 @@ ResizeNode::ResizeNode(ArrayNode* array_ptr, std::vector&& shape, doubl // our incoming array can be any shape/size, but we cannot be dynamic if (this->dynamic()) throw std::invalid_argument("cannot resize to a dynamic shape"); - add_predecessor(array_ptr); + add_predecessor_(array_ptr); } double const* ResizeNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void ResizeNode::commit(State& state) const { - return data_ptr(state)->commit(); + return data_ptr_(state)->commit(); } std::span ResizeNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void ResizeNode::initialize_state(State& state) const { @@ -1110,7 +1114,7 @@ void ResizeNode::initialize_state(State& state) const { values.resize(size, fill_value_); // Finally create the state - emplace_data_ptr(state, std::move(values)); + emplace_data_ptr_(state, std::move(values)); } bool ResizeNode::integral() const { return values_info_.integral; } @@ -1123,7 +1127,7 @@ void ResizeNode::propagate(State& state) const { const ssize_t size = this->size(); // the desired size of our state assert(size >= 0); // we're never dynamic - auto data_ptr = this->data_ptr(state); + auto data_ptr = this->data_ptr_(state); assert(data_ptr); // should never be nullptr for (const Update& update : array_ptr_->diff(state)) { @@ -1144,7 +1148,7 @@ void ResizeNode::propagate(State& state) const { } void ResizeNode::revert(State& state) const { - return data_ptr(state)->revert(); + return data_ptr_(state)->revert(); } // Return the lhs % rhs, but always as a positive number @@ -1189,7 +1193,7 @@ RollNode::RollNode(ArrayNode* array_ptr, std::vector shift, std::vector if (ax < 0 or array_ptr_->ndim() <= ax) throw std::invalid_argument("axis out of bounds"); } - add_predecessor(array_ptr); + add_predecessor_(array_ptr); } RollNode::RollNode(ArrayNode* array_ptr, ArrayNode* shift_ptr, std::vector axis) : @@ -1222,20 +1226,20 @@ RollNode::RollNode(ArrayNode* array_ptr, ArrayNode* shift_ptr, std::vectorndim() <= ax) throw std::invalid_argument("axis out of bounds"); } - add_predecessor(array_ptr); - add_predecessor(shift_ptr); + add_predecessor_(array_ptr); + add_predecessor_(shift_ptr); } std::span RollNode::axes() const { return axis_; } double const* RollNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void RollNode::commit(State& state) const { data_ptr(state)->commit(); } +void RollNode::commit(State& state) const { data_ptr_(state)->commit(); } std::span RollNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void RollNode::initialize_state(State& state) const { @@ -1253,7 +1257,7 @@ void RollNode::initialize_state(State& state) const { rotate_(buffer, shape(state), shifts); } - emplace_data_ptr(state, std::move(buffer)); + emplace_data_ptr_(state, std::move(buffer)); } bool RollNode::integral() const { return values_info_.integral; } @@ -1263,7 +1267,7 @@ double RollNode::min() const { return values_info_.min; } double RollNode::max() const { return values_info_.max; } void RollNode::propagate(State& state) const { - ArrayNodeStateData* const state_ptr = data_ptr(state); + ArrayNodeStateData* const state_ptr = data_ptr_(state); if (axis_.empty()) { // We're shifting everything as a flat array @@ -1354,7 +1358,7 @@ void RollNode::propagate(State& state) const { } } -void RollNode::revert(State& state) const { data_ptr(state)->revert(); } +void RollNode::revert(State& state) const { data_ptr_(state)->revert(); } // Act on the given array *in place*. void RollNode::rotate_(std::span array, ssize_t shift) { @@ -1474,7 +1478,7 @@ ssize_t RollNode::size(const State& state) const { SizeInfo RollNode::sizeinfo() const { return sizeinfo_; } ssize_t RollNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeNode::SizeNode(ArrayNode* node_ptr) : @@ -1483,7 +1487,7 @@ SizeNode::SizeNode(ArrayNode* node_ptr) : array_ptr_->sizeinfo().min.value_or(0), array_ptr_->sizeinfo().max.value_or(std::numeric_limits::max()) ) { - this->add_predecessor(node_ptr); + this->add_predecessor_(node_ptr); } void SizeNode::initialize_state(State& state) const { @@ -1545,7 +1549,7 @@ TransposeNode::TransposeNode(ArrayNode* array_ptr) : contiguous_(is_contiguous(ndim_, shape_.get(), strides_.get())), values_info_(array_ptr), sizeinfo_(array_ptr_->sizeinfo()) { - add_predecessor(array_ptr); + add_predecessor_(array_ptr); } // this node simply points to the predecessor buff @@ -1605,7 +1609,7 @@ std::span TransposeNode::diff(const State& state) const { return array_ptr_->diff(state); } // Otherwise, we use the stored diff data. - return data_ptr(state)->diff; + return data_ptr_(state)->diff; } ssize_t TransposeNode::size_diff(const State& state) const { return array_ptr_->size_diff(state); } @@ -1615,7 +1619,7 @@ void TransposeNode::initialize_state(State& state) const { return Node::initialize_state(state); // stateless } // Construct diff data if predecessor is (>=2)-D array - emplace_data_ptr(state); + emplace_data_ptr_(state); } Update TransposeNode::convert_predecessor_update_(Update update) const { @@ -1658,7 +1662,7 @@ void TransposeNode::propagate(State& state) const { } // Predecessor is a non-dynamic (>=2)-D array. - std::vector& transpose_diff = data_ptr(state)->diff; + std::vector& transpose_diff = data_ptr_(state)->diff; assert(transpose_diff.size() == 0); transpose_diff.reserve(array_ptr_->size_diff(state)); @@ -1678,13 +1682,13 @@ void TransposeNode::propagate(State& state) const { void TransposeNode::commit(State& state) const { if (ndim_ > 1) { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } // otherwise, stateless }; void TransposeNode::revert(State& state) const { if (ndim_ > 1) { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } // otherwise, stateless } diff --git a/dwave/optimization/src/nodes/naryop.cpp b/dwave/optimization/src/nodes/naryop.cpp index 305a9d64..420d9ebb 100644 --- a/dwave/optimization/src/nodes/naryop.cpp +++ b/dwave/optimization/src/nodes/naryop.cpp @@ -185,7 +185,7 @@ void NaryOpNode::add_node(ArrayNode* node_ptr, bool recompute_statisti throw std::invalid_argument("arrays must all be the same shape"); } - this->add_predecessor(node_ptr); + this->add_predecessor_(node_ptr); operands_.emplace_back(node_ptr); if (recompute_statistics) { @@ -195,12 +195,12 @@ void NaryOpNode::add_node(ArrayNode* node_ptr, bool recompute_statisti template double const* NaryOpNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } template std::span NaryOpNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } template @@ -220,12 +220,12 @@ double NaryOpNode::max() const { template void NaryOpNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } template void NaryOpNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } template @@ -255,12 +255,12 @@ void NaryOpNode::initialize_state(State& state) const { values.emplace_back(val); } - emplace_data_ptr(state, std::move(values), std::move(iterators)); + emplace_data_ptr_(state, std::move(values), std::move(iterators)); } template void NaryOpNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); auto& iterators = node_data->iterators; diff --git a/dwave/optimization/src/nodes/numbers.cpp b/dwave/optimization/src/nodes/numbers.cpp index 02a4fca1..8965b149 100644 --- a/dwave/optimization/src/nodes/numbers.cpp +++ b/dwave/optimization/src/nodes/numbers.cpp @@ -207,11 +207,11 @@ void NumberNodeStateData::update( } double const* NumberNode::buff(const State& state) const noexcept { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } std::span NumberNode::diff(const State& state) const noexcept { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } double NumberNode::min() const { return min_; } @@ -320,7 +320,7 @@ void NumberNode::initialize_state(State& state, std::vector&& number_dat } if (sum_constraints_.size() == 0) { // No sum constraints to consider. - emplace_data_ptr(state, std::move(number_data)); + emplace_data_ptr_(state, std::move(number_data)); } else { // Given the assignment to NumberNode `number_data`, compute the sum // of the values within each slice per sum constraint. @@ -330,7 +330,7 @@ void NumberNode::initialize_state(State& state, std::vector&& number_dat throw std::invalid_argument("Initialized values do not satisfy sum constraint(s)."); } - emplace_data_ptr( + emplace_data_ptr_( state, std::move(number_data), std::move(sum_constraints_lhs) ); } @@ -530,11 +530,11 @@ void NumberNode::propagate(State& state) const { } void NumberNode::commit(State& state) const noexcept { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } void NumberNode::revert(State& state) const noexcept { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } void NumberNode::exchange( @@ -544,7 +544,7 @@ void NumberNode::exchange( std::optional> i_slices, std::optional> j_slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); // We expect the exchange to obey the index-wise bounds. assert(lower_bound(i) <= state_data->get(j)); assert(upper_bound(i) >= state_data->get(j)); @@ -575,7 +575,7 @@ void NumberNode::exchange( } double NumberNode::get_value(State& state, ssize_t i) const { - return data_ptr(state)->get(i); + return data_ptr_(state)->get(i); } double NumberNode::lower_bound(ssize_t index) const { @@ -620,7 +620,7 @@ void NumberNode::clip_and_set_value( double value, std::optional> slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); value = std::clamp(value, lower_bound(index), upper_bound(index)); // assert() that i is a valid index occurs in ptr->set(). // State change occurs IFF `value` != buffer[index]. @@ -641,7 +641,7 @@ const std::vector& NumberNode::sum_constraints() cons } const std::vector>& NumberNode::sum_constraints_lhs(const State& state) const { - return data_ptr(state)->sum_constraints_lhs; + return data_ptr_(state)->sum_constraints_lhs; } template @@ -966,7 +966,7 @@ void IntegerNode::set_value( double value, std::optional> slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); // We expect `value` to obey the index-wise bounds and to be an integer. assert(lower_bound(index) <= value); assert(upper_bound(index) >= value); @@ -1436,7 +1436,7 @@ void BinaryNodeStateData::compute_slice_indices_(const BinaryNode& node) { } void BinaryNode::revert(State& state) const noexcept { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } void BinaryNode::initialize_state(State& state, std::vector&& number_data) const { @@ -1451,7 +1451,7 @@ void BinaryNode::initialize_state(State& state, std::vector&& number_dat } if (sum_constraints_.size() == 0) { // No sum constraints to consider. - emplace_data_ptr(state, std::move(number_data)); + emplace_data_ptr_(state, std::move(number_data)); } else { // Given the assignment to NumberNode `number_data`, compute the sum of // the values within each slice per sum constraint. @@ -1461,7 +1461,7 @@ void BinaryNode::initialize_state(State& state, std::vector&& number_dat throw std::invalid_argument("Initialized values do not satisfy sum constraint(s)."); } - emplace_data_ptr( + emplace_data_ptr_( state, std::move(number_data), std::move(sum_constraints_lhs), *this ); } @@ -1493,7 +1493,7 @@ void BinaryNode::exchange( std::optional> i_slices, std::optional> j_slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); // We expect the exchange to obey the index-wise bounds. assert(lower_bound(i) <= state_data->get(j)); assert(upper_bound(i) >= state_data->get(j)); @@ -1530,7 +1530,7 @@ void BinaryNode::clip_and_set_value( double value, std::optional> slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); value = std::clamp(value, lower_bound(index), upper_bound(index)); // assert() that i is a valid index occurs in ptr->set(). // State change occurs IFF `value` != buffer[index]. @@ -1552,7 +1552,7 @@ void BinaryNode::set_value( double value, std::optional> slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); // We expect `value` to obey the index-wise bounds and to be an integer. assert(lower_bound(index) <= value); assert(upper_bound(index) >= value); @@ -1576,7 +1576,7 @@ void BinaryNode::flip( ssize_t index, std::optional> slices ) const { - auto state_data = data_ptr(state); + auto state_data = data_ptr_(state); // Variable should not be fixed. assert(lower_bound(index) != upper_bound(index)); // assert() that `index` is valid occurs in ptr->set(). @@ -1600,7 +1600,7 @@ ssize_t BinaryNode::num_true( const ssize_t sum_constraint, const ssize_t slice ) const { - const auto& indices = data_ptr(state)->slice_indices; + const auto& indices = data_ptr_(state)->slice_indices; assert(0 <= sum_constraint && sum_constraint < static_cast(indices.size())); assert(0 <= slice && slice < static_cast(indices[sum_constraint].num_true.size())); return indices[sum_constraint].num_true[slice]; @@ -1611,7 +1611,7 @@ ssize_t BinaryNode::num_false( const ssize_t sum_constraint, const ssize_t slice ) const { - const auto& indices = data_ptr(state)->slice_indices; + const auto& indices = data_ptr_(state)->slice_indices; assert(0 <= sum_constraint && sum_constraint < static_cast(indices.size())); assert(0 <= slice && slice < static_cast(indices[sum_constraint].num_true.size())); const ssize_t num_indices = indices[sum_constraint].dense_sets[slice].size(); @@ -1624,7 +1624,7 @@ ssize_t BinaryNode::ith_true_index( const ssize_t slice, const ssize_t i ) const { - const auto& indices = data_ptr(state)->slice_indices; + const auto& indices = data_ptr_(state)->slice_indices; assert(0 <= sum_constraint && sum_constraint < static_cast(indices.size())); assert(0 <= slice && slice < static_cast(indices[sum_constraint].dense_sets.size())); assert(0 <= i && i < num_true(state, sum_constraint, slice)); @@ -1640,7 +1640,7 @@ ssize_t BinaryNode::ith_false_index( const ssize_t slice, const ssize_t i ) const { - const auto& indices = data_ptr(state)->slice_indices; + const auto& indices = data_ptr_(state)->slice_indices; assert(0 <= sum_constraint && sum_constraint < static_cast(indices.size())); const ssize_t num_true = this->num_true(state, sum_constraint, slice); assert(0 <= slice && slice < static_cast(indices[sum_constraint].dense_sets.size())); diff --git a/dwave/optimization/src/nodes/quadratic_model.cpp b/dwave/optimization/src/nodes/quadratic_model.cpp index 90ff74a6..b31e21d5 100644 --- a/dwave/optimization/src/nodes/quadratic_model.cpp +++ b/dwave/optimization/src/nodes/quadratic_model.cpp @@ -286,30 +286,30 @@ QuadraticModelNode::QuadraticModelNode( } quadratic_model_.shrink_to_fit(); - Node::add_predecessor(state_node_ptr); + Node::add_predecessor_(state_node_ptr); } double const* QuadraticModelNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } std::span QuadraticModelNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void QuadraticModelNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } void QuadraticModelNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } void QuadraticModelNode::initialize_state(State& state) const { Array* ptr = dynamic_cast(predecessors()[0]); std::vector state_copy(ptr->begin(state), ptr->end(state)); double value = quadratic_model_.compute_value(state_copy); - emplace_data_ptr( + emplace_data_ptr_( state, value, std::move(state_copy), quadratic_model_.num_variables() ); } @@ -318,7 +318,7 @@ void QuadraticModelNode::propagate(State& state) const { auto state_node_ptr = dynamic_cast(predecessors()[0]); auto diff = state_node_ptr->diff(state); if (diff.size()) { - auto node_data_ptr = data_ptr(state); + auto node_data_ptr = data_ptr_(state); auto& previous_state = node_data_ptr->previous_state_; auto& effective_changes = node_data_ptr->effective_changes_; auto& value = node_data_ptr->value; diff --git a/dwave/optimization/src/nodes/reduce.cpp b/dwave/optimization/src/nodes/reduce.cpp index 08f4901c..487c5ee7 100644 --- a/dwave/optimization/src/nodes/reduce.cpp +++ b/dwave/optimization/src/nodes/reduce.cpp @@ -807,7 +807,7 @@ ReduceNode::ReduceNode( axes_(normalize_axes(array_ptr, axes)), values_info_(values_info(array_ptr_, axes_, initial)), sizeinfo_(reducenode_calculate_sizeinfo(this, array_ptr_, axes_)) { - add_predecessor(array_ptr); + add_predecessor_(array_ptr); } template @@ -820,17 +820,17 @@ ReduceNode::ReduceNode( template double const* ReduceNode::buff(const State& state) const { - return data_ptr>(state)->buff(); + return data_ptr_>(state)->buff(); } template void ReduceNode::commit(State& state) const { - return data_ptr>(state)->commit(); + return data_ptr_>(state)->commit(); } template std::span ReduceNode::diff(const State& state) const { - return data_ptr>(state)->diff(); + return data_ptr_>(state)->diff(); } template @@ -846,12 +846,12 @@ void ReduceNode::initialize_state(State& state) const { reductions.emplace_back(reduce_(state, index)); } - emplace_data_ptr>(state, std::move(reductions), this->shape()); + emplace_data_ptr_>(state, std::move(reductions), this->shape()); } else { for (ssize_t index = 0; index < this->size(); ++index) { reductions.emplace_back(reduce_(state, index)); } - emplace_data_ptr>(state, std::move(reductions)); + emplace_data_ptr_>(state, std::move(reductions)); } } @@ -944,7 +944,7 @@ ssize_t ReduceNode::convert_predecessor_index_(ssize_t index) const { template void ReduceNode::propagate(State& state) const { - auto* const state_ptr = data_ptr>(state); + auto* const state_ptr = data_ptr_>(state); // We are reducing over all axes, so this is nice and simple if (axes_.empty() or axes_.size() == static_cast(array_ptr_->ndim())) { @@ -1068,25 +1068,25 @@ auto ReduceNode::reduce_(const State& state, const ssize_t index) cons template void ReduceNode::revert(State& state) const { - return data_ptr>(state)->revert(); + return data_ptr_>(state)->revert(); } template std::span ReduceNode::shape(const State& state) const { if (ssize_t size = this->size(); size >= 0) return this->shape(); // if we're not dynamic - return data_ptr>(state)->shape(); + return data_ptr_>(state)->shape(); } template ssize_t ReduceNode::size(const State& state) const { if (ssize_t size = this->size(); size >= 0) return size; // if we're not dynamic - return data_ptr>(state)->size(); + return data_ptr_>(state)->size(); } template ssize_t ReduceNode::size_diff(const State& state) const { if (ssize_t size = this->size(); size >= 0) return 0; // if we're not dynamic - return data_ptr>(state)->size_diff(); + return data_ptr_>(state)->size_diff(); } template class ReduceNode>; diff --git a/dwave/optimization/src/nodes/set_routines.cpp b/dwave/optimization/src/nodes/set_routines.cpp index f7af1f08..a15301a4 100644 --- a/dwave/optimization/src/nodes/set_routines.cpp +++ b/dwave/optimization/src/nodes/set_routines.cpp @@ -70,15 +70,15 @@ IsInNode::IsInNode(ArrayNode* element_ptr, ArrayNode* test_elements_ptr) : ArrayOutputMixin(element_ptr->shape()), element_ptr_(element_ptr), test_elements_ptr_(test_elements_ptr) { - add_predecessor(element_ptr); - add_predecessor(test_elements_ptr); + add_predecessor_(element_ptr); + add_predecessor_(test_elements_ptr); } double const* IsInNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -bool set_data_is_correct(State& state, const Array *element_ptr, IsInNodeData& node_data) { +bool set_data_is_correct(State& state, const Array* element_ptr, IsInNodeData& node_data) { for (ssize_t i = 0, stop = element_ptr->size(state); i < stop; ++i) { const double value = element_ptr->view(state)[i]; @@ -95,8 +95,8 @@ bool set_data_is_correct(State& state, const Array *element_ptr, IsInNodeData& n return true; } -void IsInNode::commit(State &state) const { - IsInNodeData *node_data = data_ptr(state); +void IsInNode::commit(State& state) const { + IsInNodeData* node_data = data_ptr_(state); node_data->element_updates.clear(); node_data->test_element_updates.clear(); node_data->commit(); @@ -104,7 +104,7 @@ void IsInNode::commit(State &state) const { } std::span IsInNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void IsInNode::initialize_state(State& state) const { @@ -112,7 +112,7 @@ void IsInNode::initialize_state(State& state) const { std::vector test_elements( test_elements_ptr_->begin(state), test_elements_ptr_->end(state) ); - emplace_data_ptr(state, std::move(element), std::move(test_elements)); + emplace_data_ptr_(state, std::move(element), std::move(test_elements)); } bool IsInNode::integral() const { return true; } // All values are true/false @@ -149,7 +149,7 @@ void IsInNode::propagate(State& state) const { return; // Nothing to do } - IsInNodeData* node_data = data_ptr(state); + IsInNodeData* node_data = data_ptr_(state); // Save a copy of the updates for IsInNode::revert() node_data->test_element_updates.assign(test_elements_diff.begin(), test_elements_diff.end()); @@ -231,7 +231,7 @@ void IsInNode::propagate(State& state) const { } void IsInNode::revert(State& state) const { - IsInNodeData* node_data = data_ptr(state); + IsInNodeData* node_data = data_ptr_(state); // Revert the changes to `test_elements` for (const Update& update : node_data->test_element_updates | std::views::reverse) { @@ -271,10 +271,10 @@ std::span IsInNode::shape(const State& state) const { return element_ptr_->shape(state); } -ssize_t IsInNode::size(const State& state) const { return data_ptr(state)->size(); } +ssize_t IsInNode::size(const State& state) const { return data_ptr_(state)->size(); } ssize_t IsInNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo IsInNode::sizeinfo() const { return element_ptr_->sizeinfo(); } diff --git a/dwave/optimization/src/nodes/softmax.cpp b/dwave/optimization/src/nodes/softmax.cpp index d8d90d27..dce5136a 100644 --- a/dwave/optimization/src/nodes/softmax.cpp +++ b/dwave/optimization/src/nodes/softmax.cpp @@ -59,23 +59,23 @@ struct SoftMaxNodeStateData : public ArrayNodeStateData { SoftMaxNode::SoftMaxNode(ArrayNode* arr_ptr) : ArrayOutputMixin(arr_ptr->shape()), arr_ptr_(arr_ptr), sizeinfo_(arr_ptr_->sizeinfo()) { - add_predecessor(arr_ptr); + add_predecessor_(arr_ptr); } double const* SoftMaxNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } void SoftMaxNode::commit(State& state) const { - return data_ptr(state)->commit(); + return data_ptr_(state)->commit(); } std::span SoftMaxNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void SoftMaxNode::initialize_state(State& state) const { - emplace_data_ptr( + emplace_data_ptr_( state, std::vector{arr_ptr_->begin(state), arr_ptr_->end(state)} ); } @@ -96,7 +96,7 @@ void SoftMaxNode::propagate(State& state) const { } // To update node, we need to compute the new softmax denominator - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); const double prior_denominator = node_data->denominator; double new_denominator = prior_denominator; // We only want to compute an exponential once per index @@ -140,7 +140,7 @@ void SoftMaxNode::propagate(State& state) const { } void SoftMaxNode::revert(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->revert(); // Manually reset denominator node_data->denominator = node_data->prior_denominator; @@ -151,11 +151,11 @@ std::span SoftMaxNode::shape(const State& state) const { } ssize_t SoftMaxNode::size(const State& state) const { - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } ssize_t SoftMaxNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo SoftMaxNode::sizeinfo() const { return this->sizeinfo_; } diff --git a/dwave/optimization/src/nodes/sorting.cpp b/dwave/optimization/src/nodes/sorting.cpp index d3b747f3..28131562 100644 --- a/dwave/optimization/src/nodes/sorting.cpp +++ b/dwave/optimization/src/nodes/sorting.cpp @@ -58,21 +58,21 @@ ArgSortNode::ArgSortNode(ArrayNode* arr_ptr) : ) ), sizeinfo_(arr_ptr_->sizeinfo()) { - add_predecessor(arr_ptr); + add_predecessor_(arr_ptr); } double const* ArgSortNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } -void ArgSortNode::commit(State& state) const { data_ptr(state)->commit(); } +void ArgSortNode::commit(State& state) const { data_ptr_(state)->commit(); } std::span ArgSortNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } void ArgSortNode::initialize_state(State& state) const { - emplace_data_ptr( + emplace_data_ptr_( state, std::vector{arr_ptr_->begin(state), arr_ptr_->end(state)} ); } @@ -84,7 +84,7 @@ double ArgSortNode::min() const { return minmax_.first; } double ArgSortNode::max() const { return minmax_.second; } void ArgSortNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); auto pred_diff = arr_ptr_->diff(state); @@ -113,7 +113,7 @@ void ArgSortNode::propagate(State& state) const { } void ArgSortNode::revert(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); // Revert the changes to `order` by going over the predecessor's previous updates in reverse for (const Update& update : node_data->predecessor_updates | std::views::reverse) { @@ -134,11 +134,11 @@ std::span ArgSortNode::shape(const State& state) const { } ssize_t ArgSortNode::size(const State& state) const { - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } ssize_t ArgSortNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } SizeInfo ArgSortNode::sizeinfo() const { return this->sizeinfo_; } diff --git a/dwave/optimization/src/nodes/statistics.cpp b/dwave/optimization/src/nodes/statistics.cpp index 9283bfbc..341fdc21 100644 --- a/dwave/optimization/src/nodes/statistics.cpp +++ b/dwave/optimization/src/nodes/statistics.cpp @@ -41,7 +41,7 @@ MeanNode::MeanNode(ArrayNode* arr_ptr) : ScalarOutputMixin(), arr_ptr_(arr_ptr), minmax_(calculate_values_minmax_(arr_ptr_)) { - add_predecessor(arr_ptr); + add_predecessor_(arr_ptr); } void MeanNode::initialize_state(State& state) const { @@ -82,7 +82,7 @@ void MeanNode::propagate(State& state) const { const ssize_t state_size_prior = state_size - arr_ptr_->size_diff(state); // Compute the sum of ArrayNode prior to change - double sum = data_ptr(state)->update.value * + double sum = data_ptr_(state)->update.value * static_cast(state_size_prior); for (const Update& u : arr_updates) { diff --git a/dwave/optimization/src/nodes/testing.cpp b/dwave/optimization/src/nodes/testing.cpp index 3ebddcfa..369ddef7 100644 --- a/dwave/optimization/src/nodes/testing.cpp +++ b/dwave/optimization/src/nodes/testing.cpp @@ -75,11 +75,11 @@ ArrayValidationNode::ArrayValidationNode(ArrayNode* node_ptr) : array_ptr(node_p assert(node_ptr->sizeinfo() == node_ptr->sizeinfo().substitute(100)); - add_predecessor(node_ptr); + add_predecessor_(node_ptr); } void ArrayValidationNode::commit(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); assert(array_ptr->diff(state).size() == 0); assert(array_ptr->size_diff(state) == 0); assert(array_ptr->size(state) == static_cast(node_data->current_data.size())); @@ -89,7 +89,7 @@ void ArrayValidationNode::commit(State& state) const { } void ArrayValidationNode::initialize_state(State& state) const { - emplace_data_ptr(state, array_ptr->view(state)); + emplace_data_ptr_(state, array_ptr->view(state)); assert(array_ptr->diff(state).size() == 0); assert(array_ptr->size_diff(state) == 0); assert(static_cast(array_ptr->view(state).size()) == array_ptr->size(state)); @@ -113,7 +113,7 @@ void ArrayValidationNode::initialize_state(State& state) const { } void ArrayValidationNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); std::string node_id = typeid(*array_ptr).name() + std::string{"["} + std::to_string(array_ptr->topological_index()) + std::string{"]"}; @@ -248,7 +248,7 @@ void ArrayValidationNode::propagate(State& state) const { } void ArrayValidationNode::revert(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); assert(array_ptr->diff(state).size() == 0); assert(array_ptr->size_diff(state) == 0); assert(array_ptr->size(state) == static_cast(node_data->old_data.size())); @@ -373,27 +373,27 @@ void DynamicArrayTestingNode::initialize_state(State& state, std::span 0); shape[0] = values.size() / (strides()[0] / itemsize()); - emplace_data_ptr(state, shape, values); + emplace_data_ptr_(state, shape, values); } double const* DynamicArrayTestingNode::buff(const State& state) const noexcept { - return data_ptr(state)->current_data.data(); + return data_ptr_(state)->current_data.data(); } std::span DynamicArrayTestingNode::diff(const State& state) const { - return data_ptr(state)->diff; + return data_ptr_(state)->diff; } ssize_t DynamicArrayTestingNode::size(const State& state) const { - return data_ptr(state)->current_data.size(); + return data_ptr_(state)->current_data.size(); } std::span DynamicArrayTestingNode::shape(const State& state) const { - return data_ptr(state)->shape(); + return data_ptr_(state)->shape(); } ssize_t DynamicArrayTestingNode::size_diff(const State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); return node_data->current_data.size() - node_data->old_data.size(); } @@ -411,11 +411,11 @@ double DynamicArrayTestingNode::max() const { SizeInfo DynamicArrayTestingNode::sizeinfo() const { return sizeinfo_.value_or(SizeInfo(this)); } void DynamicArrayTestingNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } void DynamicArrayTestingNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } void DynamicArrayTestingNode::update(State&, int) const {} @@ -428,19 +428,19 @@ void DynamicArrayTestingNode::grow(State& state, std::span values) assert(ndim() >= 1); assert(values.size() % (strides()[0] / itemsize()) == 0); - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); node_data->grow(values); node_data->current_shape[0] += values.size() / (strides()[0] / itemsize()); } void DynamicArrayTestingNode::set(State& state, ssize_t index, double value) const { - data_ptr(state)->set(index, value); + data_ptr_(state)->set(index, value); } void DynamicArrayTestingNode::shrink(State& state) const { if (!size(state)) return; // nothing to do const ssize_t row_size = strides()[0] / itemsize(); - data_ptr(state)->shrink(row_size); + data_ptr_(state)->shrink(row_size); } } // namespace dwave::optimization diff --git a/dwave/optimization/src/nodes/unaryop.cpp b/dwave/optimization/src/nodes/unaryop.cpp index fbc44136..5aaae206 100644 --- a/dwave/optimization/src/nodes/unaryop.cpp +++ b/dwave/optimization/src/nodes/unaryop.cpp @@ -167,22 +167,22 @@ UnaryOpNode::UnaryOpNode(ArrayNode* node_ptr) : calculate_integral(array_ptr_) ), sizeinfo_(array_ptr_->sizeinfo()) { - add_predecessor(node_ptr); + add_predecessor_(node_ptr); } template void UnaryOpNode::commit(State& state) const { - data_ptr(state)->commit(); + data_ptr_(state)->commit(); } template double const* UnaryOpNode::buff(const State& state) const { - return data_ptr(state)->buff(); + return data_ptr_(state)->buff(); } template std::span UnaryOpNode::diff(const State& state) const { - return data_ptr(state)->diff(); + return data_ptr_(state)->diff(); } template @@ -193,7 +193,7 @@ void UnaryOpNode::initialize_state(State& state) const { values.emplace_back(op(val)); } - emplace_data_ptr(state, std::move(values)); + emplace_data_ptr_(state, std::move(values)); } template @@ -213,7 +213,7 @@ double UnaryOpNode::max() const { template void UnaryOpNode::propagate(State& state) const { - auto node_data = data_ptr(state); + auto node_data = data_ptr_(state); for (const auto& update : array_ptr_->diff(state)) { const auto& [idx, _, value] = update; @@ -234,7 +234,7 @@ void UnaryOpNode::propagate(State& state) const { template void UnaryOpNode::revert(State& state) const { - data_ptr(state)->revert(); + data_ptr_(state)->revert(); } template @@ -244,12 +244,12 @@ std::span UnaryOpNode::shape(const State& state) const { template ssize_t UnaryOpNode::size(const State& state) const { - return data_ptr(state)->size(); + return data_ptr_(state)->size(); } template ssize_t UnaryOpNode::size_diff(const State& state) const { - return data_ptr(state)->size_diff(); + return data_ptr_(state)->size_diff(); } template diff --git a/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml b/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml new file mode 100644 index 00000000..bb165083 --- /dev/null +++ b/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + Rename C++ ``Graph`` class's protected members to have a trailing underscore. + See `#398 `_. From 3c8068c15175a769053b22ad81b8b9a21d2d06fd Mon Sep 17 00:00:00 2001 From: Alexander Condello Date: Wed, 17 Jun 2026 11:59:26 -0700 Subject: [PATCH 3/5] Use and/not/or rather than &&/||/! in graph.hpp and graph.cpp --- .../include/dwave-optimization/graph.hpp | 22 ++++++------ dwave/optimization/src/graph.cpp | 36 +++++++++---------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/dwave/optimization/include/dwave-optimization/graph.hpp b/dwave/optimization/include/dwave-optimization/graph.hpp index 2fa0d1eb..df8f0e6d 100644 --- a/dwave/optimization/include/dwave-optimization/graph.hpp +++ b/dwave/optimization/include/dwave-optimization/graph.hpp @@ -333,7 +333,9 @@ class Node { /// Add a successor node. Adds itself to the successor as a predecessor. void add_successor_(Node* successor) { - assert(successor->topological_index_ <= 0 && "cannot add a topologically sorted successor"); + assert( + successor->topological_index_ <= 0 and "cannot add a topologically sorted successor" + ); this->successors_.emplace_back(successor, successor->predecessors_.size()); successor->predecessors_.emplace_back(this); } @@ -341,18 +343,18 @@ class Node { template StateData> StateData* data_ptr_(State& state) const { const ssize_t index = topological_index(); - assert(index >= 0 && "must be topologically sorted"); - assert(state.size() > static_cast(index) && "unexpected state length"); - assert(state[index] != nullptr && "uninitialized state"); + assert(index >= 0 and "must be topologically sorted"); + assert(state.size() > static_cast(index) and "unexpected state length"); + assert(state[index] != nullptr and "uninitialized state"); return static_cast(state[index].get()); } template StateData> const StateData* data_ptr_(const State& state) const { const ssize_t index = topological_index(); - assert(index >= 0 && "must be topologically sorted"); - assert(state.size() > static_cast(index) && "unexpected state length"); - assert(state[index] != nullptr && "uninitialized state"); + assert(index >= 0 and "must be topologically sorted"); + assert(state.size() > static_cast(index) and "unexpected state length"); + assert(state[index] != nullptr and "uninitialized state"); return static_cast(state[index].get()); } @@ -360,9 +362,9 @@ class Node { template StateData, class... Args> void emplace_data_ptr_(State& state, Args&&... args) const { const ssize_t index = topological_index(); - assert(index >= 0 && "must be topologically sorted"); - assert(state.size() > static_cast(index) && "unexpected state length"); - assert(state[index] == nullptr && "already initialized state"); + assert(index >= 0 and "must be topologically sorted"); + assert(state.size() > static_cast(index) and "unexpected state length"); + assert(state[index] == nullptr and "already initialized state"); state[index] = std::make_unique(std::forward(args)...); } diff --git a/dwave/optimization/src/graph.cpp b/dwave/optimization/src/graph.cpp index 89a194af..01a6b0bb 100644 --- a/dwave/optimization/src/graph.cpp +++ b/dwave/optimization/src/graph.cpp @@ -21,7 +21,7 @@ #include #include -#if defined(__has_include) && __has_include() +#if defined(__has_include) and __has_include() #define _HAS_CXXABI #include #endif @@ -31,7 +31,7 @@ namespace dwave::optimization { void Graph::add_constraint(ArrayNode* constraint_ptr) { - if (!constraint_ptr->logical()) { + if (not constraint_ptr->logical()) { throw std::invalid_argument("constraint must have a logical output"); } // todo: we could substitute an AND on the user's behalf, or we could allow @@ -60,7 +60,7 @@ void Graph::commit(State& state, std::span changed) const { assert(([&state, &changed]() -> bool { for (const Node* n_ptr : changed) { if (dynamic_cast(n_ptr) == nullptr) continue; - if (!dynamic_cast(n_ptr)->diff(state).empty()) return false; + if (not dynamic_cast(n_ptr)->diff(state).empty()) return false; } return true; })()); @@ -122,7 +122,7 @@ double Graph::energy(const State& state) const { bool Graph::feasible(const State& state) const { for (const Array* ptr : constraints_) { assert(ptr->size(state) == 1); - if (!(ptr->view(state)[0])) return false; + if (not(ptr->view(state)[0])) return false; } return true; } @@ -139,8 +139,8 @@ State Graph::initialize_state() { } void Graph::initialize_state(State& state) const { - assert(static_cast(state.size()) == num_nodes() && "unexpected state length"); - assert(topologically_sorted_ && "graph must be topologically sorted"); + assert(static_cast(state.size()) == num_nodes() and "unexpected state length"); + assert(topologically_sorted_ and "graph must be topologically sorted"); for (int i = 0, end = num_nodes(); i < end; ++i) { if (state[i]) continue; // should this clear any pending changes? @@ -228,7 +228,7 @@ void Graph::recursive_reset(State& state, const Node* ptr) { } // We've already been reset so nothing to do - if (!state[index]) return; + if (not state[index]) return; // Otherwise, reset our own state and then all of our successors state[index].reset(); @@ -263,13 +263,13 @@ ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { } // as is the objective if it exists - if (objective_ptr_ && objective_ptr_->topological_index_ >= num_decisions) { + if (objective_ptr_ and objective_ptr_->topological_index_ >= num_decisions) { objective_ptr_->topological_index_ = keep; } // If we're not ignoring listeners, we check if anyone is "listening" to // the expired_ptr_. If so, we keep the node. - if (!ignore_listeners) { + if (not ignore_listeners) { for (auto& ptr : nodes_ | std::views::drop(num_decisions)) { if (ptr->expired_ptr_.use_count() > 1) ptr->topological_index_ = keep; } @@ -279,7 +279,7 @@ ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { // Now walk backwards through the topologically sorted node list // removing any nodes with no successors that we haven't marked. for (auto& ptr : nodes_ | std::views::drop(num_decisions) | std::views::reverse) { - if (!ptr->removable_()) continue; // some nodes can never be removed + if (not ptr->removable_()) continue; // some nodes can never be removed if (ptr->topological_index_ == keep) continue; // we marked these to keep if (ptr->successors().size() > 0) continue; // this node is used by other nodes @@ -297,7 +297,7 @@ ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { } // Traverse the nodes_ one last time removing any nullptrs we created - std::erase_if(nodes_, [](const auto& ptr) { return !ptr; }); + std::erase_if(nodes_, [](const auto& ptr) { return not ptr; }); // Undo all of the weird stuff we did with the topological indices reset_topological_sort(); @@ -307,7 +307,7 @@ ssize_t Graph::remove_unused_nodes(bool ignore_listeners) { } void Graph::reset_topological_sort() { - if (!topologically_sorted_) return; // already unsorted + if (not topologically_sorted_) return; // already unsorted // The decisions must have a consistent topological index, so we don't reset them std::for_each( @@ -338,7 +338,7 @@ void Graph::revert(State& state, std::span changed) const { assert(([&state, &changed]() -> bool { for (const Node* n_ptr : changed) { if (dynamic_cast(n_ptr) == nullptr) continue; - if (!dynamic_cast(n_ptr)->diff(state).empty()) return false; + if (not dynamic_cast(n_ptr)->diff(state).empty()) return false; } return true; })()); @@ -350,7 +350,7 @@ void Graph::revert(State& state, std::vector&& changed) const { void Graph::set_objective(ArrayNode* objective_ptr) { // nullptr is an unset objective, so we allow it. - if (objective_ptr != nullptr && objective_ptr->size() != 1) { + if (objective_ptr != nullptr and objective_ptr->size() != 1) { throw std::invalid_argument("objective must have a single output"); } this->objective_ptr_ = objective_ptr; @@ -370,7 +370,7 @@ void Graph::topological_sort() { if (n_ptr->topological_index_ == -2) throw std::logic_error("has cycles"); // decisions should already be sorted - assert(dynamic_cast(n_ptr) == nullptr && "unsorted decisions node"); + assert(dynamic_cast(n_ptr) == nullptr and "unsorted decisions node"); n_ptr->topological_index_ = -2; @@ -407,9 +407,9 @@ void Graph::topological_sort() { } void Node::initialize_state(State& state) const { - assert(topological_index_ >= 0 && "must be topologically sorted"); - assert(static_cast(state.size()) > topological_index_ && "unexpected state length"); - assert(state[topological_index_] == nullptr && "already initialized state"); + assert(topological_index_ >= 0 and "must be topologically sorted"); + assert(static_cast(state.size()) > topological_index_ and "unexpected state length"); + assert(state[topological_index_] == nullptr and "already initialized state"); state[topological_index_] = std::make_unique(); } From 6c903bd7407cbe652957ea5f3e0ba9d472318340 Mon Sep 17 00:00:00 2001 From: Alexander Condello Date: Wed, 17 Jun 2026 12:34:54 -0700 Subject: [PATCH 4/5] Remove unused Graph::add_successor() method --- dwave/optimization/include/dwave-optimization/graph.hpp | 9 --------- .../cpp-graph-protected-members-717df2da46c2db7f.yaml | 2 ++ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/dwave/optimization/include/dwave-optimization/graph.hpp b/dwave/optimization/include/dwave-optimization/graph.hpp index df8f0e6d..8496b771 100644 --- a/dwave/optimization/include/dwave-optimization/graph.hpp +++ b/dwave/optimization/include/dwave-optimization/graph.hpp @@ -331,15 +331,6 @@ class Node { this->predecessors_.emplace_back(predecessor); } - /// Add a successor node. Adds itself to the successor as a predecessor. - void add_successor_(Node* successor) { - assert( - successor->topological_index_ <= 0 and "cannot add a topologically sorted successor" - ); - this->successors_.emplace_back(successor, successor->predecessors_.size()); - successor->predecessors_.emplace_back(this); - } - template StateData> StateData* data_ptr_(State& state) const { const ssize_t index = topological_index(); diff --git a/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml b/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml index bb165083..6a718e92 100644 --- a/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml +++ b/releasenotes/notes/cpp-graph-protected-members-717df2da46c2db7f.yaml @@ -3,3 +3,5 @@ upgrade: - | Rename C++ ``Graph`` class's protected members to have a trailing underscore. See `#398 `_. + - | + Remove C++ ``Graph::add_successor()`` method \ No newline at end of file From 5dacdff66b53e75d512991ab5ff59e4fa499a97a Mon Sep 17 00:00:00 2001 From: Alexander Condello Date: Thu, 18 Jun 2026 15:03:00 -0700 Subject: [PATCH 5/5] Fix docstring format Co-authored-by: William Bernoudy --- dwave/optimization/include/dwave-optimization/graph.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwave/optimization/include/dwave-optimization/graph.hpp b/dwave/optimization/include/dwave-optimization/graph.hpp index 8496b771..ad7681e5 100644 --- a/dwave/optimization/include/dwave-optimization/graph.hpp +++ b/dwave/optimization/include/dwave-optimization/graph.hpp @@ -187,8 +187,8 @@ class Graph { /// ordering. void topological_sort(); - // Whether or not the model is currently topologically sorted. - // Models that are topologically sorted cannot be modified. + /// Whether or not the model is currently topologically sorted. + /// Models that are topologically sorted cannot be modified. bool topologically_sorted() const noexcept { return topologically_sorted_; } private: