diff --git a/src/group/stabchain/base_change_builder/random.rs b/src/group/stabchain/base_change_builder/random.rs index 6d1623a2a1..6853b91742 100644 --- a/src/group/stabchain/base_change_builder/random.rs +++ b/src/group/stabchain/base_change_builder/random.rs @@ -3,17 +3,12 @@ use crate::DetHashSet; use crate::{ group::{ orbit::abstraction::{FactoredTransversalResolver, TransversalResolver}, - random_perm::RandPerm, stabchain::{base::Base, Stabchain, StabchainRecord}, - Group, }, perm::{actions::SimpleApplication, Action, Permutation}, }; use num::BigUint; -const MIN_SIZE: usize = 11; -const INITIAL_RUNS: usize = 50; - /// Helper struct, used to build the stabilizer chain pub struct RandomBaseChangeBuilder> where @@ -40,7 +35,6 @@ where V: TransversalResolver, { let target_order = chain.order(); - let sgs = Group::from_list(chain.strong_generating_set()); // Create the trivial chain with all the new base points. self.chain = base .base() @@ -48,11 +42,10 @@ where .cloned() .map(StabchainRecord::trivial_record) .collect::>(); - //Random permutation generator. - let mut rand_perm = RandPerm::new(MIN_SIZE, &sgs, INITIAL_RUNS, rand::thread_rng()); + let mut rng = rand::thread_rng(); //Loop till the new chain has the correct order. while self.current_chain_order() < target_order { - let g = rand_perm.random_permutation(); + let g = chain.random_element(&mut rng); let (g_dash, i) = self.residue_with_dropout(g); //If the permutation doesn't sift through then add it as a new generator at level i. if i < base.base().len() { diff --git a/src/group/stabchain/mod.rs b/src/group/stabchain/mod.rs index a56d392a24..bd71c3ccce 100644 --- a/src/group/stabchain/mod.rs +++ b/src/group/stabchain/mod.rs @@ -12,6 +12,7 @@ use crate::perm::*; use base::Base; use base_change_builder::{BaseChangeBuilder, BaseChangeBuilderStrategy}; use builder::{Builder, BuilderStrategy}; +use rand::seq::IteratorRandom; use crate::DetHashMap; @@ -145,6 +146,47 @@ where builder.set_base(self, base); builder.build() } + + /// Get a random element of the group at a specific layer of the chain. + /// This will generate elements uniformly, assuming the given RNG also does. + pub fn random_element_from_layer(&self, layer: usize, rng: &mut R) -> P + where + R: rand::Rng, + { + self.get_chain_at_layer(layer) + .map(|record| { + record + .resolver() + .representative( + &record.transversal, + record.base.clone(), + record + .transversal + .keys() + .choose(rng) + .unwrap_or(&record.base) + .clone(), + ) + .unwrap() + }) + .fold(P::id(), |accum, product| accum.multiply(&product)) + } + + /// Get a random element of the group this chain represents. + /// This will generate elements uniformly, assuming the given RNG also does. + /// ``` + /// use stabchain::group::Group; + /// let g = Group::symmetric(4); + /// let chain = g.stabchain(); + /// let p = chain.random_element(&mut rand::thread_rng()); + /// assert!(chain.in_group(&p)); + ///``` + pub fn random_element(&self, rng: &mut R) -> P + where + R: rand::Rng, + { + self.random_element_from_layer(0, rng) + } } impl Stabchain, A>