fn apply_controlled_unitaries_fixed<const UN: usize, const UNN: usize>(
        &self,
        unitaries: [ControlledUnitary<N, UN>; UNN],
        indicies: [usize; simple_log_2(UN)],
    ) -> Box<dyn QuantumSimulator> {
        // TOOD: Make sure multiple unitaries should never be applied simultaneously...

        // TODO: Deduplicate with apply_fixed_unitary

        let swap_list = make_swap_list::<N, {simple_log_2(UN)}>(indicies);

        // Create an iterator with those swaps applied
        let swapped_iter = self.iter().map(|(pre_bv, val)| {
            let mut bv = pre_bv;
            for &(i, j) in &swap_list {
                let bits_xor = bv[i] ^ bv[j];
                bv.set(i, bits_xor ^ bv[i]);
                bv.set(j, bits_xor ^ bv[j]);
            }
            (pre_bv, bv, val)
        });

        // Apply the unitary to every element of that iterartor
        // which passes the control test (just return the elements that fail)
        let applied_iter = maybe_flat_map(swapped_iter, |(pre_bv, bv, val)| {
            for unitary in &unitaries {
                if let Some(control_true) = unitary.control_any_true {
                    if pre_bv & control_true == BasisVector::zero() {
                        continue;
                    }
                }
                if (pre_bv & unitary.control_all_false) != BasisVector::zero() {
                    continue;
                }
                if (pre_bv & unitary.control_all_true) != unitary.control_all_true {
                    continue;
                }

                // Apply this unitary

                // Multiply bv by u <tensor product> identity

                // The basis vector picks out a column in that unitary.
                // The column is of the form [0 block][u column][0 block].
                // So we need to return a new iterator of the basis vectors
                // for u_column * val_u_column * val.
                let index_column = bv % UN;
                let base_basis_vector = bv - index_column;
                let u = unitary.matrix;
                // The problem is just that the split indicies are out of order.
                // TODO: For tomorrow, audit all matricies and index orders and controls...
                return Ok(u[index_column].into_iter().enumerate().map(move |(i_col, val_u_col)| {
                    let bv_col = (base_basis_vector + i_col).into();
                    let val = val_u_col * val;
                    (bv_col, val)
                }))
            }

            // None of the matricies control bits like this, just emit the original bv.
            return Err((bv, val));
        });

        // Swap the basis elements back
        let output_iter = applied_iter.map(|(mut bv, val): (BasisVector<N>, _)| {
            for &(i, j) in swap_list.iter().rev() {
                let bits_xor = bv[i] ^ bv[j];
                bv.set(i, bits_xor ^ bv[i]);
                bv.set(j, bits_xor ^ bv[j]);
            }
            (bv, val)
        });

        // Sum up the elements of the iterator
        Box::new(self.child(output_iter))
    }
/// Indicies in order of low to high bits (when using them to index matrix cols)
Indicies in order of low to high bits (when using them to index matrix cols)
Indicies in order of low to high bits ( when using them to index matrix cols )
fn apply_controlled_unitaries_fixed<const UN: usize, const UNN: usize>(
        &self,
        unitaries: [ControlledUnitary<N, UN>; UNN],
        indicies: [usize; simple_log_2(UN)],
    ) -> Box<dyn QuantumSimulator> {
        // TOOD: Make sure multiple unitaries should never be applied simultaneously...
        // TODO: Deduplicate with apply_fixed_unitary
        let swap_list = make_swap_list::<N, {simple_log_2(UN)}>(indicies);
        // Create an iterator with those swaps applied
        let swapped_iter = self.iter().map(|(pre_bv, val)| {
            let mut bv = pre_bv;
            for &(i, j) in &swap_list {
                let bits_xor = bv[i] ^ bv[j];
                bv.set(i, bits_xor ^ bv[i]);
                bv.set(j, bits_xor ^ bv[j]);
            }
            (pre_bv, bv, val)
        });
        // Apply the unitary to every element of that iterartor
        // which passes the control test (just return the elements that fail)
        let applied_iter = maybe_flat_map(swapped_iter, |(pre_bv, bv, val)| {
            for unitary in &unitaries {
                if let Some(control_true) = unitary.control_any_true {
                    if pre_bv & control_true == BasisVector::zero() {
                        continue;
                    }
                }
                if (pre_bv & unitary.control_all_false) != BasisVector::zero() {
                    continue;
                }
                if (pre_bv & unitary.control_all_true) != unitary.control_all_true {
                    continue;
                }
                // Apply this unitary
                // Multiply bv by u <tensor product> identity
                // The basis vector picks out a column in that unitary.
                // The column is of the form [0 block][u column][0 block].
                // So we need to return a new iterator of the basis vectors
                // for u_column * val_u_column * val.
                let index_column = bv % UN;
                let base_basis_vector = bv - index_column;
                let u = unitary.matrix;
                // The problem is just that the split indicies are out of order.
                // TODO: For tomorrow, audit all matricies and index orders and controls...
                return Ok(u[index_column].into_iter().enumerate().map(move |(i_col, val_u_col)| {
                    let bv_col = (base_basis_vector + i_col).into();
                    let val = val_u_col * val;
                    (bv_col, val)
                }))
            }
            // None of the matricies control bits like this, just emit the original bv.
            return Err((bv, val));
        });
        // Swap the basis elements back
        let output_iter = applied_iter.map(|(mut bv, val): (BasisVector<N>, _)| {
            for &(i, j) in swap_list.iter().rev() {
                let bits_xor = bv[i] ^ bv[j];
                bv.set(i, bits_xor ^ bv[i]);
                bv.set(j, bits_xor ^ bv[j]);
            }
            (bv, val)
        });
        // Sum up the elements of the iterator
        Box::new(self.child(output_iter))
    }
fn apply_controlled_unitaries_fixed < const UN : usize , const UNN : usize > ( & self , unitaries : [ ControlledUnitary < N , UN > ; UNN ] , indicies : [ usize ; simple_log_2 ( UN ) ] , ) -> Box < dyn QuantumSimulator > { // TOOD: Make sure multiple unitaries should never be applied simultaneously... // TODO: Deduplicate with apply_fixed_unitary let swap_list = make_swap_list :: < N , { simple_log_2 ( UN ) } > ( indicies ) ; // Create an iterator with those swaps applied let swapped_iter = self . iter ( ) . map ( | ( pre_bv , val ) | { let mut bv = pre_bv ; for & ( i , j ) in & swap_list { let bits_xor = bv [ i ] ^ bv [ j ] ; bv . set ( i , bits_xor ^ bv [ i ] ) ; bv . set ( j , bits_xor ^ bv [ j ] ) ; } ( pre_bv , bv , val ) } ) ; // Apply the unitary to every element of that iterartor // which passes the control test (just return the elements that fail) let applied_iter = maybe_flat_map ( swapped_iter , | ( pre_bv , bv , val ) | { for unitary in & unitaries { if let Some ( control_true ) = unitary . control_any_true { if pre_bv & control_true == BasisVector :: zero ( ) { continue ; } } if ( pre_bv & unitary . control_all_false ) != BasisVector :: zero ( ) { continue ; } if ( pre_bv & unitary . control_all_true ) != unitary . control_all_true { continue ; } // Apply this unitary // Multiply bv by u <tensor product> identity // The basis vector picks out a column in that unitary. // The column is of the form [0 block][u column][0 block]. // So we need to return a new iterator of the basis vectors // for u_column * val_u_column * val. let index_column = bv % UN ; let base_basis_vector = bv - index_column ; let u = unitary . matrix ; // The problem is just that the split indicies are out of order. // TODO: For tomorrow, audit all matricies and index orders and controls... return Ok ( u [ index_column ] . into_iter ( ) . enumerate ( ) . map ( move | ( i_col , val_u_col ) | { let bv_col = ( base_basis_vector + i_col ) . into ( ) ; let val = val_u_col * val ; ( bv_col , val ) } ) ) } // None of the matricies control bits like this, just emit the original bv. return Err ( ( bv , val ) ) ; } ) ; // Swap the basis elements back let output_iter = applied_iter . map ( | ( mut bv , val ) : ( BasisVector < N > , _ ) | { for & ( i , j ) in swap_list . iter ( ) . rev ( ) { let bits_xor = bv [ i ] ^ bv [ j ] ; bv . set ( i , bits_xor ^ bv [ i ] ) ; bv . set ( j , bits_xor ^ bv [ j ] ) ; } ( bv , val ) } ) ; // Sum up the elements of the iterator Box :: new ( self . child ( output_iter ) ) }
Indicies in order of low to high bits (when using them to index matrix cols)
Indicies in order of low to high bits ( when using them to index matrix cols )
&self
unitaries
[ControlledUnitary<N, UN>; UNN]
indicies
[usize; simple_log_2(UN)]
&self
unitaries
[ControlledUnitary<N, UN>; UNN]
indicies
[usize; simple_log_2(UN)]