diff --git a/examples/readme_bin.rs b/examples/readme_bin.rs new file mode 100644 index 0000000..eebe4c7 --- /dev/null +++ b/examples/readme_bin.rs @@ -0,0 +1,78 @@ +use ernst::spin_network::SpinNetwork; +use ernst::types::{ExternalMagneticField, Interactions}; +use std::time::Instant; +use ernst::nodelib::logic_gates::OR; + +fn main() { + let some_h: ExternalMagneticField = vec![ + 5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, -1.0, 0.5, 0.5, -1.0, 0.5, + 0.5, -1.0, + ]; + let some_j: Interactions = vec![ + (0, 7, 1.0), + (1, 8, 1.0), + (7, 8, -0.5), + (7, 9, 1.0), + (8, 9, 1.0), + (1, 10, 1.0), + (2, 11, 1.0), + (10, 11, -0.5), + (10, 12, 1.0), + (11, 12, 1.0), + (0, 13, 1.0), + (4, 14, 1.0), + (13, 14, -0.5), + (13, 15, 1.0), + (14, 15, 1.0), + (3, 16, 1.0), + (2, 17, 1.0), + (16, 17, -0.5), + (16, 18, 1.0), + (17, 18, 1.0), + (3, 9, 1.0), + (4, 12, 1.0), + (5, 15, 1.0), + (6, 18, 1.0), + ]; + + let now = Instant::now(); + let exact_ground_states = ernst::solvers::find_all_ground_states(&some_j, &some_h); + let time_to_compute = now.elapsed().as_millis(); + println!("Complex spin glass ground state - took: {} ms", time_to_compute); + for ground_state in exact_ground_states { + println!( + "\tEnergy: {} - State: {:?}", + ground_state.0, ground_state.1 + ); + } + + let now = Instant::now(); + let approximate_ground_states = ernst::solvers::simulated_annealing(&some_j, &some_h, None); + let time_to_compute = now.elapsed().as_millis(); + println!("\nComplex spin glass ground state with simulated annealing - took: {} ms", time_to_compute); + for ground_state in approximate_ground_states { + println!( + "\tEnergy: {} - State: {:?} - Found in sweep number: {}", + ground_state.0, ground_state.1, ground_state.2 + ); + } + + 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 interesting_spins = vec![s0, s1, z]; + let binary_or_ground_states = spin_network.find_all_ground_states(Some(interesting_spins.clone())); + println!("\nBinary OR spin glass ground states:"); + for ground_state in binary_or_ground_states { + println!("\tEnergy: {} - State: {:?}", ground_state.0, ground_state.1); + } + + let copy_ground_states = spin_network.run_simulated_annealing(None, Some(interesting_spins)); + println!("\nBinary OR spin glass ground states with simulated annealing:"); + for ground_state in copy_ground_states { + println!("\tEnergy: {} - State: {:?} - Found in sweep number: {}", ground_state.0, ground_state.1, ground_state.2); + } +} diff --git a/examples/readme_ter.rs b/examples/readme_ter.rs new file mode 100644 index 0000000..736041a --- /dev/null +++ b/examples/readme_ter.rs @@ -0,0 +1,27 @@ +use ernst::spin_network::SpinNetwork; +use ernst::types::{ExternalMagneticField, Interactions}; +use std::time::Instant; +use ernst::nodelib::logic_gates::OR; + +fn main() { + 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: usize = spin_network.add_ternary_node(s0, s1, s2, &or_gate); + + let interesting_spins = vec![s0, s1, s2, z]; + let ternary_or_ground_states = spin_network.find_all_ground_states(Some(interesting_spins.clone())); + println!("\nTernary OR spin glass ground states:"); + for ground_state in ternary_or_ground_states { + println!("\tEnergy: {} - State: {:?}", ground_state.0, ground_state.1); + } + + let copy_ground_states = spin_network.run_simulated_annealing(None, Some(interesting_spins)); + println!("\nTernary OR spin glass ground states with simulated annealing:"); + for ground_state in copy_ground_states { + println!("\tEnergy: {} - State: {:?} - Found in sweep number: {}", ground_state.0, ground_state.1, ground_state.2); + } + +} diff --git a/examples/readme_ter_aux.rs b/examples/readme_ter_aux.rs new file mode 100644 index 0000000..f78b1d9 --- /dev/null +++ b/examples/readme_ter_aux.rs @@ -0,0 +1,27 @@ +use ernst::spin_network::SpinNetwork; +use ernst::types::{ExternalMagneticField, Interactions}; +use std::time::Instant; +use ernst::nodelib::logic_gates::OR; + +fn main() { + 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 interesting_spins = vec![s0, s1, s2, z]; + let ternary_or_ground_states = spin_network.find_all_ground_states(Some(interesting_spins.clone())); + println!("\nTernary OR spin glass ground states:"); + for ground_state in ternary_or_ground_states { + println!("\tEnergy: {} - State: {:?}", ground_state.0, ground_state.1); + } + + let copy_ground_states = spin_network.run_simulated_annealing(None, Some(interesting_spins)); + println!("\nTernary OR spin glass ground states with simulated annealing:"); + for ground_state in copy_ground_states { + println!("\tEnergy: {} - State: {:?} - Found in sweep number: {}", ground_state.0, ground_state.1, ground_state.2); + } +} diff --git a/src/nodelib/logic_gates.rs b/src/nodelib/logic_gates.rs index 419a459..c0058b2 100644 --- a/src/nodelib/logic_gates.rs +++ b/src/nodelib/logic_gates.rs @@ -1,5 +1,5 @@ use crate::spin_network::SpinNetwork; -use crate::types::{BinaryNode, Energy, MagneticFieldStrength, Node, UnaryNode}; +use crate::types::{BinaryNode, TernaryNode, Energy, MagneticFieldStrength, Node, UnaryNode}; #[derive(Default)] pub struct COPY { @@ -106,6 +106,42 @@ impl BinaryNode for OR { output_node_index } } +impl TernaryNode for OR { + fn connect_to_three( + &self, + spin_network: &mut SpinNetwork, + first_input: usize, + second_input: usize, + third_input: usize, + ) -> usize { + let ouput_node_index: usize = self.connect(spin_network); + let copy_with_minus_third = COPY::new(-1.0 / 3.0); + let first_copy_output_index = spin_network.add_unary_node(first_input, ©_with_minus_third); + let second_copy_output_index = + spin_network.add_unary_node(second_input, ©_with_minus_third); + let third_copy_output_index = spin_network.add_unary_node(third_input, ©_with_minus_third); + + let first_to_second = (first_copy_output_index, second_copy_output_index, -1.0 / 3.0); + let first_to_third = (first_copy_output_index, third_copy_output_index, -1.0 / 3.0); + let second_to_third = (second_copy_output_index, third_copy_output_index, -1.0 / 3.0); + let first_to_output = (first_copy_output_index, ouput_node_index, 1.0); + let second_to_output = (second_copy_output_index, ouput_node_index, 1.0); + let third_to_output = (third_copy_output_index, ouput_node_index, 1.0); + + spin_network.interactions.push(first_to_second); + spin_network.interactions.push(first_to_third); + spin_network.interactions.push(second_to_third); + spin_network.interactions.push(first_to_output); + spin_network.interactions.push(second_to_output); + spin_network.interactions.push(third_to_output); + + ouput_node_index + } + +}// + +// + #[derive(Default)] pub struct NAND {} diff --git a/src/spin_network.rs b/src/spin_network.rs index 3a4fa6b..ff55a78 100644 --- a/src/spin_network.rs +++ b/src/spin_network.rs @@ -2,8 +2,7 @@ use crate::solvers::{ find_all_ground_states, simulated_annealing, Epoch, SimulatedAnnealingConfiguration, }; use crate::types::{ - BinaryNode, Energy, ExternalMagneticField, Interactions, MagneticFieldStrength, SpinIndex, - State, UnaryNode + BinaryNode, TernaryNode, Energy, ExternalMagneticField, Interactions, MagneticFieldStrength, NAryNode, SpinIndex, State, UnaryNode }; /// A SpinNetwork is meant to represent a 2D Spin Glass. @@ -103,6 +102,24 @@ impl SpinNetwork { ) -> usize { return BinaryNode::connect_to_two(binary_node, self, left_input, right_input); } + pub fn add_ternary_node( + &mut self, + first_input: usize, + second_input: usize, + third_input: usize, + ternary_node: &impl TernaryNode, + ) -> usize { + return TernaryNode::connect_to_three(ternary_node, self, first_input, second_input, third_input); + } + // problem here: how to make it accept variable n number of inputs in rust? + pub fn add_NAry_node( + &mut self, + inputs: &Vec, + nary_node: &impl NAryNode, + ) -> usize { + NAryNode::connect_to_n(nary_node, self, inputs) + } + /// Finds all ground states of the spin glass represented by the SpinNetwork. The argument `spin_ordering`, when /// given, will ensure that the `State`s will be projected according to it. /// diff --git a/src/types.rs b/src/types.rs index ccf09ad..eabac28 100644 --- a/src/types.rs +++ b/src/types.rs @@ -29,6 +29,15 @@ pub trait BinaryNode: Node { right_input: SpinIndex, ) -> SpinIndex; } +pub trait TernaryNode: Node { + fn connect_to_three( + &self, + spin_network: &mut SpinNetwork, + first_input: SpinIndex, + second_input: SpinIndex, + third_input: SpinIndex, + ) -> SpinIndex; +} pub trait NAryNode: Node { fn connect_to_n(&self, spin_network: &mut SpinNetwork, inputs: &Vec) -> SpinIndex; }