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_ofstream.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_ofstream 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
202 // Remove copy construction
203 builder(const builder&) = delete;
204
205 // Remove move construction
206 builder(builder&&) = delete;
207
213
214 public:
241 add_node(typename Policy::label_type label,
244 {
245 attach_if_needed();
246
247 // Check validity of input
248 if (low.builder_ref != builder_ref || high.builder_ref != builder_ref) {
249 throw invalid_argument("Cannot use pointers from a different builder");
250 }
251 if (label > Policy::max_label) { throw invalid_argument("Nodes must have a valid label"); }
252 if (label > current_label) { throw invalid_argument("Nodes must be added bottom-up"); }
253 if (low.uid.is_node() && low.uid.label() <= label) {
254 throw invalid_argument("Low child must point to a node with higher label");
255 }
256 if (high.uid.is_node() && high.uid.label() <= label) {
257 throw invalid_argument("High child must point to a node with higher label");
258 }
259
260 // Update label and ID if necessary
261 if (label < current_label) {
262 current_label = label;
263 current_id = Policy::max_id;
264 }
265
266 // Create potential node
267 const node_type n(label, current_id, low.uid, high.uid);
268
269 // Check whether this node is 'redundant'
270 const typename node_type::uid_type res_uid = Policy::reduction_rule(n);
271
272 if (res_uid.is_terminal()) {
273 created_terminal = true;
274 terminal_val = res_uid.value();
275 }
276
277 if (res_uid == low.uid) { return low; }
278 if (res_uid == high.uid) { return high; }
279
280 // Push node to file
281 nw.push(n);
282 unref_nodes++;
283 current_id--;
284
285 // Update count of unreferenced nodes
286 bool& low_unref = *low.unreferenced;
287 if (low_unref && !low.uid.is_terminal()) {
288 low_unref = false;
289 unref_nodes--;
290 }
291
292 bool& high_unref = *high.unreferenced;
293 if (high_unref && !high.uid.is_terminal()) {
294 high_unref = false;
295 unref_nodes--;
296 }
297
298 return make_ptr(res_uid);
299 }
300
319 add_node(const typename Policy::label_type label,
320 const bool low,
322 {
323 attach_if_needed();
324
325 builder_ptr<Policy> low_ptr = make_ptr(typename node_type::pointer_type(low));
326 return add_node(label, low_ptr, high);
327 }
328
347 add_node(const typename Policy::label_type label,
349 const bool high)
350 {
351 attach_if_needed();
352
353 builder_ptr<Policy> high_ptr = make_ptr(typename node_type::pointer_type(high));
354 return add_node(label, low, high_ptr);
355 }
356
374 add_node(const typename Policy::label_type label, const bool low, const bool high)
375 {
376 attach_if_needed();
377
378 builder_ptr<Policy> low_ptr = make_ptr(typename node_type::pointer_type(low));
379 builder_ptr<Policy> high_ptr = make_ptr(typename node_type::pointer_type(high));
380 return add_node(label, low_ptr, high_ptr);
381 }
382
394 {
395 attach_if_needed();
396
397 created_terminal = true;
398 terminal_val = terminal_value;
399
400 return make_ptr(typename node_type::pointer_type(terminal_value));
401 }
402
419 typename Policy::dd_type
421 {
422 attach_if_needed();
423
424 if (!nw.has_pushed()) {
425 if (created_terminal) {
426 nw.push(node_type(terminal_val));
427 } else {
428 throw domain_error("There must be at least one node or terminal in the decision diagram");
429 }
430 }
431 nw.close();
432
433 if (unref_nodes > 1) { throw domain_error("Decision diagram has more than one root"); }
434
435 const typename Policy::dd_type res(nf);
436 close();
437 return res;
438 }
439
447 void
449 {
450 close();
451 }
452
453 private:
457 inline void
458 attach_if_needed() noexcept
459 {
460 if (nf) { return; }
461
462 adiar_assert(!nw.is_open(),
463 "`nw`'s attachment should be consistent with existence of `nf`");
464
465 // Initialise file
466 nf = internal::make_shared_levelized_file<node_type>();
467 nw.open(nf);
468
469 // Initialise state variables
470 current_label = Policy::max_label;
471 current_id = Policy::max_id;
472 created_terminal = false;
473 terminal_val = false;
474 unref_nodes = 0;
475
476 // Initialise shared builder reference.
477 builder_ref = make_shared<builder_shared>();
478 }
479
483 inline void
484 close() noexcept
485 {
486 nw.close();
487 nf.reset();
488 }
489
494 make_ptr(const typename node_type::pointer_type& p) noexcept
495 {
496 return builder_ptr<Policy>(p, builder_ref);
497 }
498 };
499
506
513
516}
517
518#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:347
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:374
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:448
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:241
~builder() noexcept
Destructor.
Definition builder.h:211
builder_ptr< Policy > add_node(bool terminal_value)
Add a terminal node with a given value.
Definition builder.h:393
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:319
Policy::dd_type build()
Builds the decision diagram with the added nodes. This also clears the builder.
Definition builder.h:420
consumer< ValueType > make_consumer(OutputIt &&iter)
Wrap an iterator into a consumer function.
Definition functional.h:71
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