Adiar 2.1.0
An External Memory Decision Diagram Library
Loading...
Searching...
No Matches
builder.h
1#ifndef ADIAR_BUILDER_H
2#define ADIAR_BUILDER_H
3
4#include <adiar/bdd/bdd_policy.h>
5#include <adiar/exception.h>
6#include <adiar/zdd/zdd_policy.h>
7
8#include <adiar/internal/assert.h>
9#include <adiar/internal/data_types/node.h>
10#include <adiar/internal/data_types/uid.h>
11#include <adiar/internal/io/node_file.h>
12#include <adiar/internal/io/node_writer.h>
13#include <adiar/internal/memory.h>
14
25
26namespace adiar
27{
32
39 struct builder_shared
40 {};
42
43 template <typename dd_policy>
44 class builder;
45
52 template <typename Policy>
54 {
55 public:
56 friend class builder<Policy>;
57
58 private:
62 // TODO: rename to 'ptr ptr' when using complement edges
63 /*const*/ internal::node::uid_type uid;
64
68 /*const*/ shared_ptr<const builder_shared> builder_ref;
69
74 /*const*/ shared_ptr<bool> unreferenced = make_shared<bool>(true);
75
76 public:
80 builder_ptr() = default;
81
85 builder_ptr(const builder_ptr& bp) = default;
86
91
92 public:
97 operator=(const builder_ptr& bp) = default;
98
104
105 private:
115 builder_ptr(const internal::node::uid_type& p, const shared_ptr<const builder_shared>& sp)
116 : uid(p)
117 , builder_ref(sp)
118 {}
119 };
120
127
134
144 template <typename Policy>
146 {
147 private:
148 // See 'attach_if_needed()' for default values of most values below.
149
153 using node_type = typename Policy::node_type;
154
159
163 internal::node_writer nw;
164
168 bool created_terminal;
169
173 bool terminal_val;
174
178 typename Policy::label_type current_label;
179
183 typename Policy::id_type current_id;
184
188 size_t unref_nodes;
189
193 shared_ptr<builder_shared> builder_ref;
194
195 public:
201
207
208 public:
235 add_node(typename Policy::label_type label,
238 {
239 attach_if_needed();
240
241 // Check validity of input
242 if (low.builder_ref != builder_ref || high.builder_ref != builder_ref) {
243 throw invalid_argument("Cannot use pointers from a different builder");
244 }
245 if (label > Policy::max_label) { throw invalid_argument("Nodes must have a valid label"); }
246 if (label > current_label) { throw invalid_argument("Nodes must be added bottom-up"); }
247 if (low.uid.is_node() && low.uid.label() <= label) {
248 throw invalid_argument("Low child must point to a node with higher label");
249 }
250 if (high.uid.is_node() && high.uid.label() <= label) {
251 throw invalid_argument("High child must point to a node with higher label");
252 }
253
254 // Update label and ID if necessary
255 if (label < current_label) {
256 current_label = label;
257 current_id = Policy::max_id;
258 }
259
260 // Create potential node
261 const node_type n(label, current_id, low.uid, high.uid);
262
263 // Check whether this node is 'redundant'
264 const typename node_type::uid_type res_uid = Policy::reduction_rule(n);
265
266 if (res_uid.is_terminal()) {
267 created_terminal = true;
268 terminal_val = res_uid.value();
269 }
270
271 if (res_uid == low.uid) { return low; }
272 if (res_uid == high.uid) { return high; }
273
274 // Push node to file
275 nw.push(n);
276 unref_nodes++;
277 current_id--;
278
279 // Update count of unreferenced nodes
280 bool& low_unref = *low.unreferenced;
281 if (low_unref && !low.uid.is_terminal()) {
282 low_unref = false;
283 unref_nodes--;
284 }
285
286 bool& high_unref = *high.unreferenced;
287 if (high_unref && !high.uid.is_terminal()) {
288 high_unref = false;
289 unref_nodes--;
290 }
291
292 return make_ptr(res_uid);
293 }
294
313 add_node(const typename Policy::label_type label,
314 const bool low,
316 {
317 attach_if_needed();
318
319 builder_ptr<Policy> low_ptr = make_ptr(typename node_type::pointer_type(low));
320 return add_node(label, low_ptr, high);
321 }
322
341 add_node(const typename Policy::label_type label,
343 const bool high)
344 {
345 attach_if_needed();
346
347 builder_ptr<Policy> high_ptr = make_ptr(typename node_type::pointer_type(high));
348 return add_node(label, low, high_ptr);
349 }
350
368 add_node(const typename Policy::label_type label, const bool low, const bool high)
369 {
370 attach_if_needed();
371
372 builder_ptr<Policy> low_ptr = make_ptr(typename node_type::pointer_type(low));
373 builder_ptr<Policy> high_ptr = make_ptr(typename node_type::pointer_type(high));
374 return add_node(label, low_ptr, high_ptr);
375 }
376
388 {
389 attach_if_needed();
390
391 created_terminal = true;
392 terminal_val = terminal_value;
393
394 return make_ptr(typename node_type::pointer_type(terminal_value));
395 }
396
413 typename Policy::dd_type
415 {
416 attach_if_needed();
417
418 if (!nw.has_pushed()) {
419 if (created_terminal) {
420 nw.push(node_type(terminal_val));
421 } else {
422 throw domain_error("There must be at least one node or terminal in the decision diagram");
423 }
424 }
425 nw.detach();
426
427 if (unref_nodes > 1) { throw domain_error("Decision diagram has more than one root"); }
428
429 const typename Policy::dd_type res(nf);
430 detach();
431 return res;
432 }
433
441 void
443 {
444 detach();
445 }
446
447 private:
451 inline void
452 attach_if_needed() noexcept
453 {
454 if (!nf) {
455 adiar_assert(!nw.attached(),
456 "`nw`'s attachment should be consistent with existence of `nf`");
457
458 // Initialise file
459 nf = internal::make_shared_levelized_file<node_type>();
460 nw.attach(nf);
461
462 // Initialise state variables
463 current_label = Policy::max_label;
464 current_id = Policy::max_id;
465 created_terminal = false;
466 terminal_val = false;
467 unref_nodes = 0;
468
469 // Initialise shared builder reference.
470 builder_ref = make_shared<builder_shared>();
471 }
472 }
473
477 inline void
478 detach() noexcept
479 {
480 nw.detach();
481 nf.reset();
482 }
483
488 make_ptr(const typename node_type::pointer_type& p) noexcept
489 {
490 return builder_ptr<Policy>(p, builder_ref);
491 }
492 };
493
500
507
510}
511
512#endif // ADIAR_BUILDER_H
The pointer type that builders use to identify the nodes they have constructed in a decision diagram.
Definition builder.h:54
builder_ptr()=default
Default construction for a pointer to null.
builder_ptr & operator=(const builder_ptr &bp)=default
Copy construction.
builder_ptr & operator=(builder_ptr &&bp)=default
Move construction.
builder_ptr(builder_ptr &&bp)=default
Move construction.
builder_ptr(const builder_ptr &bp)=default
Copy construction.
A builder for decision diagrams.
Definition builder.h:146
builder_ptr< Policy > add_node(const typename Policy::label_type label, const builder_ptr< Policy > &low, const bool high)
Add an internal node with a given label and its two children.
Definition builder.h:341
builder_ptr< Policy > add_node(const typename Policy::label_type label, const bool low, const bool high)
Add an internal node with a given label and its two children.
Definition builder.h:368
builder() noexcept
Constructor.
Definition builder.h:199
void clear() noexcept
Clear builder of all its current content, discarding all nodes and invalidating any pointers to them.
Definition builder.h:442
builder_ptr< Policy > add_node(typename Policy::label_type label, const builder_ptr< Policy > &low, const builder_ptr< Policy > &high)
Add an internal node with a given label and its two children.
Definition builder.h:235
~builder() noexcept
Destructor.
Definition builder.h:205
builder_ptr< Policy > add_node(bool terminal_value)
Add a terminal node with a given value.
Definition builder.h:387
builder_ptr< Policy > add_node(const typename Policy::label_type label, const bool low, const builder_ptr< Policy > &high)
Add an internal node with a given label and its two children.
Definition builder.h:313
Policy::dd_type build()
Builds the decision diagram with the added nodes. This also clears the builder.
Definition builder.h:414
consumer< ValueType > make_consumer(OutputIt &iter)
Wrap an iterator into a consumer function.
Definition functional.h:67
Core types.
Definition adiar.h:40
std::domain_error domain_error
Inputs for which an operation is undefined.
Definition exception.h:38
std::invalid_argument invalid_argument
Inputs that are invalid.
Definition exception.h:33
std::shared_ptr< T > shared_ptr
Shared ownership of an object on the heap. This smart pointer essentially provides a (thread-safe) re...
Definition memory.h:52