use crate::gate_type::GateType; #[derive(Debug, Clone)] pub struct Gate { pub gate_type: GateType, pub input_gates_indices: Vec, // Which previous gates to use pub input_bits_indices: Vec, // Which input bits to use } impl Gate { pub fn new( gate_type: GateType, input_gates_indices: Vec, input_bits_indices: Vec, ) -> 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, evaluated_gates: &Vec) -> 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()} }, } } }