use crate::spin_network::SpinNetwork;
use crate::types::{BinaryNode, Energy, MagneticFieldStrength, Node, UnaryNode};
#[derive(Default)]
pub struct COPY {
magnetic_field_strength: Energy,
}
impl COPY {
fn new(magnetic_field_strength: MagneticFieldStrength) -> Self {
return COPY {
magnetic_field_strength,
};
}
}
impl Node for COPY {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(self.magnetic_field_strength)
}
}
impl UnaryNode for COPY {
fn connect_to_one(&self, spin_network: &mut SpinNetwork, input: usize) -> usize {
let output_node_index = self.connect(spin_network);
spin_network
.interactions
.push((input, output_node_index, 1.0));
output_node_index
}
}
#[derive(Default)]
pub struct NOT {}
impl Node for NOT {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(0.0)
}
}
impl UnaryNode for NOT {
fn connect_to_one(&self, spin_network: &mut SpinNetwork, input: usize) -> usize {
let output_node_index = self.connect(spin_network);
spin_network
.interactions
.push((input, output_node_index, -1.0));
output_node_index
}
}
#[derive(Default)]
pub struct AND {}
impl Node for AND {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(-1.0)
}
}
impl BinaryNode for AND {
fn connect_to_two(
&self,
spin_network: &mut SpinNetwork,
left_input: usize,
right_input: usize,
) -> usize {
let output_node_index = self.connect(spin_network);
let copy_with_half = COPY::new(0.5);
let left_copy_output_index = spin_network.add_unary_node(left_input, ©_with_half);
let right_copy_output_index = spin_network.add_unary_node(right_input, ©_with_half);
let left_to_right = (left_copy_output_index, right_copy_output_index, -0.5);
let left_to_output = (left_copy_output_index, output_node_index, 1.0);
let right_to_output = (right_copy_output_index, output_node_index, 1.0);
spin_network.interactions.push(left_to_right);
spin_network.interactions.push(left_to_output);
spin_network.interactions.push(right_to_output);
output_node_index
}
}
#[derive(Default)]
pub struct OR {}
impl Node for OR {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(1.0)
}
}
impl BinaryNode for OR {
fn connect_to_two(
&self,
spin_network: &mut SpinNetwork,
left_input: usize,
right_input: usize,
) -> usize {
let output_node_index = self.connect(spin_network);
let copy_with_minus_half = COPY::new(-0.5);
let left_copy_output_index = spin_network.add_unary_node(left_input, ©_with_minus_half);
let right_copy_output_index =
spin_network.add_unary_node(right_input, ©_with_minus_half);
let left_to_right = (left_copy_output_index, right_copy_output_index, -0.5);
let left_to_output = (left_copy_output_index, output_node_index, 1.0);
let right_to_output = (right_copy_output_index, output_node_index, 1.0);
spin_network.interactions.push(left_to_right);
spin_network.interactions.push(left_to_output);
spin_network.interactions.push(right_to_output);
output_node_index
}
}
#[derive(Default)]
pub struct NAND {}
impl Node for NAND {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(1.0)
}
}
impl BinaryNode for NAND {
fn connect_to_two(
&self,
spin_network: &mut SpinNetwork,
left_input: usize,
right_input: usize,
) -> usize {
let output_node_index = self.connect(spin_network);
let copy_with_minus_half = COPY::new(0.5);
let left_copy_output_index = spin_network.add_unary_node(left_input, ©_with_minus_half);
let right_copy_output_index =
spin_network.add_unary_node(right_input, ©_with_minus_half);
let left_to_right = (left_copy_output_index, right_copy_output_index, -0.5);
let left_to_output = (left_copy_output_index, output_node_index, -1.0);
let right_to_output = (right_copy_output_index, output_node_index, -1.0);
spin_network.interactions.push(left_to_right);
spin_network.interactions.push(left_to_output);
spin_network.interactions.push(right_to_output);
output_node_index
}
}
#[derive(Default)]
pub struct NOR {}
impl Node for NOR {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(-1.0)
}
}
impl BinaryNode for NOR {
fn connect_to_two(
&self,
spin_network: &mut SpinNetwork,
left_input: usize,
right_input: usize,
) -> usize {
let output_node_index = self.connect(spin_network);
let copy_with_minus_half = COPY::new(-0.5);
let left_copy_output_index = spin_network.add_unary_node(left_input, ©_with_minus_half);
let right_copy_output_index =
spin_network.add_unary_node(right_input, ©_with_minus_half);
let left_to_right = (left_copy_output_index, right_copy_output_index, -0.5);
let left_to_output = (left_copy_output_index, output_node_index, -1.0);
let right_to_output = (right_copy_output_index, output_node_index, -1.0);
spin_network.interactions.push(left_to_right);
spin_network.interactions.push(left_to_output);
spin_network.interactions.push(right_to_output);
output_node_index
}
}
#[derive(Default)]
pub struct XOR {}
impl Node for XOR {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(-0.5)
}
}
impl BinaryNode for XOR {
fn connect_to_two(
&self,
spin_network: &mut SpinNetwork,
left_input: usize,
right_input: usize,
) -> usize {
let output_node_index = self.connect(spin_network);
let aux_node_index = spin_network.add_auxiliary_node(-1.0);
let copy_with_minus_half = COPY::new(-0.5);
let left_copy_output_index = spin_network.add_unary_node(left_input, ©_with_minus_half);
let right_copy_output_index =
spin_network.add_unary_node(right_input, ©_with_minus_half);
let left_to_right = (left_copy_output_index, right_copy_output_index, -0.5);
let left_to_aux = (left_copy_output_index, aux_node_index, -1.0);
let right_to_aux = (right_copy_output_index, aux_node_index, -1.0);
let left_to_output = (left_copy_output_index, output_node_index, -0.5);
let right_to_output = (right_copy_output_index, output_node_index, -0.5);
let aux_to_output = (aux_node_index, output_node_index, -1.0);
spin_network.interactions.push(left_to_right);
spin_network.interactions.push(left_to_aux);
spin_network.interactions.push(right_to_aux);
spin_network.interactions.push(left_to_output);
spin_network.interactions.push(right_to_output);
spin_network.interactions.push(aux_to_output);
output_node_index
}
}
#[derive(Default)]
pub struct XNOR {}
impl Node for XNOR {
fn connect(&self, spin_network: &mut SpinNetwork) -> usize {
spin_network.add_output_node(0.5)
}
}
impl BinaryNode for XNOR {
fn connect_to_two(
&self,
spin_network: &mut SpinNetwork,
left_input: usize,
right_input: usize,
) -> usize {
let output_node_index = self.connect(spin_network);
let aux_node_index = spin_network.add_auxiliary_node(-1.0);
let copy_with_minus_half = COPY::new(-0.5);
let left_copy_output_index = spin_network.add_unary_node(left_input, ©_with_minus_half);
let right_copy_output_index =
spin_network.add_unary_node(right_input, ©_with_minus_half);
let left_to_right = (left_copy_output_index, right_copy_output_index, -0.5);
let left_to_aux = (left_copy_output_index, aux_node_index, -1.0);
let right_to_aux = (right_copy_output_index, aux_node_index, -1.0);
let left_to_output = (left_copy_output_index, output_node_index, 0.5);
let right_to_output = (right_copy_output_index, output_node_index, 0.5);
let aux_to_output = (aux_node_index, output_node_index, 1.0);
spin_network.interactions.push(left_to_right);
spin_network.interactions.push(left_to_aux);
spin_network.interactions.push(right_to_aux);
spin_network.interactions.push(left_to_output);
spin_network.interactions.push(right_to_output);
spin_network.interactions.push(aux_to_output);
output_node_index
}
}
#[cfg(test)]
mod tests {
use crate::nodelib::logic_gates::{AND, COPY, NAND, NOR, NOT, OR, XNOR, XOR};
use crate::spin_network::SpinNetwork;
#[test]
fn test_copy() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let copy_gate = COPY::new(0.0);
let z = spin_network.add_unary_node(s0, ©_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, z]));
let expected_ground_states = vec![(-1.0, vec![false, false]), (-1.0, vec![true, true])];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_not() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let not_gate = NOT::default();
let z = spin_network.add_unary_node(s0, ¬_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, z]));
let expected_ground_states = vec![(-1.0, vec![true, false]), (-1.0, vec![false, true])];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_and() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let and_gate = AND::default();
let z = spin_network.add_binary_node(s0, s1, &and_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, z]));
let expected_ground_states = vec![
(-3.5, vec![false, false, false]),
(-3.5, vec![true, false, false]),
(-3.5, vec![true, true, true]),
(-3.5, vec![false, true, false]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_or() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let or_gate = OR::default();
let z = spin_network.add_binary_node(s0, s1, &or_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, z]));
let expected_ground_states = vec![
(-3.5, vec![false, false, false]),
(-3.5, vec![true, false, true]),
(-3.5, vec![true, true, true]),
(-3.5, vec![false, true, true]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_nand() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let nand_gate = NAND::default();
let z = spin_network.add_binary_node(s0, s1, &nand_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, z]));
let expected_ground_states = vec![
(-3.5, vec![false, false, true]),
(-3.5, vec![true, false, true]),
(-3.5, vec![true, true, false]),
(-3.5, vec![false, true, true]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_nor() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let nand_gate = NOR::default();
let z = spin_network.add_binary_node(s0, s1, &nand_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, z]));
let expected_ground_states = vec![
(-3.5, vec![false, false, true]),
(-3.5, vec![true, false, false]),
(-3.5, vec![true, true, false]),
(-3.5, vec![false, true, false]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_xor() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let xor_gate = XOR::default();
let z = spin_network.add_binary_node(s0, s1, &xor_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, z]));
let expected_ground_states = vec![
(-4.0, vec![false, false, false]),
(-4.0, vec![true, false, true]),
(-4.0, vec![true, true, false]),
(-4.0, vec![false, true, true]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_xnor() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let xnor_gate = XNOR::default();
let z = spin_network.add_binary_node(s0, s1, &xnor_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, z]));
let expected_ground_states = vec![
(-4.0, vec![false, false, true]),
(-4.0, vec![true, false, false]),
(-4.0, vec![true, true, true]),
(-4.0, vec![false, true, false]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
#[test]
fn test_ternary_or() {
let mut spin_network = SpinNetwork::new();
let s0 = spin_network.add_input_node(0.0);
let s1 = spin_network.add_input_node(0.0);
let s2 = spin_network.add_input_node(0.0);
let or_gate = OR::default();
let z_aux = spin_network.add_binary_node(s0, s1, &or_gate);
let z = spin_network.add_binary_node(z_aux, s2, &or_gate);
let actual_ground_states = spin_network.find_all_ground_states(Some(vec![s0, s1, s2, z]));
let expected_ground_states = vec![
(-7.0, vec![false, false, false, false]),
(-7.0, vec![true, false, false, true]),
(-7.0, vec![true, true, false, true]),
(-7.0, vec![false, true, false, true]),
(-7.0, vec![false, true, true, true]),
(-7.0, vec![true, true, true, true]),
(-7.0, vec![true, false, true, true]),
(-7.0, vec![false, false, true, true]),
];
assert_eq!(expected_ground_states, actual_ground_states)
}
}