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 (Complement Edges): Turn this into a `Policy::pointer_type`?
63 /*const*/ typename Policy::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 typename Policy::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 // TODO (Complement Edges): Turn this into a `Policy::pointer_type`?
271 const typename Policy::uid_type n_ptr = typename Policy::uid_type(Policy::reduction_rule(n));
272
273 if (n_ptr.is_terminal()) {
274 created_terminal = true;
275 terminal_val = n_ptr.value();
276 }
277
278 if (n_ptr == low.uid) { return low; }
279 if (n_ptr == high.uid) { return high; }
280
281 // Push node to file
282 nw.push(n);
283 unref_nodes++;
284 current_id--;
285
286 // Update count of unreferenced nodes
287 bool& low_unref = *low.unreferenced;
288 if (low_unref && !low.uid.is_terminal()) {
289 low_unref = false;
290 unref_nodes--;
291 }
292
293 bool& high_unref = *high.unreferenced;
294 if (high_unref && !high.uid.is_terminal()) {
295 high_unref = false;
296 unref_nodes--;
297 }
298
299 return make_ptr(n_ptr);
300 }
301
320 add_node(const typename Policy::label_type label,
321 const bool low,
323 {
324 attach_if_needed();
325
326 builder_ptr<Policy> low_ptr = make_ptr(typename Policy::uid_type(low));
327 return add_node(label, low_ptr, high);
328 }
329
348 add_node(const typename Policy::label_type label,
350 const bool high)
351 {
352 attach_if_needed();
353
354 builder_ptr<Policy> high_ptr = make_ptr(typename Policy::uid_type(high));
355 return add_node(label, low, high_ptr);
356 }
357
375 add_node(const typename Policy::label_type label, const bool low, const bool high)
376 {
377 attach_if_needed();
378
379 builder_ptr<Policy> low_ptr = make_ptr(typename Policy::uid_type(low));
380 builder_ptr<Policy> high_ptr = make_ptr(typename Policy::uid_type(high));
381 return add_node(label, low_ptr, high_ptr);
382 }
383
395 {
396 attach_if_needed();
397
398 created_terminal = true;
399 terminal_val = terminal_value;
400
401 return make_ptr(typename node_type::uid_type(terminal_value));
402 }
403
420 typename Policy::dd_type
422 {
423 attach_if_needed();
424
425 if (!nw.has_pushed()) {
426 if (created_terminal) {
427 nw.push(node_type(terminal_val));
428 } else {
429 throw domain_error("There must be at least one node or terminal in the decision diagram");
430 }
431 }
432 nw.close();
433
434 if (unref_nodes > 1) { throw domain_error("Decision diagram has more than one root"); }
435
436 const typename Policy::dd_type res(nf);
437 close();
438 return res;
439 }
440
448 void
450 {
451 close();
452 }
453
454 private:
458 inline void
459 attach_if_needed() noexcept
460 {
461 if (nf) { return; }
462
463 adiar_assert(!nw.is_open(), "`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 Policy::uid_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:348
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:375
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:449
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:394
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:320
Policy::dd_type build()
Builds the decision diagram with the added nodes. This also clears the builder.
Definition builder.h:421
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