============ Truth-tables ============ A :math:`k`-ary truth-table represents an operation :math:`f:V^k \to \mathsf{Power}(V)`, where :math:`V` is a a non-empty finite collection of values. For example, the truth-table for classical conjunction over the set of values :math:`\{\mathrm{F},\mathrm{T}\}` (which plays the role of :math:`V`) is presented below: .. list-table:: :widths: 10 10 10 :header-rows: 1 * - :math:`x` - :math:`y` - :math:`\land` * - F - F - F * - F - T - F * - T - F - F * - T - T - T In our library, each truth-table implements the interface :cpp:class:`ct4l::TruthTableI`, holding a non-negative integer indicating its arity, and a pointer to a :cpp:class:`ct4l::Domain`, intended to represent the collection :math:`V`. The template parameter determines what is the type of the values of the domain. Internally, only integers are stored and manipulated. To the user, we provide methods that allows to mention the domain values, but also the internal (integer) values. .. note:: We opted to use a pointer to a domain instead of a plain object envisioning the possibility of considering groups of truth-tables sharing the same domain (as is the case of truth-tables representing interpretations in an algebra). To facilitate the creation of truth-tables, however, we have provided constructors which takes concrete objects and deals internally with the conversion to a pointer type. The implementation of the truth-table interface provided for now follows the principles below: - instead of storing the truth-table mappings as correspondences between tuples and integers, we use the position of the tuples in the lexicographical order as indices; - not every mapping is stored, but only those whose output differs from a default output value, given by the user or somehow inferred by one of the constructors. For instance, the classical truth-table for :math:`\land` presented above would store only a single mapping: the value :math:`3` mapping to :math:`1` (since the tuple :math:`(1, 1)` is the fourth in the lexicographical ordering of pairs over :math:`\{0,1\}`), in case it is informed that the default output is :math:`\{0\}`. Notice that we only mentioned integers, while the given table for :math:`\land` has :math:`\{\mathrm{F},\mathrm{T}\}` as values. This is not a problem as the pointer to the domain object allows us to perform translations between the representations. Constructing truth-tables ------------------------- We provide many ways to build truth-tables: - by specifying the domain, the arity and a default output, lefting the specification of the mapping for later: .. code-block:: cpp ct4l::TruthTable and_table { {"F", "T"}, // domain 2, // arity {"F"}, // default output }; and_table.set({"T","T"}, {"T"}); - by specifying the domain, the arity, a default output and specific mappings: .. code-block:: cpp ct4l::TruthTable and_table { {"F", "T"}, // domain 2, // arity {"F"}, // default output { {{"T","T"}, {"T"}} // specific mapping } }; - by specifying the domain, the arity and specific mappings (the default output will be taken as the most frequent output in those mappings): .. code-block:: cpp ct4l::TruthTable and_table { {"F", "T"}, // domain 2, // arity { {{"T","T"}, {"T"}} // specific mapping {{"F","F"}, {"F"}} // specific mapping {{"F","T"}, {"F"}} // specific mapping } }; - by specifying only the domain and specific mappings (the default output will be inferred as in the previous item, and the arity will be taken to be the size of the first input tuple in the specific mappings list): .. code-block:: cpp ct4l::TruthTable and_table { {"F", "T"}, // domain { {{"T","T"}, {"T"}} // specific mapping {{"F","F"}, {"F"}} // specific mapping {{"F","T"}, {"F"}} // specific mapping } }; - by specifying a domain, an arity and a function that takes input tuples over the domain values and indicates the outputs: .. code-block:: cpp ct4l::TruthTable and_table { {"F", "T"}, 2, [](const std::vector& args) -> std::set { if (args[0] == "T" and args[1] == "T") return {"T"}; else return {"F"}; } }; .. note:: The choice of which constructor you will use depends on whether you want to enforce some characteristic in the construction of the truth-table. For example, if you want to build a binary truth-table and the mappings are given by the user, you can specify the arity in the construction so that an error is thrown in case the user provides mappings with input tuples of sizes other than :math:`2`. Let us fix the following truth-table for the next sections: .. code-block:: cpp ct4l::TruthTable or_table = { {"F", "T"}, { {{"T","T"}, {"T"}} {{"T","F"}, {"T"}} {{"F","F"}, {"F"}} } }; Manipulating truth-tables ------------------------- We provide methods for manipulating truth-tables in terms of the domain values, via the methods :cpp:func:`ct4l::TruthTableI::at()` and :cpp:func:`ct4l::TruthTableI::set()`: .. code-block:: cpp or_table.at({"T","F"}); // returns the set {"T"} or_table.set({"T", "T"}, {"T","F"}); // add non-determinism at input {"T", "T"} Also, in terms of the internal values, via the methods :cpp:func:`ct4l::TruthTableI::ati()` and :cpp:func:`ct4l::TruthTableI::seti()`: .. code-block:: cpp or_table.ati({0,0}); // returns the set {0} or_table.seti({1, 0}, {1, 0}); // add non-determinism at input {1, 0} Iterating over truth-tables --------------------------- The interface for truth-tables implements an iterator that produces the so-called *determinants*, which are objects intended to represent independently the rows of a truth-table. We use by default the internal representation (in terms of integers), but each determinant may hold a pointer to a domain, allowing for the translation of the internal values to the domain values during the iteration. A determinant also implements the unary operator :cpp:func:`operator*()`, which performs this translation automatically if a domain in present. Granted this iterator, we can use a *forach* loop to iterate over *all* determinants of a truth-table: .. code-block:: cpp for (auto& det : or_table) { auto args = det.arguments; // the input tuple in the row in internal values auto output = det.output; // the output set in the row in internal values ... } Alternatively, we could use the structured binding syntax: .. code-block:: cpp for (auto& [args, output, domain] : or_table) { ... } If we want to work with the domain values, we could just to the following: .. code-block:: cpp for (auto& det : or_table) { auto [args, output] = *det; ... } API --- .. doxygenstruct:: ct4l::Determinant :members: .. doxygenclass:: ct4l::TruthTableI :members: .. doxygenclass:: ct4l::TruthTable :members: