1. Your first circuit¶
Build the C package using the commands in the package README. Your application’s CMake file needs only:
find_package(tididi CONFIG REQUIRED)
target_link_libraries(your_program PRIVATE tididi::tididi)
We will represent (x ∧ y) ∨ z: either both x and y
are true, or z is true. A vtree groups the variables used by related circuits.
Here it contains three variables, numbered 1 through 3.
The examples use small helpers: check prints an error and stops on failure,
count queries the model count, and copy and release manage circuit
handles. Their definitions appear below.
Construct the three literals, then combine them. A final NULL means no
operation limits. Initialize every owned output pointer to NULL.
TididiVtree *vtree = NULL;
TididiCircuit *x = NULL, *y = NULL, *z = NULL;
TididiCircuit *xy = NULL, *formula = NULL;
check(tididi_vtree_balanced(3, &vtree));
check(tididi_literal(vtree, 1, &x, NULL));
check(tididi_literal(vtree, 2, &y, NULL));
check(tididi_literal(vtree, 3, &z, NULL));
check(tididi_and(x, y, &xy, NULL));
check(tididi_or(xy, z, &formula, NULL));
printf("Satisfying assignments: %" PRIu64 "\n", count(formula));
Output:
Satisfying assignments: 5
1.1. Keep a circuit for later¶
tididi_and consumes x and y; tididi_or then consumes xy
and z. To keep a circuit while transforming it, copy it first. Here the copy
is consumed by negation while the original formula remains available.
TididiCircuit *saved = copy(formula), *complement = NULL;
check(tididi_negate(saved, &complement, NULL));
printf("Original: %" PRIu64 "; complement: %" PRIu64 "\n",
count(formula), count(complement));
Output:
Original: 5; complement: 3
1.2. Release handles¶
Consumption moves the circuit out of its handle. The empty handle still needs
to be freed, along with the result handles. release calls
tididi_circuit_free and checks its result.
release(x); release(y); release(z); release(xy);
release(formula); release(saved); release(complement);
tididi_vtree_free(vtree);
1.3. Example helpers¶
These helpers call the public API directly. An application that handles errors locally can inspect the returned error instead of exiting; see Handle operation limits.
static inline void check(TididiError *error) {
if (error) {
fprintf(stderr, "%s\n", tididi_error_message(error));
tididi_error_free(error);
exit(EXIT_FAILURE);
}
}
static inline TididiCircuit *copy(const TididiCircuit *value) {
TididiCircuit *result = NULL;
check(tididi_copy(value, &result));
return result;
}
static inline void release(TididiCircuit *value) { check(tididi_circuit_free(value)); }
static inline uint64_t count(const TididiCircuit *value) {
uint64_t result = 0;
check(tididi_model_count(value, &result, NULL));
return result;
}
1.4. Complete program¶
Download first_circuit.c and the
shared helper. The source includes cleanup
for all handles. Both files are included in the source checkout.