From b02e74d88fab168f883d784890b32a204953b5e8 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Sun, 9 Feb 2020 11:31:01 -0800 Subject: [PATCH] Better implementation of Num::add_assign. The original implementation of Num::add_assign had a few inefficiencies: * It instantiated the standard hashmap with small keys. * It put a bunch of items into an empty hashmap, without setting the intial hashmap capacity. * It used multiple hash lookups in an insert-or-modify pattern. This commit: * Uses the Fnv hash function instead of the default: SipHash. * Initializes the hashmap with appropriate capacity. * Uses the entry API. In my microbenchmarks, this sped up Poseidon evaluation by 1.7x. --- Cargo.toml | 1 + src/circuit/num.rs | 32 ++++++++++++++++---------------- src/lib.rs | 1 + 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bc5581e3..976810f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ wasm = ["bellman/wasm"] [dependencies] rand = "0.4" digest = "0.8" +fnv = "1.0.3" byteorder = "1" tiny-keccak = {version = "2.0", features = ["keccak"] } serde = "1.0" diff --git a/src/circuit/num.rs b/src/circuit/num.rs index 2c1a3a64..b4596907 100644 --- a/src/circuit/num.rs +++ b/src/circuit/num.rs @@ -1,3 +1,6 @@ +use fnv::FnvHashMap; +use std::default::Default; + use bellman::pairing::{ Engine, }; @@ -779,27 +782,24 @@ impl Num { self.value = newval; let mut lc = LinearCombination::zero(); // std::mem::swap(&mut self.lc, &mut lc); - use std::collections::HashMap; - let mut final_coeffs: HashMap = HashMap::new(); + let mut final_coeffs = FnvHashMap::::with_capacity_and_hasher( + self.lc.as_ref().len() + other.lc.as_ref().len(), + Default::default(), + ); for (var, coeff) in self.lc.as_ref() { - if final_coeffs.get(var).is_some() { - if let Some(existing_coeff) = final_coeffs.get_mut(var) { - existing_coeff.add_assign(&coeff); - } - } else { - final_coeffs.insert(*var, *coeff); - } + final_coeffs + .entry(*var) + .and_modify(|c| c.add_assign(coeff)) + .or_insert_with(|| *coeff); } for (var, coeff) in other.lc.as_ref() { - if final_coeffs.get(var).is_some() { - if let Some(existing_coeff) = final_coeffs.get_mut(var) { - existing_coeff.add_assign(&coeff); - } - } else { - final_coeffs.insert(*var, *coeff); - } + final_coeffs + .entry(*var) + .and_modify(|c| c.add_assign(coeff)) + .or_insert_with(|| *coeff); } + for (var, coeff) in final_coeffs.into_iter() { lc = lc + (coeff, var); } diff --git a/src/lib.rs b/src/lib.rs index 9698f78a..f5d7b56d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub extern crate bellman; extern crate blake2_rfc_bellman_edition as blake2_rfc; extern crate digest; +extern crate fnv; extern crate rand; extern crate byteorder; extern crate tiny_keccak;