Browse Source

Added XOR gates, which vastly speeds up many cases

master
Thomas Johnson 2 years ago
parent
commit
05d56e171f
  1. 113
      src/circ.rs
  2. 4
      src/main.rs

113
src/circ.rs

@ -17,6 +17,12 @@ pub enum TreeGate {
invert: bool,
num_gates: usize,
},
Xor {
a: Box<TreeGate>,
b: Box<TreeGate>,
invert: bool,
num_gates: usize,
},
Input {
idx: usize,
invert: bool,
@ -28,21 +34,21 @@ impl TreeGate {
match self {
Self::And { a, b, invert, .. } => invert ^ (a.evaluate(inputs) && b.evaluate(inputs)),
Self::Or { a, b, invert, .. } => invert ^ (a.evaluate(inputs) || b.evaluate(inputs)),
Self::Xor { a, b, invert, .. } => invert ^ (a.evaluate(inputs) ^ b.evaluate(inputs)),
Self::Input { idx, invert, .. } => invert ^ inputs[*idx],
}
}
pub fn is_binary(&self) -> bool {
match self {
Self::And { .. } | Self::Or { .. } => true,
Self::And { .. } | Self::Or { .. } | Self::Xor { .. } => true,
_ => false,
}
}
pub fn num_interior_gates(&self) -> usize {
match self {
Self::And { num_gates, .. } => *num_gates,
Self::Or { num_gates, .. } => *num_gates,
Self::And { num_gates, .. } | Self::Or { num_gates, .. } | Self::Xor { num_gates, .. } => *num_gates,
Self::Input { .. } => 0,
}
}
@ -51,11 +57,12 @@ impl TreeGate {
match self {
Self::And {
num_gates, a, b, ..
} => {
*num_gates = a.num_interior_gates() + b.num_interior_gates() + 1;
}
} |
Self::Or {
num_gates, a, b, ..
} |
Self::Xor {
num_gates, a, b, ..
} => {
*num_gates = a.num_interior_gates() + b.num_interior_gates() + 1;
}
@ -65,11 +72,9 @@ impl TreeGate {
pub fn fix_num_interior_gates(&mut self) {
match self {
Self::And { a, b, .. } => {
a.fix_num_interior_gates();
b.fix_num_interior_gates();
}
Self::Or { a, b, .. } => {
Self::And { a, b, .. } |
Self::Or { a, b, .. } |
Self::Xor { a, b, .. } => {
a.fix_num_interior_gates();
b.fix_num_interior_gates();
}
@ -82,6 +87,7 @@ impl TreeGate {
match self {
TreeGate::And { invert, .. }
| TreeGate::Or { invert, .. }
| TreeGate::Xor { invert, .. }
| TreeGate::Input { invert, .. } => {
*invert ^= true;
}
@ -110,6 +116,17 @@ impl TreeGate {
}
}
pub fn xor(a: Self, b: Self) -> Self {
let nga = a.num_interior_gates();
let ngb = b.num_interior_gates();
Self::Xor {
a: Box::new(a),
b: Box::new(b),
invert: false,
num_gates: nga + ngb + 1,
}
}
pub fn input(idx: usize) -> Self {
Self::Input { idx, invert: false }
}
@ -136,6 +153,17 @@ impl TreeGate {
}
}
pub fn xnor(a: Self, b: Self) -> Self {
let nga = a.num_interior_gates();
let ngb = b.num_interior_gates();
Self::Xor {
a: Box::new(a),
b: Box::new(b),
invert: true,
num_gates: nga + ngb + 1,
}
}
pub fn ninput(idx: usize) -> Self {
Self::Input { idx, invert: true }
}
@ -179,6 +207,12 @@ impl TreeGate {
b,
num_gates,
invert,
} => each!(a, b, invert, num_gates, Xor),
Self::Xor {
a,
b,
num_gates,
invert,
} => each!(a, b, invert, num_gates, And),
_ => false,
}
@ -197,6 +231,9 @@ impl TreeGate {
}
| TreeGate::Or {
a, b, num_gates, ..
}
| TreeGate::Xor {
a, b, num_gates, ..
} => {
let ag;
if idx == num_gates.clone() - 1 {
@ -252,6 +289,13 @@ impl TreeGate {
if *invert { "o" } else { "O" },
b.multiline_string(indent + 1, false, fill)
),
TreeGate::Xor { a, b, invert, .. } => format!(
"{}\n{}{}\n{}",
a.multiline_string(indent + 1, true, upper_fill),
pad,
if *invert { "+" } else { "%" },
b.multiline_string(indent + 1, false, fill)
),
TreeGate::Input { idx, invert, .. } => {
format!("{}{}Input({})", pad, if *invert { "/" } else { "" }, idx)
}
@ -349,25 +393,25 @@ impl Perturbable for TreeCircuit {
for _ in 0..num_to_add {
let random_input = TreeGate::input(rng.gen_range(0, self.num_inputs));
let get_rand_gate = |rng: &mut R, new_input: TreeGate| {
let dist = WeightedIndex::new(&[1, 1]).unwrap();
let invert = rng.sample(&dist);
match rng.sample(&dist) {
let dist = WeightedIndex::new(&[1, 1, 1]).unwrap();
let dist5050 = Bernoulli::new(0.5).unwrap();
let invert = rng.sample(&dist5050);
let mut gate = match rng.sample(&dist) {
0 => {
let mut gate = TreeGate::and(new_input.clone(), new_input);
if invert == 1 {
gate.invert();
}
gate
TreeGate::and(new_input.clone(), new_input)
}
1 => {
let mut gate = TreeGate::or(new_input.clone(), new_input);
if invert == 1 {
gate.invert();
}
gate
TreeGate::or(new_input.clone(), new_input)
}
2 => {
TreeGate::xor(new_input.clone(), new_input)
}
_ => unreachable!(),
};
if invert {
gate.invert();
}
gate
};
let link_rand_gate =
|rng: &mut R, new_input, other_input: &mut Box<TreeGate>| {
@ -375,7 +419,7 @@ impl Perturbable for TreeCircuit {
match &mut gate {
// The randomness here isn't functional; it's mostly for visual
// balance
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { a, b, .. } => {
let dist = Bernoulli::new(0.5).unwrap();
if rng.sample(&dist) {
core::mem::swap(a.as_mut(), other_input.as_mut());
@ -389,7 +433,7 @@ impl Perturbable for TreeCircuit {
};
if let None = self.act_on_random_gate(rng, |gate, rng| {
match &mut **gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { a, b, .. } => {
let dist = Bernoulli::new(0.5).unwrap();
if rng.sample(&dist) {
// Insert before `a`
@ -420,7 +464,7 @@ impl Perturbable for TreeCircuit {
if let None = self.act_on_random_gate(rng, |gate, rng| {
let mut temp = TreeGate::input(0);
match &mut **gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { a, b, .. } => {
let dist = Bernoulli::new(0.5).unwrap();
if rng.sample(&dist) {
core::mem::swap(a.as_mut(), &mut temp);
@ -452,7 +496,7 @@ impl Perturbable for TreeCircuit {
// Invert gates
if self
.act_on_random_gate(rng, |gate, rng| match &mut **gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { a, b, .. } => {
let dist = Bernoulli::new(0.5).unwrap();
if rng.sample(dist) {
a.invert();
@ -469,7 +513,6 @@ impl Perturbable for TreeCircuit {
}
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);
@ -478,21 +521,21 @@ impl Perturbable for TreeCircuit {
return false;
}
match &**gate {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } => {
TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { 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 {
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { 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, .. } =
if let TreeGate::And { a: ta, b: tb, .. } | TreeGate::Or { a: ta, b: tb, .. } | TreeGate::Xor { a: ta, b: tb, .. } =
&mut **gate
{
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } =
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { a, b, .. } =
&mut temp_gate
{
core::mem::swap(
@ -502,7 +545,7 @@ impl Perturbable for TreeCircuit {
}
}
temp_gate.adjust_num_interior_gates();
if let TreeGate::And { a: ta, b: tb, .. } | TreeGate::Or { a: ta, b: tb, .. } =
if let TreeGate::And { a: ta, b: tb, .. } | TreeGate::Or { a: ta, b: tb, .. } | TreeGate::Xor { a: ta, b: tb, .. } =
&mut **gate
{
core::mem::swap(if right { tb } else { ta }.as_mut(), &mut temp_gate);
@ -517,7 +560,7 @@ impl Perturbable for TreeCircuit {
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 {
if let TreeGate::And { a, b, .. } | TreeGate::Or { a, b, .. } | TreeGate::Xor { a, b, .. } = &mut **gate {
core::mem::swap(a.as_mut(), b.as_mut());
}
});

4
src/main.rs

@ -15,8 +15,8 @@ fn print_tt(tt: &Vec<bool>, n: usize) {
}
fn main() {
let num_iters = 10000;
let num_inputs = 3;
let num_iters = 10000000;
let num_inputs = 4;
let mut circ = TreeCircuit::new_simple(num_inputs);
let mut rng = rand::thread_rng();
let ib = 1.0 / (num_iters as f64);

Loading…
Cancel
Save