123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- use crate::gate_type::GateType;
-
- #[derive(Debug, Clone)]
- pub struct Gate {
- pub gate_type: GateType,
- pub input_gates_indices: Vec<usize>, // Which previous gates to use
- pub input_bits_indices: Vec<usize>, // Which input bits to use
- }
-
- impl Gate {
- pub fn new(
- gate_type: GateType,
- input_gates_indices: Vec<usize>,
- input_bits_indices: Vec<usize>,
- ) -> Self {
- let num_input_wires = input_bits_indices.len() + input_gates_indices.len();
-
- if num_input_wires == 0 {
- panic!("A gate without inputs is invalid");
- }
-
- if gate_type == GateType::Bigger && num_input_wires != 2 {
- if num_input_wires != 2 {
- panic!("Bigger gates need exactly two inputs")
- }
- }
-
- if gate_type == GateType::Equal && num_input_wires != 2 {
- if num_input_wires != 2 {
- panic!("Equal gates need exactly two inputs")
- }
- }
- Self {
- gate_type,
- input_gates_indices,
- input_bits_indices,
- }
- }
-
- pub fn eval(&self, input_bits: &Vec<bool>, evaluated_gates: &Vec<bool>) -> bool {
- /*
- The goal is to perform short-circuit evaluation with the minimum number of vector lookups.
- */
-
- match self.gate_type {
- /*
- A multi-input gate that outputs 1 if all input bits are 1, and 0 otherwise
- */
- GateType::And => {
-
- for &index in self.input_bits_indices.iter(){
- if !input_bits[index] {
- return false;
- }
- }
- for &index in self.input_gates_indices.iter(){
- if !evaluated_gates[index] {
- return false;
- }
- }
-
- return true;
- }
-
- /*
- A multi-input gate that outputs 1 if at least one input bit is 1, and 0 otherwise.
- */
- GateType::Or => {
- for &index in self.input_bits_indices.iter(){
- if input_bits[index] {
- return true;
- }
- }
- for &index in self.input_gates_indices.iter(){
- if evaluated_gates[index] {
- return true;
- }
- }
- return false;
- },
-
- /*
- A gate with exactly two inputs. It outputs 1 if the two input bits are equal
- (i.e., both 0 or both 1), and 0 otherwise
- */
- GateType::Equal => match self.input_bits_indices.len() {
- 0 => evaluated_gates[self.input_gates_indices[0]] == evaluated_gates[self.input_gates_indices[1]],
- 1 => input_bits[self.input_bits_indices[0]] == evaluated_gates[self.input_gates_indices[0]],
- 2 => {
- input_bits[self.input_bits_indices[0]] == input_bits[self.input_bits_indices[1]]
- },
- _ => panic!{"How'd we get here?"}
- },
-
- /*
- A gate with exactly two inputs. It outputs 1 if the first input is 1 and the second
- input is 0; otherwise, it outputs 0. This gate is used to compare individual bits a_i > b_i
-
- A B | A > B | A && !B
- --------------------
- 0 0 | 0 | 0 0 1
- 0 1 | 0 | 0 0 0
- 1 0 | 1 | 1 1 1
- 1 1 | 0 | 1 0 0
- */
- GateType::Bigger => match self.input_bits_indices.len() {
- // bits: [] gates: [A,B]
- 0 => evaluated_gates[self.input_gates_indices[0]] && !evaluated_gates[self.input_gates_indices[1]],
-
- // bits: [A] gates: [B]
- 1 => input_bits[self.input_bits_indices[0]] && !evaluated_gates[self.input_gates_indices[0]],
-
- // bits: [A,B] gates: []
- 2 => {
- input_bits[self.input_bits_indices[0]] && !input_bits[self.input_bits_indices[1]]
- },
-
- _ => panic!{"How'd we get here? {}", input_bits.len()}
- },
- }
- }
- }
|