Browse Source

Made some improvements

master
Thomas Johnson 2 years ago
parent
commit
16285f6c78
  1. 1
      Cargo.toml
  2. 5
      src/anneal.rs
  3. 91
      src/circ.rs
  4. 40
      src/main.rs

1
Cargo.toml

@ -6,3 +6,4 @@ edition = "2018"
[dependencies]
rand = "0.7.3"
rand_distr = "0.2.2"

5
src/anneal.rs

@ -15,9 +15,14 @@ pub fn anneal_discrete_step<T: Perturbable + Optimizable<Goal = U> + Clone, U>(
s: &mut T,
temp: f64,
goal: &U,
distance_factor: f64,
rng: &mut impl Rng,
) -> bool {
let mut t = s.clone();
let dist_poisson = rand_distr::Poisson::new(distance_factor).unwrap();
for _ in 0..rng.sample(dist_poisson) {
t.perturb(rng);
}
t.perturb(rng);
let closer = t.closer_than(&s, goal);
let p_switch = if closer { 1.0 } else { temp };

91
src/circ.rs

@ -32,6 +32,13 @@ impl TreeGate {
}
}
pub fn is_binary(&self) -> bool {
match self {
Self::And { .. } | Self::Or { .. } => true,
_ => false,
}
}
pub fn num_interior_gates(&self) -> usize {
match self {
Self::And { num_gates, .. } => *num_gates,
@ -334,7 +341,7 @@ impl Perturbable for TreeCircuit {
fn perturb<R: Rng>(&mut self, rng: &mut R) {
use rand::distributions::WeightedIndex;
let choice = WeightedIndex::new(&[1, 1, 1, 1]).unwrap();
let choice = WeightedIndex::new(&[1, 1, 3, 3, 3, 3]).unwrap();
match rng.sample(choice) {
0 => {
// Add gates
@ -434,28 +441,88 @@ impl Perturbable for TreeCircuit {
}
2 => {
// Change gates
if let Some(true) = self.act_on_random_gate(rng, |gate, _rng| gate.switch_type()) {
} else {
if self
.act_on_random_gate(rng, |gate, _rng| gate.switch_type())
.is_none()
{
self.perturb(rng); // Try again
}
}
3 => {
// Invert gates
if let Some(()) = self.act_on_random_gate(rng, |gate, rng| match &mut **gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
let dist = Bernoulli::new(0.5).unwrap();
if rng.sample(dist) {
a.invert();
} else {
b.invert();
if self
.act_on_random_gate(rng, |gate, rng| match &mut **gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
let dist = Bernoulli::new(0.5).unwrap();
if rng.sample(dist) {
a.invert();
} else {
b.invert();
}
}
_ => unreachable!(),
})
.is_none()
{
self.root.invert();
}
}
4 => {
// Tree rotation on gates
if let Some(true) = self.act_on_random_gate(rng, |gate, rng| {
let dist = Bernoulli::new(0.5).unwrap();
let right = rng.sample(&dist);
let mut temp_gate = TreeGate::input(0);
if !gate.is_binary() {
return false;
}
_ => unreachable!(),
match &**gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
if !(if right { a } else { b }).is_binary() {
return false;
}
}
_ => return false,
}
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } = &mut **gate {
core::mem::swap(if right { a } else { b }.as_mut(), &mut temp_gate);
}
core::mem::swap(gate.as_mut(), &mut temp_gate);
if let TreeGate::And { a: ta, b: tb, .. } | TreeGate::Or { a: ta, b: tb, .. } =
&mut **gate
{
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } =
&mut temp_gate
{
core::mem::swap(
if right { tb } else { ta }.as_mut(),
if right { a } else { b }.as_mut(),
);
}
}
temp_gate.adjust_num_interior_gates();
if let TreeGate::And { a: ta, b: tb, .. } | TreeGate::Or { a: ta, b: tb, .. } =
&mut **gate
{
core::mem::swap(if right { tb } else { ta }.as_mut(), &mut temp_gate);
}
gate.adjust_num_interior_gates();
true
}) {
} else {
self.root.invert();
self.perturb(rng); // Try again
}
}
5 => {
// Switch the two inputs, then retstart
self.act_on_random_gate(rng, |gate, _rng| {
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } = &mut **gate {
core::mem::swap(a.as_mut(), b.as_mut());
}
});
self.perturb(rng);
}
_ => panic!("random index is out of range! wrong distribution?"),
}
}

40
src/main.rs

@ -3,23 +3,47 @@ pub mod circ;
use anneal::anneal_discrete_step;
use circ::TreeCircuit;
use rand::{distributions::Bernoulli, Rng};
fn print_tt(tt: &Vec<bool>, n: usize) {
for (row, val) in tt.iter().enumerate() {
for i in 0..n {
print!("{} ", if row & (1 << (n - i - 1)) != 0 { 1 } else { 0 });
}
println!("│ {}", if *val { 1 } else { 0 });
}
}
fn main() {
let num_iters = 100000;
let num_iters = 10000;
let num_inputs = 3;
let mut circ = TreeCircuit::new_simple(num_inputs);
let mut rng = rand::thread_rng();
let ib = 1.0 / (num_iters as f64);
let mut goal = Vec::new();
let dist = Bernoulli::new(0.5).unwrap();
#[allow(unused_variables)]
for i in 0usize..1 << num_inputs {
goal.push(i.count_ones() & 1 == 0);
goal.push(rng.sample(&dist));
//goal.push(i.count_ones() & 1 == 1);
}
for i in 0..num_iters {
if i % 137 == 0 {
println!("step: {}", i);
loop {
for i in 0..num_iters {
if i % 1377 == 0 {
println!("step: {}", i);
}
let temp = ((num_iters - i) as f64) * ib;
anneal_discrete_step(&mut circ, temp, &goal, 5.0, &mut rng);
// if (circ.distance_from_goal(&goal) == 0) {
// println!("{}", circ.root);
// }
}
let dist = circ.distance_from_goal(&goal);
println!("--- truth table of goal ---");
print_tt(&goal, num_inputs);
println!("{}: \n{}", dist, circ.root);
if dist == 0 {
break;
}
let temp = ((num_iters - i) as f64) * ib;
anneal_discrete_step(&mut circ, temp, &goal, &mut rng);
}
println!("{}: \n{}", circ.distance_from_goal(&goal), circ.root);
}
Loading…
Cancel
Save