libreda_logic/
traits.rs

1// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! Abstractions for different representations of boolean formulas.
6//! Defines how different types of boolean functions/formulas can be accessed and manipulated.
7
8use std::hash::Hash;
9
10/// Trait used for identifier types.
11pub trait IdType:
12    Copy + Clone + PartialEq + Eq + Hash + PartialOrd + Ord + Send + Sync + 'static
13{
14}
15
16/// Blanket implementation.
17impl<T> IdType for T where
18    T: Copy + Clone + PartialEq + Eq + Hash + PartialOrd + Ord + Send + Sync + 'static
19{
20}
21
22/// Define the number of function arguments.
23pub trait NumInputs {
24    /// Get the number of inputs of the boolean function.
25    fn num_inputs(&self) -> usize;
26}
27
28/// Define the number of function outputs.
29pub trait NumOutputs {
30    /// Get the number of outputs of the boolean function.
31    fn num_outputs(&self) -> usize;
32}
33
34/// Generic ways to access and query a set of partially specified boolean formulas.
35pub trait PartialBooleanSystem: NumInputs + NumOutputs {
36    /// An identifier for an input of the boolean formula.
37    type LiteralId: IdType;
38    /// An identifier of an intermediate value or output.
39    type TermId: IdType;
40
41    /// Compute the value of the `term`.
42    /// The values of all needed literals must be defined by the `input_values` function.
43    /// Returns `None` if the value is not specified for the given inputs.
44    fn evaluate_term_partial(&self, term: &Self::TermId, input_values: &[bool]) -> Option<bool>;
45
46    //fn evaluate_term_partial_with_context(
47    //    &self,
48    //    term: &Self::TermId,
49    //    input_values: &impl Fn(Self::LiteralId) -> bool,
50    //) -> Option<bool>;
51}
52
53/// Define positions of input variables such that they can be
54/// adressed with an index.
55pub trait PositionalInputs: NumInputs {
56    /// ID type used for input variables.
57    type InputId: IdType;
58
59    /// Find the input variable at the given position.
60    /// Returns `None` if there's no variable at the position.
61    fn get_input_var(&self, position: usize) -> Option<Self::InputId>;
62
63    /// Find the first position of an input variable.
64    fn find_input_position(&self, input_id: &Self::InputId) -> Option<usize> {
65        (0..self.num_inputs()).find(|&i| self.get_input_var(i).as_ref() == Some(input_id))
66    }
67}
68
69/// A set of fully specified boolean formulas.
70pub trait BooleanSystem: PartialBooleanSystem {
71    /// Compute the value of the `term`.
72    /// The values of all needed literals must be defined by the `input_values` function.
73    fn evaluate_term(&self, term: &Self::TermId, input_values: &[bool]) -> bool;
74}
75
76/// Special case of a boolean system with exactly one output.
77pub trait PartialBooleanFunction: PartialBooleanSystem + StaticNumOutputs<1> {
78    /// Evaluate the boolean function with the given input values.
79    fn partial_eval(&self, input_values: &[bool]) -> Option<bool>;
80}
81
82/// Special case of a boolean system with exactly one output.
83pub trait BooleanFunction: PartialBooleanFunction {
84    /// Evaluate the boolean function with the given input values.
85    fn eval(&self, input_values: &[bool]) -> bool;
86}
87
88/// Number of inputs known at compile time.
89pub trait StaticNumInputs<const NUM_INPUTS: usize> {}
90
91/// Number of outputs known at compile time.
92pub trait StaticNumOutputs<const NUM_OUTPUTS: usize> {}
93
94/// Generic ways how a boolean system can be modified.
95pub trait BooleanSystemEdit: BooleanSystem {
96    // TODO
97}
98
99/// Marker trait for functions which are partially commutative.
100///
101/// Partially commutative means that the function inputs can be grouped into disjoint sets. Within each set of inputs, the inputs can be reordered
102/// without changing the function. Trivially, every function is partially commutative when grouping each input into it's own set.
103pub trait StaticPartialComutative<const NUM_INPUTS: usize> {
104    /// Set indices for each input.
105    ///
106    /// Example: A function `f` with `f(a, b, c, d) == f(b, a, c, d)` would have `COMMUTATIVE_INPUTS = [0, 0, 1, 2]`.
107    const COMMUTATIVE_INPUTS: [usize; NUM_INPUTS];
108}
109
110/// Marker trait for commutative functions.
111///
112/// Boolean systems implementing this trait are invariant under permutations of the inputs.
113pub trait StaticCommutative {}
114
115/// TODO
116pub trait ArithmeticProperties {
117    /// Check if the boolean function is commutative.
118    fn is_commutative(&self) -> bool;
119}
120
121/// Abstraction of logic values.
122pub trait LogicValue: Copy + Clone + PartialEq + Eq + Hash + 'static {
123    /// Get number of different values that this type can have.
124    fn num_values() -> usize;
125
126    /// List of possible logic values.
127    fn value(idx: usize) -> Self;
128
129    /// Additive neutral element.
130    fn zero() -> Self;
131
132    /// Multiplicative neutral element.
133    fn one() -> Self;
134}
135
136/// Binary logic operations for logic types such as `bool` or `Logic3`.
137pub trait LogicOps:
138    Sized + std::ops::Not + std::ops::BitAnd + std::ops::BitOr + std::ops::BitXor
139{
140}
141
142impl<T> LogicOps for T where
143    T: Sized + std::ops::Not + std::ops::BitAnd + std::ops::BitOr + std::ops::BitXor
144{
145}