diff --git a/.compatibility_tests/compatibility_test_1_0/Cargo.toml b/.compatibility_tests/compatibility_test_1_0/Cargo.toml index de3e669c..80c66836 100644 --- a/.compatibility_tests/compatibility_test_1_0/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_0" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_0 = { package = "roqoqo", version = "=1.0.0" } test_roqoqo_derive_1_0 = { package = "roqoqo-derive", version = "=1.0.0" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_10/Cargo.toml b/.compatibility_tests/compatibility_test_1_10/Cargo.toml index 8d432f58..a32f7bba 100644 --- a/.compatibility_tests/compatibility_test_1_10/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_10/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "compatibility_test_1_10" -version = "1.12.1" authors = ["HQS Quantum Simulations "] +name = "compatibility_test_1_10" +version = "1.13.0" license = "Apache-2.0" edition = "2021" rust-version = "1.56" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_10 = { package = "roqoqo", version = "=1.10.0" } test_roqoqo_derive_1_10 = { package = "roqoqo-derive", version = "=1.10.0" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_11/Cargo.toml b/.compatibility_tests/compatibility_test_1_11/Cargo.toml index 946aebbe..dba5b327 100644 --- a/.compatibility_tests/compatibility_test_1_11/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_11/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_11" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_11 = { package = "roqoqo", version = "=1.11.0" } test_roqoqo_derive_1_11 = { package = "roqoqo-derive", version = "=1.11.0" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_11/tests/integration/compatibility_1_11.rs b/.compatibility_tests/compatibility_test_1_11/tests/integration/compatibility_1_11.rs index 9fe98694..84d17087 100644 --- a/.compatibility_tests/compatibility_test_1_11/tests/integration/compatibility_1_11.rs +++ b/.compatibility_tests/compatibility_test_1_11/tests/integration/compatibility_1_11.rs @@ -125,7 +125,7 @@ use test_roqoqo_1_11; // Operations from 1.11 - ApplyConstantSpinHamiltonian and ApplyTimeDependentHamiltonian are unstable in 1.11 // #[test_case(create_apply_constant_spin_hamiltonian(); "ApplyConstantSpinHamiltonian")] // #[test_case(create_apply_timedependent_spin_hamiltonian(); "ApplyTimeDependentHamiltonian")] -fn test_bincode_compatibility_1_10(operation: test_roqoqo_1_11::operations::Operation) { +fn test_bincode_compatibility_1_11(operation: test_roqoqo_1_11::operations::Operation) { let mut test_circuit = test_roqoqo_1_11::Circuit::new(); test_circuit += operation; diff --git a/.compatibility_tests/compatibility_test_1_12/Cargo.toml b/.compatibility_tests/compatibility_test_1_12/Cargo.toml new file mode 100644 index 00000000..bc7ee48a --- /dev/null +++ b/.compatibility_tests/compatibility_test_1_12/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "compatibility_test_1_12" +version = "1.13.0" +authors = ["HQS Quantum Simulations "] +license = "Apache-2.0" +edition = "2021" +rust-version = "1.56" +categories = ["science", "simulation"] +homepage = "https://github.com/HQSquantumsimulations/qoqo" +repository = "https://github.com/HQSquantumsimulations/qoqo" +documentation = "https://docs.rs/roqoqo/" +readme = "../README.md" +description = "Compatibility tests for roqoqo" +include = ["src*", "build.rs", "LICENSE", "README.md"] +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[workspace] + +[dependencies] +test_roqoqo_1_12 = { package = "roqoqo", version = "=1.12.0" } +test_roqoqo_derive_1_12 = { package = "roqoqo-derive", version = "=1.12.0" } +qoqo_calculator = { version = "1.2" } +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ + "serialize", + "overrotate", +] } +struqture = { version = "1.7" } +bincode = { version = "1.3" } +ndarray = "0.15" + +[dev-dependencies] +test-case = "3.0" diff --git a/.compatibility_tests/compatibility_test_1_12/src/lib.rs b/.compatibility_tests/compatibility_test_1_12/src/lib.rs new file mode 100644 index 00000000..7d12d9af --- /dev/null +++ b/.compatibility_tests/compatibility_test_1_12/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/.compatibility_tests/compatibility_test_1_12/tests/integration/compatibility_1_12.rs b/.compatibility_tests/compatibility_test_1_12/tests/integration/compatibility_1_12.rs new file mode 100644 index 00000000..24e21c69 --- /dev/null +++ b/.compatibility_tests/compatibility_test_1_12/tests/integration/compatibility_1_12.rs @@ -0,0 +1,203 @@ +// Copyright © 2023 HQS Quantum Simulations GmbH. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::HashMap; + +use test_case::test_case; +use test_roqoqo_1_12; + +// 1.0 version +#[test_case(test_roqoqo_1_12::operations::SingleQubitGate::new(0, 1.0.into(), 0.0.into(), 0.0.into(), 0.0.into(), 0.0.into(),).into(); "SingleQubitGate")] +#[test_case(test_roqoqo_1_12::operations::RotateZ::new(0, 0.1.into()).into(); "RotateZ")] +#[test_case(test_roqoqo_1_12::operations::RotateY::new(0, 0.1.into()).into(); "RotateY")] +#[test_case(test_roqoqo_1_12::operations::RotateX::new(0, 0.1.into()).into(); "RotateX")] +#[test_case(test_roqoqo_1_12::operations::RotateXY::new(0,1.0.into(), 0.1.into()).into(); "RotateXY")] +#[test_case(test_roqoqo_1_12::operations::RotateAroundSphericalAxis::new(0, 1.0.into(), 1.0.into(), 1.0.into()).into(); "RotateAroundSphericalAxis")] +#[test_case(test_roqoqo_1_12::operations::PauliZ::new(0).into(); "PauliZ")] +#[test_case(test_roqoqo_1_12::operations::PauliY::new(0).into(); "PauliY")] +#[test_case(test_roqoqo_1_12::operations::PauliX::new(0).into(); "PauliX")] +#[test_case(test_roqoqo_1_12::operations::SqrtPauliX::new(0).into(); "SqrtPauliX")] +#[test_case(test_roqoqo_1_12::operations::InvSqrtPauliX::new(0).into(); "InvSqrtPauliX")] +#[test_case(test_roqoqo_1_12::operations::Hadamard::new(0).into(); "Hadamard")] +#[test_case(test_roqoqo_1_12::operations::TGate::new(0).into(); "TGate")] +#[test_case(test_roqoqo_1_12::operations::SGate::new(0).into(); "SGate")] +#[test_case(test_roqoqo_1_12::operations::DefinitionBit::new("ro".to_string(), 1, false).into(); "DefinitionBit")] +#[test_case(test_roqoqo_1_12::operations::DefinitionComplex::new("ro".to_string(), 1, true).into(); "DefinitionComplex")] +#[test_case(test_roqoqo_1_12::operations::DefinitionUsize::new("ro".to_string(), 1, true).into(); "DefinitionUsize")] +#[test_case(test_roqoqo_1_12::operations::DefinitionFloat::new("ro".to_string(), 1, true).into(); "DefinitionFloat")] +#[test_case(test_roqoqo_1_12::operations::InputSymbolic::new("ro".to_string(), 1.0).into(); "InputSymbolic")] +#[test_case(test_roqoqo_1_12::operations::MeasureQubit::new(0,"ro".to_string(), 1).into(); "MeasureQubit")] +#[test_case(test_roqoqo_1_12::operations::PragmaGetStateVector::new("ro".to_string(), None).into(); "PragmaGetStateVector")] +#[test_case(test_roqoqo_1_12::operations::PragmaGetDensityMatrix::new("ro".to_string(), None).into(); "PragmaGetDensityMatrix")] +#[test_case(test_roqoqo_1_12::operations::PragmaGetOccupationProbability::new("ro".to_string(), None).into(); "PragmaGetOccupationProbability")] +#[test_case(test_roqoqo_1_12::operations::PragmaGetPauliProduct::new(std::collections::HashMap::new(),"ro".to_string(), test_roqoqo_1_12::Circuit::new()).into(); "PragmaGetPauliProduct")] +#[test_case(test_roqoqo_1_12::operations::PragmaRepeatedMeasurement::new("ro".to_string(), 10, None).into(); "PragmaRepeatedMeasurement")] +#[test_case(test_roqoqo_1_12::operations::PragmaSetNumberOfMeasurements::new(10, "ro".to_string()).into(); "PragmaSetNumberOfMeasurements")] +#[test_case(test_roqoqo_1_12::operations::PragmaSetStateVector::new(ndarray::array![1.0.into(), 0.0.into(), 0.0.into()]).into(); "PragmaSetStateVector")] +#[test_case(test_roqoqo_1_12::operations::PragmaSetDensityMatrix::new(ndarray::array![[1.0.into(), 0.0.into(), 0.0.into()]]).into(); "PragmaSetDensityMatrix")] +#[test_case(test_roqoqo_1_12::operations::PragmaRepeatGate::new(10).into(); "PragmaRepeatGate")] +#[test_case(test_roqoqo_1_12::operations::PragmaOverrotation::new("RotateZ".to_string(), vec![0], 1.0, 1.0).into(); "PragmaOverrotation")] +#[test_case(test_roqoqo_1_12::operations::PragmaBoostNoise::new(1.0.into()).into(); "PragmaBoostNoise")] +#[test_case(test_roqoqo_1_12::operations::PragmaStopParallelBlock::new(vec![0], 1.0.into()).into(); "PragmaStopParallelBlock")] +#[test_case(test_roqoqo_1_12::operations::PragmaGlobalPhase::new(1.0.into()).into(); "PragmaGlobalPhase")] +#[test_case(test_roqoqo_1_12::operations::PragmaSleep::new(vec![0], 1.0.into()).into(); "PragmaSleep")] +#[test_case(test_roqoqo_1_12::operations::PragmaActiveReset::new(0).into(); "PragmaActiveReset")] +#[test_case(test_roqoqo_1_12::operations::PragmaStartDecompositionBlock::new(vec![0], HashMap::new()).into(); "PragmaStartDecompositionBlock")] +#[test_case(test_roqoqo_1_12::operations::PragmaStopDecompositionBlock::new(vec![0]).into(); "PragmaStopDecompositionBlock")] +#[test_case(test_roqoqo_1_12::operations::PragmaDamping::new(0,1.0.into(), 1.0.into()).into(); "PragmaDamping")] +#[test_case(test_roqoqo_1_12::operations::PragmaDepolarising::new(0,1.0.into(), 1.0.into()).into(); "PragmaDepolarising")] +#[test_case(test_roqoqo_1_12::operations::PragmaDephasing::new(0,1.0.into(), 1.0.into()).into(); "PragmaDephasing")] +#[test_case(test_roqoqo_1_12::operations::PragmaRandomNoise::new(0,1.0.into(), 1.0.into(), 1.0.into()).into(); "PragmaRandomNoise")] +#[test_case(test_roqoqo_1_12::operations::PragmaGeneralNoise::new(0, 0.1.into(), ndarray::array![[1.0.into(), 0.0.into()], [1.0.into(), 2.0.into()]]).into(); "PragmaGeneralNoise")] +#[test_case(test_roqoqo_1_12::operations::PragmaConditional::new("ro".to_string(),0, test_roqoqo_1_12::Circuit::new()).into(); "PragmaConditional")] +// #[test_case(test_roqoqo_1_12::operations::PragmaChangeDevice::new(&"PragmaTest".into()).unwrap().into(); "PragmaChangeDevice")] +#[test_case(test_roqoqo_1_12::operations::CNOT::new(0,1).into(); "CNOT")] +#[test_case(test_roqoqo_1_12::operations::SWAP::new(0,1).into(); "SWAP")] +#[test_case(test_roqoqo_1_12::operations::FSwap::new(0,1).into(); "FSwap")] +#[test_case(test_roqoqo_1_12::operations::ISwap::new(0,1).into(); "ISwap")] +#[test_case(test_roqoqo_1_12::operations::SqrtISwap::new(0,1).into(); "SqrtISWAP")] +#[test_case(test_roqoqo_1_12::operations::InvSqrtISwap::new(0,1).into(); "InvSqrtISWAP")] +#[test_case(test_roqoqo_1_12::operations::XY::new(0,1, 0.1.into()).into(); "XY")] +#[test_case(test_roqoqo_1_12::operations::ControlledPhaseShift::new(0,1, 0.1.into()).into(); "ControlledPhase")] +#[test_case(test_roqoqo_1_12::operations::ControlledPauliY::new(0,1).into(); "ControlledPauliY")] +#[test_case(test_roqoqo_1_12::operations::ControlledPauliZ::new(0,1).into(); "ControlledPauliZ")] +#[test_case(test_roqoqo_1_12::operations::MolmerSorensenXX::new(0,1).into(); "MolmerSorensenXX")] +#[test_case(test_roqoqo_1_12::operations::VariableMSXX::new(0,1, 0.1.into()).into(); "VariableMSXX")] +#[test_case(test_roqoqo_1_12::operations::GivensRotation::new(0,1, 0.1.into(), 0.1.into()).into(); "GivensRotation")] +#[test_case(test_roqoqo_1_12::operations::GivensRotationLittleEndian::new(0,1, 0.1.into(), 0.1.into()).into(); "GivensRotationLittleEndian")] +#[test_case(test_roqoqo_1_12::operations::Qsim::new(0,1, 0.1.into(), 0.1.into(), 0.1.into()).into(); "Qsim")] +#[test_case(test_roqoqo_1_12::operations::Fsim::new(0,1, 0.1.into(), 0.1.into(), 0.1.into()).into(); "Fsim")] +#[test_case(test_roqoqo_1_12::operations::SpinInteraction::new(0,1, 0.1.into(), 0.1.into(), 0.1.into()).into(); "SpinInteraction")] +#[test_case(test_roqoqo_1_12::operations::Bogoliubov::new(0,1, 0.1.into(), 0.1.into()).into(); "Bogoliubov")] +#[test_case(test_roqoqo_1_12::operations::PMInteraction::new(0,1, 0.1.into()).into(); "PMInteraction")] +#[test_case(test_roqoqo_1_12::operations::ComplexPMInteraction::new(0,1, 0.1.into(), 0.1.into()).into(); "ComplexPMInteraction")] +#[test_case(test_roqoqo_1_12::operations::PhaseShiftedControlledZ::new(0,1, 1.0.into()).into(); "PhaseShiftedControlledZ")] +#[test_case(test_roqoqo_1_12::operations::PhaseShiftState1::new(0, 1.0.into()).into(); "PhaseShiftState1")] +#[test_case(test_roqoqo_1_12::operations::PhaseShiftState0::new(0, 1.0.into()).into(); "PhaseShiftState0")] +#[test_case(test_roqoqo_1_12::operations::MultiQubitMS::new(vec![0,2,3], 1.0.into()).into(); "MultiQubitMS")] +#[test_case(test_roqoqo_1_12::operations::MultiQubitZZ::new(vec![0,2,3], 1.0.into()).into(); "MultiQubitZZ")] +// 1.1 and 1.2 +#[test_case(test_roqoqo_1_12::operations::InputBit::new("input".to_string(), 1, true).into(); "InputBit")] +#[test_case(test_roqoqo_1_12::operations::PragmaLoop::new(2.0.into(), test_roqoqo_1_12::Circuit::new()).into(); "PragmaLoop")] +#[test_case(test_roqoqo_1_12::operations::PhaseShiftedControlledPhase::new(0,1, 1.0.into(), 1.0.into()).into(); "PhaseShiftedControlledPhase")] +// 1.3 +#[test_case(test_roqoqo_1_12::operations::ControlledRotateX::new(0,1, 1.0.into()).into(); "ControlledRotateX")] +#[test_case(test_roqoqo_1_12::operations::ControlledRotateXY::new(0,1, 1.0.into(), 1.0.into()).into(); "ControlledRotateXY")] +#[test_case(test_roqoqo_1_12::operations::ControlledControlledPauliZ::new(0,1,2).into(); "ControlledControlledPauliZ")] +#[test_case(test_roqoqo_1_12::operations::ControlledControlledPhaseShift::new(0,1,2, 1.0.into()).into(); "ControlledControlledPhaseShift")] +#[test_case(test_roqoqo_1_12::operations::Toffoli::new(0,1,2).into(); "Toffoli")] +// 1.4 +#[test_case(test_roqoqo_1_12::operations::GPi::new(0, 0.1.into()).into(); "GPi")] +#[test_case(test_roqoqo_1_12::operations::GPi2::new(0, 0.1.into()).into(); "GPi2")] +// 1.5 +#[test_case(test_roqoqo_1_12::operations::PragmaControlledCircuit::new(0, test_roqoqo_1_12::Circuit::new()).into(); "PragmaControlledCircuit")] +// Operations from 1.6 +#[test_case(test_roqoqo_1_12::operations::Squeezing::new(0, 0.1.into(), 0.1.into()).into(); "Squeezing")] +#[test_case(test_roqoqo_1_12::operations::PhaseShift::new(0, 0.1.into()).into(); "PhaseShift")] +#[test_case(test_roqoqo_1_12::operations::BeamSplitter::new(0, 1, 0.1.into(), 0.2.into()).into(); "BeamSplitter")] +#[test_case(test_roqoqo_1_12::operations::PhotonDetection::new(0, "ro".into(), 0).into(); "PhotonDetection")] +// Operations from 1.7 +#[test_case(test_roqoqo_1_12::operations::Identity::new(0).into(); "Identity")] +// Operations from 1.8 +#[test_case(test_roqoqo_1_12::operations::PhaseDisplacement::new(0, 0.1.into(), 0.1.into()).into(); "PhaseDisplacement")] +#[test_case(test_roqoqo_1_12::operations::EchoCrossResonance::new(0, 1).into(); "EchoCrossResonance")] +#[test_case(test_roqoqo_1_12::operations::PragmaAnnotatedOp::new(test_roqoqo_1_12::operations::PauliX::new(0).into(), "test".to_string()).into(); "PragmaAnnotatedOp")] +// Operations from 1.9 - nothing was added +// Operations from 1.10 +// QuantumRabi, LongitudinalCoupling, JaynesCummings, SingleExcitationLoad, SingleExcitationStore and CZQubitResonator were all added +// as unstable, but have been added as stable in 1.11 +// Operations from 1.11 +#[test_case(test_roqoqo_1_12::operations::QuantumRabi::new(0, 1, 0.1.into()).into(); "QuantumRabi")] +#[test_case(test_roqoqo_1_12::operations::LongitudinalCoupling::new(0, 1, 0.1.into()).into(); "LongitudinalCoupling")] +#[test_case(test_roqoqo_1_12::operations::JaynesCummings::new(0, 1, 0.1.into()).into(); "JaynesCummings")] +#[test_case(test_roqoqo_1_12::operations::SingleExcitationLoad::new(0, 1).into(); "SingleExcitationLoad")] +#[test_case(test_roqoqo_1_12::operations::SingleExcitationStore::new(0, 1).into(); "SingleExcitationStore")] +#[test_case(test_roqoqo_1_12::operations::CZQubitResonator::new(0, 1).into(); "CZQubitResonator")] +// Operations from 1.11 - ApplyConstantSpinHamiltonian and ApplyTimeDependentHamiltonian are unstable in 1.11 +// #[test_case(create_apply_constant_spin_hamiltonian(); "ApplyConstantSpinHamiltonian")] +// #[test_case(create_apply_timedependent_spin_hamiltonian(); "ApplyTimeDependentHamiltonian")] +// Operations from 1.13 - GateDefinition and CallDefined gate are unstable, uncomment when stable. +// #[test_case(test_roqoqo_1_12::operations::GateDefinition::new(test_roqoqo_1_12::Circuit::new(), "name".into(), vec![0, 1], vec!["param".into()]).into(); "GateDefinition")] +// #[test_case(test_roqoqo_1_12::operations::CallDefinedGate::new("name".into(), vec![0, 1], vec![0.0]).into(); "CallDefinedGate")] +fn test_bincode_compatibility_1_12(operation: test_roqoqo_1_12::operations::Operation) { + let mut test_circuit = test_roqoqo_1_12::Circuit::new(); + test_circuit += operation; + + let test_measurement_input = test_roqoqo_1_12::measurements::PauliZProductInput::new(3, false); + let test_measurement = test_roqoqo_1_12::measurements::PauliZProduct { + constant_circuit: Some(test_circuit.clone()), + circuits: vec![test_circuit], + input: test_measurement_input, + }; + let test_program = test_roqoqo_1_12::QuantumProgram::PauliZProduct { + measurement: test_measurement, + input_parameter_names: vec!["test".to_string()], + }; + let test_serialisation: Vec = bincode::serialize(&test_program).unwrap(); + + let _test_deserialisation: roqoqo::QuantumProgram = + bincode::deserialize(&test_serialisation).unwrap(); +} + +#[test] +fn test_device_compat() { + let test_device = test_roqoqo_1_12::devices::AllToAllDevice::new( + 3, + &["RotateZ".to_string()], + &["CNOT".to_string()], + 1.0, + ); + let test_serialisation: Vec = bincode::serialize(&test_device).unwrap(); + + let test_deserialisation: roqoqo::devices::AllToAllDevice = + bincode::deserialize(&test_serialisation).unwrap(); + + let comparsion_device = roqoqo::devices::AllToAllDevice::new( + 3, + &["RotateZ".to_string()], + &["CNOT".to_string()], + 1.0, + ); + assert_eq!(test_deserialisation, comparsion_device); +} + +// Operations from 1.11 - ApplyConstantSpinHamiltonian and ApplyTimeDependentHamiltonian are unstable in 1.11 +// use struqture; +// use struqture::prelude::*; +// fn create_apply_constant_spin_hamiltonian( +// ) -> test_roqoqo_1_12::operations::ApplyConstantSpinHamiltonian { +// let pp = struqture::spins::PauliProduct::new().z(0); +// let mut hamiltonian = struqture::spins::SpinHamiltonian::new(); +// hamiltonian +// .add_operator_product(pp.clone(), 1.0.into()) +// .unwrap(); +// return test_roqoqo_1_12::operations::ApplyConstantSpinHamiltonian::new( +// hamiltonian, +// 1.0.into(), +// ); +// } + +// fn create_apply_timedependent_spin_hamiltonian( +// ) -> test_roqoqo_1_12::operations::ApplyTimeDependentSpinHamiltonian { +// let pp = struqture::spins::PauliProduct::new().z(0); +// let mut hamiltonian = struqture::spins::SpinHamiltonian::new(); +// hamiltonian +// .add_operator_product(pp.clone(), "omega".into()) +// .unwrap(); +// let mut values = HashMap::new(); +// values.insert("omega".to_string(), vec![1.0]); +// return test_roqoqo_1_12::operations::ApplyTimeDependentSpinHamiltonian::new( +// hamiltonian, +// vec![1.0], +// values.clone(), +// ); +// } diff --git a/.compatibility_tests/compatibility_test_1_12/tests/integration/main.rs b/.compatibility_tests/compatibility_test_1_12/tests/integration/main.rs new file mode 100644 index 00000000..756385b4 --- /dev/null +++ b/.compatibility_tests/compatibility_test_1_12/tests/integration/main.rs @@ -0,0 +1,13 @@ +// Copyright © 2021-2023 HQS Quantum Simulations GmbH. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing permissions and +// limitations under the License. +#[cfg(test)] +mod compatibility_1_12; diff --git a/.compatibility_tests/compatibility_test_1_2/Cargo.toml b/.compatibility_tests/compatibility_test_1_2/Cargo.toml index 0c2e8963..d779951d 100644 --- a/.compatibility_tests/compatibility_test_1_2/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_2" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_2 = { package = "roqoqo", version = "=1.2.5" } test_roqoqo_derive_1_2 = { package = "roqoqo-derive", version = "=1.2.5" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_3/Cargo.toml b/.compatibility_tests/compatibility_test_1_3/Cargo.toml index 53759517..24ae6aeb 100644 --- a/.compatibility_tests/compatibility_test_1_3/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_3/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_3" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_3 = { package = "roqoqo", version = "=1.3.2" } test_roqoqo_derive_1_3 = { package = "roqoqo-derive", version = "=1.3.2" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_4/Cargo.toml b/.compatibility_tests/compatibility_test_1_4/Cargo.toml index 4f1f0e8f..9453a9d8 100644 --- a/.compatibility_tests/compatibility_test_1_4/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_4/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_4" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -21,8 +21,8 @@ publish = false [dependencies] test_roqoqo_1_4 = { package = "roqoqo", version = "=1.4.0" } test_roqoqo_derive_1_4 = { package = "roqoqo-derive", version = "=1.4.0" } -qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +qoqo_calculator = { version = "1.1" } +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_5/Cargo.toml b/.compatibility_tests/compatibility_test_1_5/Cargo.toml index 254f3876..77107825 100644 --- a/.compatibility_tests/compatibility_test_1_5/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_5" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_5 = { package = "roqoqo", version = "=1.5.0" } test_roqoqo_derive_1_5 = { package = "roqoqo-derive", version = "=1.5.0" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_6/Cargo.toml b/.compatibility_tests/compatibility_test_1_6/Cargo.toml index 9d763e53..79803295 100644 --- a/.compatibility_tests/compatibility_test_1_6/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_6/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_6" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_6 = { package = "roqoqo", version = "=1.6.1" } test_roqoqo_derive_1_6 = { package = "roqoqo-derive", version = "=1.6.1" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_7/Cargo.toml b/.compatibility_tests/compatibility_test_1_7/Cargo.toml index f3c6a541..dcdda5b4 100644 --- a/.compatibility_tests/compatibility_test_1_7/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_7/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_7" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_7 = { package = "roqoqo", version = "=1.7.1" } test_roqoqo_derive_1_7 = { package = "roqoqo-derive", version = "=1.7.1" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_8/Cargo.toml b/.compatibility_tests/compatibility_test_1_8/Cargo.toml index 8bf4837b..88d0dd2c 100644 --- a/.compatibility_tests/compatibility_test_1_8/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_8/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_8" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_8 = { package = "roqoqo", version = "=1.8.0" } test_roqoqo_derive_1_8 = { package = "roqoqo-derive", version = "=1.8.0" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_1_9/Cargo.toml b/.compatibility_tests/compatibility_test_1_9/Cargo.toml index 9be4f66d..bc99e35a 100644 --- a/.compatibility_tests/compatibility_test_1_9/Cargo.toml +++ b/.compatibility_tests/compatibility_test_1_9/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_1_9" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -22,7 +22,7 @@ publish = false test_roqoqo_1_9 = { package = "roqoqo", version = "=1.9.0" } test_roqoqo_derive_1_9 = { package = "roqoqo-derive", version = "=1.9.0" } qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../../roqoqo", features = [ +roqoqo = { version = "1.13.0", path = "../../roqoqo", features = [ "serialize", "overrotate", ] } diff --git a/.compatibility_tests/compatibility_test_sim/Cargo.toml b/.compatibility_tests/compatibility_test_sim/Cargo.toml index a6d18e8e..fc86ba69 100644 --- a/.compatibility_tests/compatibility_test_sim/Cargo.toml +++ b/.compatibility_tests/compatibility_test_sim/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compatibility_test_sim" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d8a5da..11b89e9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ This changelog track changes to the qoqo project starting at version v0.5.0 +## 1.13.0 + +### Added in 1.13.0 + +* Unstable feature `unstable_operation_definition` adding new operations: GateDefinition and CallDefinedGate. + ## 1.12.1 ### Added in 1.12.1 diff --git a/Cargo.lock b/Cargo.lock index 6af63695..31397d2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -245,7 +245,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -419,7 +419,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1077,7 +1077,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1090,12 +1090,12 @@ dependencies = [ "proc-macro2", "pyo3-build-config 0.21.2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] name = "qoqo" -version = "1.12.1" +version = "1.13.0" dependencies = [ "bincode", "nalgebra", @@ -1115,19 +1115,19 @@ dependencies = [ "serde_json", "struqture", "struqture-py", - "syn 2.0.65", + "syn 2.0.66", "test-case", "thiserror", ] [[package]] name = "qoqo-macros" -version = "1.12.1" +version = "1.13.0" dependencies = [ "proc-macro2", "quote", "struqture", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1287,7 +1287,7 @@ dependencies = [ [[package]] name = "roqoqo" -version = "1.12.1" +version = "1.13.0" dependencies = [ "async-trait", "bincode", @@ -1309,7 +1309,7 @@ dependencies = [ "serde_json", "serde_test", "struqture", - "syn 2.0.65", + "syn 2.0.66", "test-case", "thiserror", "typetag", @@ -1317,16 +1317,16 @@ dependencies = [ [[package]] name = "roqoqo-derive" -version = "1.12.1" +version = "1.13.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] name = "roqoqo-test" -version = "1.12.1" +version = "1.13.0" dependencies = [ "nalgebra", "ndarray", @@ -1335,7 +1335,7 @@ dependencies = [ "quote", "rand", "roqoqo", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1367,9 +1367,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -1379,14 +1379,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1412,7 +1412,7 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1423,7 +1423,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1539,7 +1539,7 @@ dependencies = [ "serde_json", "struqture", "struqture-py-macros", - "syn 2.0.65", + "syn 2.0.66", "thiserror", ] @@ -1552,7 +1552,7 @@ dependencies = [ "num-complex", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1568,9 +1568,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.65" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -1628,7 +1628,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1639,7 +1639,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "test-case-core", ] @@ -1660,7 +1660,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1801,7 +1801,7 @@ checksum = "ac73887f47b9312552aa90ef477927ff014d63d1920ca8037c6c1951eab64bb1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1896,7 +1896,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -1930,7 +1930,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2127,5 +2127,5 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] diff --git a/qoqo-macros/Cargo.toml b/qoqo-macros/Cargo.toml index 860d9c9f..bf408fae 100644 --- a/qoqo-macros/Cargo.toml +++ b/qoqo-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "qoqo-macros" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" readme = "../README.md" diff --git a/qoqo-macros/src/lib.rs b/qoqo-macros/src/lib.rs index a014ab42..4a7b54d1 100644 --- a/qoqo-macros/src/lib.rs +++ b/qoqo-macros/src/lib.rs @@ -394,7 +394,7 @@ pub fn wrap( /// Return list of qubits of the multi qubit operation in order of descending significance /// /// Returns: - /// list[int] + /// List[int] pub fn qubits(&self) -> Vec{ self.internal.qubits().clone() } @@ -447,7 +447,7 @@ pub fn wrap( /// List of modes the operation acts on. /// /// Returns: - /// Union[set[int], str]: The involved qubits as a set or 'ALL' if all qubits are involved + /// Union[Set[int], str]: The involved qubits as a set or 'ALL' if all qubits are involved pub fn involved_modes(&self) -> PyObject { Python::with_gil(|py| -> PyObject { let involved = self.internal.involved_modes(); @@ -484,7 +484,7 @@ pub fn wrap( /// Remap the bosonic modes in copy of the operation. /// /// Args: - /// mapping (dict[int, int]): Mapping for bosonic modes in operation. + /// mapping (Dict[int, int]): Mapping for bosonic modes in operation. /// /// Returns: /// self diff --git a/qoqo-macros/src/operate.rs b/qoqo-macros/src/operate.rs index 715e2979..0aceee76 100644 --- a/qoqo-macros/src/operate.rs +++ b/qoqo-macros/src/operate.rs @@ -211,7 +211,7 @@ fn operate_struct(ds: DataStruct, ident: Ident) -> TokenStream { /// Returns tags identifying the Operation /// /// Returns: - /// list[str]: The tags identifying the operation + /// List[str]: The tags identifying the operation fn tags(&self) -> Vec{ self.internal.tags().iter().map(|s| s.to_string()).collect() } @@ -230,7 +230,7 @@ fn operate_struct(ds: DataStruct, ident: Ident) -> TokenStream { /// provided parameters. /// /// Args: - /// substitution_parameters (dict[str, float]): The substituted free parameters + /// substitution_parameters (Dict[str, float]): The substituted free parameters /// /// Returns: /// Operation: The operation with the parameters substituted @@ -250,7 +250,7 @@ fn operate_struct(ds: DataStruct, ident: Ident) -> TokenStream { /// Remap qubits /// /// Args: - /// mapping (dict[int, int]): The mapping + /// mapping (Dict[int, int]): The mapping /// /// Returns: /// Operation: The operation with the remapped qubits @@ -267,7 +267,7 @@ fn operate_struct(ds: DataStruct, ident: Ident) -> TokenStream { /// List all involved Qubits /// /// Returns: - /// Union[set[int], str]: The involved qubits as a set or 'ALL' if all qubits are involved + /// Union[Set[int], str]: The involved qubits as a set or 'ALL' if all qubits are involved fn involved_qubits(&self) -> PyObject { Python::with_gil(|py| -> PyObject { let involved = self.internal.involved_qubits(); diff --git a/qoqo/Cargo.toml b/qoqo/Cargo.toml index ba39267f..17ef65d1 100644 --- a/qoqo/Cargo.toml +++ b/qoqo/Cargo.toml @@ -1,6 +1,7 @@ [package] + +version = "1.13.0" name = "qoqo" -version = "1.12.1" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" homepage = "https://github.com/HQSquantumsimulations/qoqo" @@ -39,8 +40,8 @@ num-complex = "0.4" thiserror = "1.0" qoqo_calculator = { version = "1.2" } qoqo_calculator_pyo3 = { version = "1.2", default-features = false } -qoqo-macros = { version = "1.12.1", path = "../qoqo-macros" } -roqoqo = { version = "1.12.1", path = "../roqoqo", features = [ +qoqo-macros = { version = "1.13.0", path = "../qoqo-macros" } +roqoqo = { version = "1.13.0", path = "../roqoqo", features = [ "serialize", "overrotate", ] } @@ -74,3 +75,4 @@ unstable_chain_with_environment = [ "qoqo-macros/unstable_chain_with_environment", ] unstable_analog_operations = ["roqoqo/unstable_analog_operations"] +unstable_operation_definition = ["roqoqo/unstable_operation_definition"] diff --git a/qoqo/build.rs b/qoqo/build.rs index f4e35d2e..12b9c920 100644 --- a/qoqo/build.rs +++ b/qoqo/build.rs @@ -21,8 +21,8 @@ use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::visit::{self, Visit}; use syn::{ - AttrStyle, Fields, File, GenericArgument, Ident, ItemStruct, Macro, Path, PathArguments, Token, - Type, TypePath, + AttrStyle, Fields, File, GenericArgument, Ident, ItemStruct, LitStr, Macro, Path, + PathArguments, Token, Type, TypePath, }; type StructFieldInfo = Vec<(Ident, Option, Type)>; @@ -48,6 +48,18 @@ impl Visitor { } } +#[derive(Debug, Eq, PartialEq)] +struct CfgFeatureMacroArgument(String); + +impl Parse for CfgFeatureMacroArgument { + fn parse(input: ParseStream) -> syn::parse::Result { + input.parse::()?; + input.parse::()?; + let feature_name: LitStr = input.parse()?; + Ok(Self(feature_name.value())) + } +} + /// Struct for parsed derive macro arguments. Used to identify structs belonging to enums #[allow(dead_code)] #[derive(Debug)] @@ -87,6 +99,17 @@ impl<'ast> Visit<'ast> for Visitor { // Check attributes for att in itemstruct.attrs.clone() { let path = att.path().get_ident().map(|id| id.to_string()); + // TOFIX: REMOVE WHEN STABILISED + if matches!(att.style, AttrStyle::Outer) + && path == Some("cfg".to_string()) + && !cfg!(feature = "unstable_operation_definition") + { + let cfg_feature_name: CfgFeatureMacroArgument = + att.parse_args().expect("parsing failed 1"); + if cfg_feature_name.0.contains("unstable_operation_definition") { + return; + } + } // only consider the wrap attribute, if no derive attribute is present don't add anything // to the internal storage of the visitor if matches!(att.style, AttrStyle::Outer) && path == Some("wrap".to_string()) { @@ -104,6 +127,14 @@ impl<'ast> Visit<'ast> for Visitor { Some(id) => Some(id.clone()), _ => i.path.segments.last().map(|segment| segment.ident.clone()), }; + // TOFIX: REMOVE WHEN STABILISED + if i.tokens.clone().into_iter().any(|tok| { + tok.to_string().contains("CallDefinedGate") + || tok.to_string().contains("DefinitionGate") + }) && !cfg!(feature = "unstable_operation_definition") + { + return; + } if let Some(ident) = id { if ident.to_string().as_str() == "insert_pyany_to_operation" { self.pyany_to_operation.push(i.tokens.clone()) @@ -297,7 +328,7 @@ fn extract_fields_with_types(input_fields: Fields) -> Vec<(Ident, Option .ident .expect("Operate can only be derived on structs with named fields"); let ty = f.ty; - let type_path =match &ty { + let type_path = match &ty { Type::Path(TypePath{path:p,..}) => p, _ => panic!("Trait only supports fields with normal types of form path (e.g. CalculatorFloat, qoqo_calculator::CalculatorFloat)") }; diff --git a/qoqo/pyproject.toml b/qoqo/pyproject.toml index 50083173..28aff380 100644 --- a/qoqo/pyproject.toml +++ b/qoqo/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "qoqo" -version = "1.12.1" +version = "1.13.0" dependencies = ['numpy', 'qoqo_calculator_pyo3>=1.2'] license = { text = "Apache-2.0 AND Apache-2.0 with LLVM-exception AND MIT AND Unicode-DFS-2016 AND BSD-2-Clause AND BSD-3-CLause" } maintainers = [ diff --git a/qoqo/qoqo/DEPENDENCIES b/qoqo/qoqo/DEPENDENCIES index 4689fb95..f1a72b12 100644 --- a/qoqo/qoqo/DEPENDENCIES +++ b/qoqo/qoqo/DEPENDENCIES @@ -245,6 +245,22 @@ https://github.com/jonas-schievink/adler.git by Jonas Schievink A simple clean-room implementation of the Adler-32 checksum License: 0BSD OR MIT OR Apache-2.0 +---------------------------------------------------- +LICENSE-0BSD: + +Copyright (C) Jonas Schievink + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ---------------------------------------------------- LICENSE-MIT: @@ -272,22 +288,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------- -LICENSE-0BSD: - -Copyright (C) Jonas Schievink - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ---------------------------------------------------- LICENSE-APACHE: @@ -741,31 +741,6 @@ https://github.com/BurntSushi/aho-corasick by Andrew Gallant Fast multiple substring searching. License: Unlicense OR MIT ----------------------------------------------------- -LICENSE-MIT: - -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---------------------------------------------------- UNLICENSE: @@ -794,6 +769,31 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to +---------------------------------------------------- +LICENSE-MIT: + +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + ---------------------------------------------------- COPYING: @@ -4379,6 +4379,29 @@ https://github.com/llogiq/bytecount by Andre Bogus , Joshua Landau count occurrences of a given byte, or the number of UTF-8 code points, in a byte slice, fast License: Apache-2.0/MIT +---------------------------------------------------- +LICENSE.MIT: + +Copyright (c) 2017 The bytecount Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ---------------------------------------------------- LICENSE.Apache2: @@ -4584,29 +4607,6 @@ LICENSE.Apache2: See the License for the specific language governing permissions and limitations under the License. ----------------------------------------------------- -LICENSE.MIT: - -Copyright (c) 2017 The bytecount Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ==================================================== bytemuck 1.16.0 @@ -4627,21 +4627,6 @@ The above copyright notice and this permission notice (including the next paragr THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------- -LICENSE-ZLIB: - -Copyright (c) 2019 Daniel "Lokathor" Gee. - -This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source distribution. - ---------------------------------------------------- LICENSE-APACHE: @@ -4707,6 +4692,21 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +---------------------------------------------------- +LICENSE-ZLIB: + +Copyright (c) 2019 Daniel "Lokathor" Gee. + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + ==================================================== bytes 1.6.0 @@ -6903,29 +6903,6 @@ https://github.com/jhpratt/deranged by Jacob Pratt Ranged integers License: MIT OR Apache-2.0 ----------------------------------------------------- -LICENSE-MIT: - -Copyright (c) 2022 Jacob Pratt et al. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---------------------------------------------------- LICENSE-Apache: @@ -7132,6 +7109,29 @@ LICENSE-Apache: See the License for the specific language governing permissions and limitations under the License. +---------------------------------------------------- +LICENSE-MIT: + +Copyright (c) 2022 Jacob Pratt et al. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ==================================================== dyn-clone 1.0.17 @@ -7624,36 +7624,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------- -LICENSE-WHATWG: - -Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---------------------------------------------------- LICENSE-APACHE: @@ -7860,6 +7830,36 @@ LICENSE-APACHE: See the License for the specific language governing permissions and limitations under the License. +---------------------------------------------------- +LICENSE-WHATWG: + +Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==================================================== equivalent 1.0.1 @@ -16124,31 +16124,6 @@ Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for 1, 2 or 3 byte search and single substring search. License: Unlicense OR MIT ----------------------------------------------------- -LICENSE-MIT: - -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---------------------------------------------------- UNLICENSE: @@ -16177,6 +16152,31 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to +---------------------------------------------------- +LICENSE-MIT: + +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + ---------------------------------------------------- COPYING: @@ -16456,6 +16456,33 @@ https://github.com/Alexhuszagh/minimal-lexical by Alex Huszagh Fast float parsing conversion routines. License: MIT/Apache-2.0 +---------------------------------------------------- +LICENSE-MIT: + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ---------------------------------------------------- LICENSE.md: @@ -16497,33 +16524,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------- -LICENSE-MIT: - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - ---------------------------------------------------- LICENSE-APACHE: @@ -16737,19 +16737,54 @@ by Frommi , oyvindln allocation, and avoid repetitive calculations. License: MIT OR Apache-2.0 ----------------------------------------------------- -LICENSE-MIT: - -Copyright (c) 2023 Jacob Pratt et al. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---------------------------------------------------- LICENSE-Apache: @@ -22441,6 +22418,29 @@ LICENSE-Apache: See the License for the specific language governing permissions and limitations under the License. +---------------------------------------------------- +LICENSE-MIT: + +Copyright (c) 2023 Jacob Pratt et al. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ==================================================== ppv-lite86 0.2.17 @@ -24272,7 +24272,7 @@ LICENSE-APACHE: ==================================================== -qoqo 1.12.1 +qoqo 1.13.0 https://github.com/HQSquantumsimulations/qoqo by HQS Quantum Simulations Quantum computing circuit toolkit. Python interface of roqoqo @@ -24484,7 +24484,7 @@ LICENSE: ==================================================== -qoqo-macros 1.12.1 +qoqo-macros 1.13.0 by HQS Quantum Simulations Macros for the qoqo crate License: Apache-2.0 @@ -27490,7 +27490,7 @@ limitations under the License. ==================================================== -roqoqo 1.12.1 +roqoqo 1.13.0 https://github.com/HQSquantumsimulations/qoqo by HQS Quantum Simulations Rust Quantum Computing Toolkit by HQS @@ -27702,7 +27702,7 @@ LICENSE: ==================================================== -roqoqo-derive 1.12.1 +roqoqo-derive 1.13.0 by HQS Quantum Simulations Macros for the roqoqo crate License: Apache-2.0 @@ -27913,7 +27913,7 @@ LICENSE: ==================================================== -roqoqo-test 1.12.1 +roqoqo-test 1.13.0 https://github.com/HQSquantumsimulations/qoqo by HQS Quantum Simulations Testing helper functions for roqoqo toolkit @@ -28826,19 +28826,17 @@ by Lokathor Crate that exposes `core::arch` safely via `#[cfg()]`. License: Zlib OR Apache-2.0 OR MIT ---------------------------------------------------- -LICENSE-ZLIB.md: +LICENSE-MIT.md: -Copyright (c) 2020 Daniel "Lokathor" Gee. - -This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +MIT License -Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +Copyright (c) 2023 Daniel "Lokathor" Gee. -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. -3. This notice may not be removed or altered from any source distribution. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------- LICENSE-APACHE.md: @@ -28906,21 +28904,23 @@ See the License for the specific language governing permissions and limitations under the License. ---------------------------------------------------- -LICENSE-MIT.md: +LICENSE-ZLIB.md: -MIT License +Copyright (c) 2020 Daniel "Lokathor" Gee. -Copyright (c) 2023 Daniel "Lokathor" Gee. +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. ==================================================== -schemars 0.8.20 +schemars 0.8.21 https://graham.cool/schemars/ by Graham Esau Generate JSON Schemas from Rust code @@ -28952,7 +28952,7 @@ SOFTWARE. ==================================================== -schemars_derive 0.8.20 +schemars_derive 0.8.21 https://graham.cool/schemars/ by Graham Esau Macros for #[derive(JsonSchema)], for use with schemars @@ -31951,7 +31951,7 @@ limitations under the License. ==================================================== -syn 2.0.65 +syn 2.0.66 https://github.com/dtolnay/syn by David Tolnay Parser for Rust source code @@ -33127,29 +33127,6 @@ https://time-rs.github.io by Jacob Pratt , Time contributors Date and time library. Fully interoperable with the standard library. Mostly compatible with #![no_std]. License: MIT OR Apache-2.0 ----------------------------------------------------- -LICENSE-MIT: - -Copyright (c) 2024 Jacob Pratt et al. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---------------------------------------------------- LICENSE-Apache: @@ -33356,17 +33333,10 @@ LICENSE-Apache: See the License for the specific language governing permissions and limitations under the License. - -==================================================== -time-core 0.1.2 -https://github.com/time-rs/time -by Jacob Pratt , Time contributors -This crate is an implementation detail and should not be relied upon directly. -License: MIT OR Apache-2.0 ---------------------------------------------------- LICENSE-MIT: -Copyright (c) 2022 Jacob Pratt et al. +Copyright (c) 2024 Jacob Pratt et al. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -33386,6 +33356,13 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==================================================== +time-core 0.1.2 +https://github.com/time-rs/time +by Jacob Pratt , Time contributors +This crate is an implementation detail and should not be relied upon directly. +License: MIT OR Apache-2.0 ---------------------------------------------------- LICENSE-Apache: @@ -33592,19 +33569,10 @@ LICENSE-Apache: See the License for the specific language governing permissions and limitations under the License. - -==================================================== -time-macros 0.2.18 -https://github.com/time-rs/time -by Jacob Pratt , Time contributors - Procedural macros for the time crate. - This crate is an implementation detail and should not be relied upon directly. - -License: MIT OR Apache-2.0 ---------------------------------------------------- LICENSE-MIT: -Copyright (c) 2024 Jacob Pratt et al. +Copyright (c) 2022 Jacob Pratt et al. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -33624,6 +33592,15 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==================================================== +time-macros 0.2.18 +https://github.com/time-rs/time +by Jacob Pratt , Time contributors + Procedural macros for the time crate. + This crate is an implementation detail and should not be relied upon directly. + +License: MIT OR Apache-2.0 ---------------------------------------------------- LICENSE-Apache: @@ -33830,6 +33807,29 @@ LICENSE-Apache: See the License for the specific language governing permissions and limitations under the License. +---------------------------------------------------- +LICENSE-MIT: + +Copyright (c) 2024 Jacob Pratt et al. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ==================================================== tinyvec 1.6.0 @@ -33838,19 +33838,13 @@ by Lokathor `tinyvec` provides 100% safe vec-like data structures. License: Zlib OR Apache-2.0 OR MIT ---------------------------------------------------- -LICENSE-ZLIB.md: +LICENSE-MIT.md: -Copyright (c) 2019 Daniel "Lokathor" Gee. - -This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -3. This notice may not be removed or altered from any source distribution. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------- LICENSE-APACHE.md: @@ -34059,13 +34053,19 @@ LICENSE-APACHE.md: limitations under the License. ---------------------------------------------------- -LICENSE-MIT.md: +LICENSE-ZLIB.md: -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Copyright (c) 2019 Daniel "Lokathor" Gee. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. ==================================================== @@ -34075,28 +34075,29 @@ by Soveu Some macros for tiny containers License: MIT OR Apache-2.0 OR Zlib ---------------------------------------------------- -LICENSE-ZLIB.md: - -zlib License +LICENSE-MIT.md: -(C) 2020 Tomasz "Soveu" Marx +MIT License -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. +Copyright (c) 2020 Soveu -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ---------------------------------------------------- LICENSE-APACHE.md: @@ -34305,29 +34306,28 @@ LICENSE-APACHE.md: ---------------------------------------------------- -LICENSE-MIT.md: +LICENSE-ZLIB.md: -MIT License +zlib License -Copyright (c) 2020 Soveu +(C) 2020 Tomasz "Soveu" Marx -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ==================================================== @@ -34558,6 +34558,10 @@ Typenum is a Rust library for type-level numbers evaluated at implementation is incomplete. License: MIT OR Apache-2.0 ---------------------------------------------------- +LICENSE: + +MIT OR Apache-2.0 +---------------------------------------------------- LICENSE-MIT: The MIT License (MIT) @@ -34786,10 +34790,6 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ----------------------------------------------------- -LICENSE: - -MIT OR Apache-2.0 ==================================================== unicode-bidi 0.3.15 @@ -35038,33 +35038,6 @@ https://github.com/dtolnay/unicode-ident by David Tolnay Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31 License: (MIT OR Apache-2.0) AND Unicode-DFS-2016 ----------------------------------------------------- -LICENSE-MIT: - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - ---------------------------------------------------- LICENSE-UNICODE: @@ -35115,6 +35088,33 @@ shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. +---------------------------------------------------- +LICENSE-MIT: + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ---------------------------------------------------- LICENSE-APACHE: @@ -36726,33 +36726,6 @@ https://github.com/bytecodealliance/wasi by The Cranelift Project Developers Experimental WASI API bindings for Rust License: Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT ----------------------------------------------------- -LICENSE-MIT: - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - ---------------------------------------------------- LICENSE-Apache-2.0_WITH_LLVM-exception: @@ -36977,6 +36950,33 @@ the License, but only in their entirety and only with respect to the Combined Software. +---------------------------------------------------- +LICENSE-MIT: + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ---------------------------------------------------- LICENSE-APACHE: @@ -43438,6 +43438,34 @@ https://github.com/google/zerocopy by Joshua Liebow-Feeser Utilities for zero-copy parsing and serialization License: BSD-2-Clause OR Apache-2.0 OR MIT +---------------------------------------------------- +LICENSE-BSD: + +Copyright 2019 The Fuchsia Authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------- LICENSE-MIT: @@ -43674,6 +43702,13 @@ LICENSE-APACHE: limitations under the License. + +==================================================== +zerocopy-derive 0.7.34 +https://github.com/google/zerocopy +by Joshua Liebow-Feeser +Custom derive for traits from the zerocopy crate +License: BSD-2-Clause OR Apache-2.0 OR MIT ---------------------------------------------------- LICENSE-BSD: @@ -43702,13 +43737,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -==================================================== -zerocopy-derive 0.7.34 -https://github.com/google/zerocopy -by Joshua Liebow-Feeser -Custom derive for traits from the zerocopy crate -License: BSD-2-Clause OR Apache-2.0 OR MIT ---------------------------------------------------- LICENSE-MIT: @@ -43945,32 +43973,4 @@ LICENSE-APACHE: limitations under the License. ----------------------------------------------------- -LICENSE-BSD: - -Copyright 2019 The Fuchsia Authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/qoqo/src/circuit.rs b/qoqo/src/circuit.rs index cbe5390b..7e931432 100644 --- a/qoqo/src/circuit.rs +++ b/qoqo/src/circuit.rs @@ -104,7 +104,7 @@ impl CircuitWrapper { /// Substitute the symbolic parameters in a clone of the Circuit according to the substitution_parameters input. /// /// Args: - /// substitution_parameters (dict[str, float]): The dictionary containing the substitutions to use in the Circuit. + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the Circuit. /// /// Returns: /// self: The Circuit with the parameters substituted. @@ -135,7 +135,7 @@ impl CircuitWrapper { /// Remap qubits in operations in clone of Circuit. /// /// Args: - /// mapping (dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the Circuit. + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the Circuit. /// /// Returns: /// self: The Circuit with the qubits remapped. @@ -182,7 +182,7 @@ impl CircuitWrapper { /// Count the number of occurences of a set of operation tags in the circuit. /// /// Args: - /// operations (list[str]): List of operation tags that should be counted. + /// operations (List[str]): List of operation tags that should be counted. /// /// Returns: /// int: The number of occurences of these operation tags. @@ -199,7 +199,7 @@ impl CircuitWrapper { /// Return a list of the hqslang names of all operations occuring in the circuit. /// /// Returns: - /// set[str]: The operation types in the Circuit. + /// Set[str]: The operation types in the Circuit. pub fn get_operation_types(&self) -> HashSet<&str> { let mut operations: HashSet<&str> = HashSet::new(); for op in self.internal.iter() { @@ -227,7 +227,7 @@ impl CircuitWrapper { /// Return the roqoqo and qoqo versions from when the code was compiled. /// /// Returns: - /// tuple[str, str]: The roqoqo and qoqo versions. + /// Tuple[str, str]: The roqoqo and qoqo versions. fn _qoqo_versions(&self) -> (String, String) { let mut rsplit = ROQOQO_VERSION.split('.').take(2); let mut qsplit = QOQO_VERSION.split('.').take(2); @@ -425,7 +425,7 @@ impl CircuitWrapper { /// Definitions need to be unique. /// /// Returns: - /// list[Operation]: A vector of the definitions in the Circuit. + /// List[Operation]: A vector of the definitions in the Circuit. pub fn definitions(&self) -> PyResult> { let mut defs: Vec = Vec::new(); for op in self @@ -443,7 +443,7 @@ impl CircuitWrapper { /// Return a list of all operations in the Circuit. /// /// Returns: - /// list[Operation]: A vector of the operations in the Circuit. + /// List[Operation]: A vector of the operations in the Circuit. pub fn operations(&self) -> PyResult> { let mut ops: Vec = Vec::new(); for op in self @@ -464,7 +464,7 @@ impl CircuitWrapper { /// tag (str): tag by which to filter operations. /// /// Returns: - /// list[Operation]: A vector of the operations with the specified tag in the Circuit. + /// List[Operation]: A vector of the operations with the specified tag in the Circuit. pub fn filter_by_tag(&self, tag: &str) -> PyResult> { let mut tagged: Vec = Vec::new(); for op in self diff --git a/qoqo/src/circuitdag.rs b/qoqo/src/circuitdag.rs index 3c298c8f..ee4b431a 100644 --- a/qoqo/src/circuitdag.rs +++ b/qoqo/src/circuitdag.rs @@ -155,11 +155,11 @@ impl CircuitDagWrapper { /// Checks if executing an operation is blocked by any not-yet executed operation. /// /// Args: - /// already_executed (list[int]): List of NodeIndices of Nodes that have already been executed in the Circuit. + /// already_executed (List[int]): List of NodeIndices of Nodes that have already been executed in the Circuit. /// to_be_executed (int): NodeIndex of the operation that should be executed next. /// /// Returns: - /// list[int]: List containing the sorted blocking elements. + /// List[int]: List containing the sorted blocking elements. #[pyo3(text_signature = "($self, already_executed, to_be_executed)")] pub fn execution_blocked( &self, @@ -178,11 +178,11 @@ impl CircuitDagWrapper { /// this method returning an empty vector does not imply that the `to_be_executed` operation can be executed. /// /// Args: - /// already_executed (list[int]): List of NodeIndices of Nodes that have already been executed in the Circuit. + /// already_executed (List[int]): List of NodeIndices of Nodes that have already been executed in the Circuit. /// to_be_executed (int): NodeIndex of the Operation that should be executed next. /// /// Returns: - /// list[int]: List containing the sorted blocking elements. + /// List[int]: List containing the sorted blocking elements. #[pyo3(text_signature = "($self, already_executed, to_be_executed)")] pub fn blocking_predecessors( &self, @@ -198,8 +198,8 @@ impl CircuitDagWrapper { /// Returns an error if operation to be executed is not in the current front layer. /// /// Args: - /// already_executed (list[int]): List of NodeIndices of Nodes that have already been executed in the Circuit. - /// current_front_layer (list[int]): List of NodeIndices in the current front layer ready to be executed if physically possible. + /// already_executed (List[int]): List of NodeIndices of Nodes that have already been executed in the Circuit. + /// current_front_layer (List[int]): List of NodeIndices in the current front layer ready to be executed if physically possible. /// to_be_executed (int): NodeIndex of the operation that should be executed next. #[pyo3(text_signature = "($self, already_executed, current_front_layer, to_be_executed)")] pub fn new_front_layer( @@ -302,7 +302,7 @@ impl CircuitDagWrapper { /// Return the roqoqo and qoqo versions from when the code was compiled. /// /// Returns: - /// tuple[str, str]: The roqoqo and qoqo versions. + /// Tuple[str, str]: The roqoqo and qoqo versions. #[pyo3(text_signature = "($self)")] fn _qoqo_versions(&self) -> (String, String) { let mut rsplit = ROQOQO_VERSION.split('.').take(2); @@ -371,7 +371,7 @@ impl CircuitDagWrapper { /// Returns the list of nodes of commuting operations in CircuitDag. /// /// Returns: - /// list[int]: The list of nodes of commuting operations. + /// List[int]: The list of nodes of commuting operations. #[pyo3(text_signature = "($self)")] pub fn commuting_operations(&self) -> Vec { self.internal.commuting_operations().to_vec() @@ -380,7 +380,7 @@ impl CircuitDagWrapper { /// Returns a set containing the nodes in the first parallel block. /// /// Returns: - /// set[int]: The set of nodes in the first parallel block. + /// Set[int]: The set of nodes in the first parallel block. #[pyo3(text_signature = "($self)")] pub fn first_parallel_block(&self) -> HashSet { self.internal.first_parallel_block().clone() @@ -389,7 +389,7 @@ impl CircuitDagWrapper { /// Returns a set containing the nodes in the last parallel block. /// /// Returns: - /// set[int]: The set of nodes in the last parallel block. + /// Set[int]: The set of nodes in the last parallel block. #[pyo3(text_signature = "($self)")] pub fn last_parallel_block(&self) -> HashSet { self.internal.last_parallel_block().clone() @@ -399,7 +399,7 @@ impl CircuitDagWrapper { /// the first node that involves that qubit. /// /// Returns: - /// dict[int, int]: The dictionary of {qubit: node} elements. + /// Dict[int, int]: The dictionary of {qubit: node} elements. #[pyo3(text_signature = "($self)")] pub fn first_operation_involving_qubit(&self) -> PyObject { Python::with_gil(|py| -> PyObject { @@ -413,7 +413,7 @@ impl CircuitDagWrapper { /// the last node that involves that qubit. /// /// Returns: - /// dict[int, int]: The dictionary of {qubit: node} elements. + /// Dict[int, int]: The dictionary of {qubit: node} elements. #[pyo3(text_signature = "($self)")] pub fn last_operation_involving_qubit(&self) -> PyObject { Python::with_gil(|py| -> PyObject { @@ -426,7 +426,7 @@ impl CircuitDagWrapper { /// register. /// /// Returns: - /// dict[(str, int), int]: The dictionary of {(str, int), int} elements. + /// Dict[(str, int), int]: The dictionary of {(str, int), int} elements. #[pyo3(text_signature = "($self)")] pub fn first_operation_involving_classical(&self) -> PyObject { Python::with_gil(|py| -> PyObject { @@ -441,7 +441,7 @@ impl CircuitDagWrapper { /// register. /// /// Returns: - /// dict[(str, int), int]: The dictionary of {(str, int), int} elements. + /// Dict[(str, int), int]: The dictionary of {(str, int), int} elements. #[pyo3(text_signature = "($self)")] pub fn last_operation_involving_classical(&self) -> PyObject { Python::with_gil(|py| -> PyObject { diff --git a/qoqo/src/devices/mod.rs b/qoqo/src/devices/mod.rs index 60349338..1846c29e 100644 --- a/qoqo/src/devices/mod.rs +++ b/qoqo/src/devices/mod.rs @@ -60,12 +60,9 @@ impl ChainWithEnvironmentCapsule { internal: python_device.into_py(py), }) }), - _ => { - return Err(RoqoqoError::GenericError { - msg: "Python device does not implement `environment_chains` method." - .to_string(), - }) - } + _ => Err(RoqoqoError::GenericError { + msg: "Python device does not implement `environment_chains` method.".to_string(), + }), } } } diff --git a/qoqo/src/measurements/basis_rotation_measurement.rs b/qoqo/src/measurements/basis_rotation_measurement.rs index c97b8739..15b25a00 100644 --- a/qoqo/src/measurements/basis_rotation_measurement.rs +++ b/qoqo/src/measurements/basis_rotation_measurement.rs @@ -32,7 +32,7 @@ use std::collections::HashMap; /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. -/// circuits (list[Circuit]): The collection of quantum circuits for the separate basis rotations. +/// circuits (List[Circuit]): The collection of quantum circuits for the separate basis rotations. /// input (PauliZProductInput): The additional input information required for measurement. /// /// Returns: @@ -48,7 +48,7 @@ impl PauliZProductWrapper { /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. - /// circuits (list[Circuit]): The collection of quantum circuits for the separate basis rotations. + /// circuits (List[Circuit]): The collection of quantum circuits for the separate basis rotations. /// input (PauliZProductInput): The additional input information required for measurement. /// /// Returns: @@ -102,12 +102,12 @@ impl PauliZProductWrapper { /// Execute the PauliZ product measurement. /// /// Args: - /// input_bit_registers (dict[str, Union[list[list[int]], list[list[bool]]]]): The classical bit registers with the register name as key + /// input_bit_registers (Dict[str, Union[List[List[int]], List[List[bool]]]]): The classical bit registers with the register name as key /// float_registers (Dict[str, List[List[float]]]): The classical float registers as a dictionary with the register name as key /// complex_registers (Dict[str, List[List[complex]]]): The classical complex registers as a dictionary with the register name as key /// /// Returns: - /// Optional[dict[str, float]]: The evaluated measurement. + /// Optional[Dict[str, float]]: The evaluated measurement. /// /// Raises: /// RuntimeError: Unexpected repetition of key in bit_register. @@ -152,7 +152,7 @@ impl PauliZProductWrapper { /// Return the collection of quantum circuits for the separate basis rotations. /// /// Returns: - /// list[Circuit]: The quantum circuits. + /// List[Circuit]: The quantum circuits. pub fn circuits(&self) -> Vec { self.internal .circuits() @@ -193,7 +193,7 @@ impl PauliZProductWrapper { /// Return clone of Measurement with symbolic parameters replaced. /// /// Args: - /// substituted_parameters (dict[str, float]): The dictionary containing the substitutions to use in the Circuit. + /// substituted_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the Circuit. pub fn substitute_parameters( &self, substituted_parameters: HashMap, diff --git a/qoqo/src/measurements/cheated_basis_rotation_measurement.rs b/qoqo/src/measurements/cheated_basis_rotation_measurement.rs index 10d50967..76b80368 100644 --- a/qoqo/src/measurements/cheated_basis_rotation_measurement.rs +++ b/qoqo/src/measurements/cheated_basis_rotation_measurement.rs @@ -32,7 +32,7 @@ use std::collections::HashMap; /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. -/// circuits (list[Circuit]): The collection of quantum circuits for the separate basis rotations. +/// circuits (List[Circuit]): The collection of quantum circuits for the separate basis rotations. /// input (CheatedPauliZProductInput): The additional input information required for measurement. /// /// Returns: @@ -48,7 +48,7 @@ impl CheatedPauliZProductWrapper { /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. - /// circuits (list[Circuit]): The collection of quantum circuits for the separate basis rotations. + /// circuits (List[Circuit]): The collection of quantum circuits for the separate basis rotations. /// input (CheatedPauliZProductInput): The additional input information required for measurement. /// /// Returns: @@ -103,12 +103,12 @@ impl CheatedPauliZProductWrapper { /// Executes the cheated PauliZ product measurement. /// /// Args: - /// input_bit_registers (dict[str, Union[list[list[int]], list[list[bool]]]]): The classical bit registers with the register name as key + /// input_bit_registers (Dict[str, Union[List[List[int]], List[List[bool]]]]): The classical bit registers with the register name as key /// float_registers (Dict[str, List[List[float]]]): The classical float registers as a dictionary with the register name as key /// complex_registers (Dict[str, List[List[complex]]]): The classical complex registers as a dictionary with the register name as key /// /// Returns: - /// Optional[dict[str, float]]: The evaluated measurement. + /// Optional[Dict[str, float]]: The evaluated measurement. /// /// Raises: /// RuntimeError: Unexpected repetition of key in bit_register. @@ -153,7 +153,7 @@ impl CheatedPauliZProductWrapper { /// Returns the collection of quantum circuits for the separate basis rotations. /// /// Returns: - /// list[Circuit]: The quantum circuits. + /// List[Circuit]: The quantum circuits. pub fn circuits(&self) -> Vec { self.internal .circuits() @@ -194,7 +194,7 @@ impl CheatedPauliZProductWrapper { /// Returns clone of Measurement with symbolic parameters replaced /// /// Args: - /// substituted_parameters (dict[str, float]): The dictionary containing the substitutions to use in the Circuit. + /// substituted_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the Circuit. pub fn substitute_parameters( &self, substituted_parameters: HashMap, diff --git a/qoqo/src/measurements/cheated_measurement.rs b/qoqo/src/measurements/cheated_measurement.rs index 2b44551a..ad67b020 100644 --- a/qoqo/src/measurements/cheated_measurement.rs +++ b/qoqo/src/measurements/cheated_measurement.rs @@ -32,7 +32,7 @@ use std::collections::HashMap; /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. -/// circuits (list[Circuit]): The collection of quantum circuits executed for the measurement. +/// circuits (List[Circuit]): The collection of quantum circuits executed for the measurement. /// input (CheatedInput): The additional input information required for measurement. /// /// Returns: @@ -48,7 +48,7 @@ impl CheatedWrapper { /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. - /// circuits (list[Circuit]): The collection of quantum circuits executed for the measurement. + /// circuits (List[Circuit]): The collection of quantum circuits executed for the measurement. /// input (CheatedInput): The additional input information required for measurement. /// /// Returns: @@ -102,12 +102,12 @@ impl CheatedWrapper { /// Execute the cheated measurement. /// /// Args: - /// input_bit_registers (dict[str, Union[list[list[int]], list[list[bool]]]]): The classical bit registers with the register name as key. + /// input_bit_registers (Dict[str, Union[List[List[int]], List[List[bool]]]]): The classical bit registers with the register name as key. /// float_registers (Dict[str, List[List[float]]]): The classical float registers as a dictionary with the register name as key. /// complex_registers (Dict[str, List[List[complex]]]): The classical complex registers as a dictionary with the register name as key. /// /// Returns: - /// Optional[dict[str, float]]: The evaluated expectation values. + /// Optional[Dict[str, float]]: The evaluated expectation values. /// /// Raises: /// RuntimeError: Unexpected repetition of key in bit_register. @@ -149,7 +149,7 @@ impl CheatedWrapper { /// Return the collection of quantum circuits for the separate cheated measurements. /// /// Returns: - /// list[Circuit]: The quantum circuits. + /// List[Circuit]: The quantum circuits. pub fn circuits(&self) -> Vec { self.internal .circuits() @@ -190,7 +190,7 @@ impl CheatedWrapper { /// Return copy of Measurement with symbolic parameters replaced. /// /// Arguments: - /// substituted_parameters (dict[str, float]): The dictionary containing the substitutions to use in the Circuit. + /// substituted_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the Circuit. /// /// Raises: /// RuntimeError: Error substituting symbolic parameters. diff --git a/qoqo/src/measurements/classical_register_measurement.rs b/qoqo/src/measurements/classical_register_measurement.rs index 39ddef02..1738a3e2 100644 --- a/qoqo/src/measurements/classical_register_measurement.rs +++ b/qoqo/src/measurements/classical_register_measurement.rs @@ -30,7 +30,7 @@ use std::collections::HashMap; /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. -/// circuits (list[Circuit]): The collection of quantum circuits executed for the measurement. +/// circuits (List[Circuit]): The collection of quantum circuits executed for the measurement. /// /// Returns: /// ClassicalRegister: The new register. @@ -45,7 +45,7 @@ impl ClassicalRegisterWrapper { /// /// Args: /// constant_circuit (Optional[Circuit]): The constant Circuit that is executed before each Circuit in circuits. - /// circuits (list[Circuit]): The collection of quantum circuits executed for the measurement. + /// circuits (List[Circuit]): The collection of quantum circuits executed for the measurement. /// /// Returns: /// ClassicalRegister: The new register. @@ -90,7 +90,7 @@ impl ClassicalRegisterWrapper { /// Return the collection of quantum circuits that make up the total measurement. /// /// Returns: - /// list[Circuit]: The quantum circuits. + /// List[Circuit]: The quantum circuits. pub fn circuits(&self) -> Vec { self.internal .circuits() @@ -122,7 +122,7 @@ impl ClassicalRegisterWrapper { /// Return copy of Measurement with symbolic parameters replaced. /// /// Args: - /// substituted_parameters (dict[str, float]): The dictionary containing the substitutions to use in the Circuit. + /// substituted_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the Circuit. /// /// Raises: /// RuntimeError: Error substituting symbolic parameters. diff --git a/qoqo/src/measurements/measurement_auxiliary_data_input.rs b/qoqo/src/measurements/measurement_auxiliary_data_input.rs index 1b5f07ac..924025ae 100644 --- a/qoqo/src/measurements/measurement_auxiliary_data_input.rs +++ b/qoqo/src/measurements/measurement_auxiliary_data_input.rs @@ -77,7 +77,7 @@ impl PauliZProductInputWrapper { /// /// Args: /// readout (str): The name of the readout register the pauli_product is defined on. - /// pauli_product_mask (list[int]): List of the qubits involved in the Pauli produc measurement. + /// pauli_product_mask (List[int]): List of the qubits involved in the Pauli produc measurement. /// /// Returns: /// int: The index of the added Pauli product in the list of all Pauli products. @@ -101,7 +101,7 @@ impl PauliZProductInputWrapper { /// /// Args: /// name (str): The name of the expectation value. - /// linear (dict[int, float]): The linear combination of expectation values as a map between Pauli product index and coefficient. + /// linear (Dict[int, float]): The linear combination of expectation values as a map between Pauli product index and coefficient. /// /// Raises: /// RuntimeError: Failed to add linear expectation value. @@ -332,7 +332,7 @@ impl CheatedPauliZProductInputWrapper { /// /// Args: /// name (str): The name of the expectation value. - /// linear (dict[int, float]): The linear combination of expectation values as a map between Pauli product index and coefficient. + /// linear (Dict[int, float]): The linear combination of expectation values as a map between Pauli product index and coefficient. /// /// Raises: /// RuntimeError: Failed to add linear expectation value. @@ -550,7 +550,7 @@ impl CheatedInputWrapper { /// /// Args: /// name (str): The name of the expectation value. - /// operator (list[(int, int, complex)]): The measured operator on the Hilbert space, + /// operator (List[(int, int, complex)]): The measured operator on the Hilbert space, /// given as a list of sparse matrix entries of the form (row, col, value). /// readout (str): The mame of the readout register that contains the density matrix or satevector. /// diff --git a/qoqo/src/noise_models/continuous_decoherence.rs b/qoqo/src/noise_models/continuous_decoherence.rs index 1bcc4d15..8d4c1238 100644 --- a/qoqo/src/noise_models/continuous_decoherence.rs +++ b/qoqo/src/noise_models/continuous_decoherence.rs @@ -150,7 +150,7 @@ impl ContinuousDecoherenceModelWrapper { /// Convenience function to add damping to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add damping to. + /// qubits (List[int]): The qubits to add damping to. /// rate (float): The damping rate. /// /// Returns: @@ -164,7 +164,7 @@ impl ContinuousDecoherenceModelWrapper { /// Convenience function to add dephasing to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add dephasing to. + /// qubits (List[int]): The qubits to add dephasing to. /// rate (float): The dephasing rate. /// /// Returns: @@ -178,7 +178,7 @@ impl ContinuousDecoherenceModelWrapper { /// Convenience function to add depolarising to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add depolarising to. + /// qubits (List[int]): The qubits to add depolarising to. /// rate (float): The depolarising rate. /// /// Returns: @@ -192,7 +192,7 @@ impl ContinuousDecoherenceModelWrapper { /// Convenience function to add excitation to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add excitation to. + /// qubits (List[int]): The qubits to add excitation to. /// rate (float): The excitation rate. /// /// Returns: diff --git a/qoqo/src/noise_models/decoherence_on_gate.rs b/qoqo/src/noise_models/decoherence_on_gate.rs index 4d76ac27..e95fcd98 100644 --- a/qoqo/src/noise_models/decoherence_on_gate.rs +++ b/qoqo/src/noise_models/decoherence_on_gate.rs @@ -146,8 +146,8 @@ impl DecoherenceOnGateModelWrapper { /// /// Args: /// gate (str): The name of the gate. - /// control (int) - The control qubit the gate acts on. - /// target (int) - The target qubit the gate acts on. + /// control (int): The control qubit the gate acts on. + /// target (int): The target qubit the gate acts on. /// /// Returns /// Optional[struqture_py.spins.PlusMinusLindbladNoiseOperator]: The error model applied when gate is applied. @@ -260,7 +260,7 @@ impl DecoherenceOnGateModelWrapper { /// /// Args: /// gate (str): The name of the gate. - /// qubits (list[int]): The qubits the gate acts on. + /// qubits (List[int]): The qubits the gate acts on. /// /// Returns /// Optional[struqture_py.spins.PlusMinusLindbladNoiseOperator]: The error model applied when gate is applied. diff --git a/qoqo/src/noise_models/decoherence_on_idle.rs b/qoqo/src/noise_models/decoherence_on_idle.rs index 61a9cb4b..776f139e 100644 --- a/qoqo/src/noise_models/decoherence_on_idle.rs +++ b/qoqo/src/noise_models/decoherence_on_idle.rs @@ -149,7 +149,7 @@ impl DecoherenceOnIdleModelWrapper { /// Convenience function to add damping to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add damping to. + /// qubits (List[int]): The qubits to add damping to. /// rate (float): The damping rate. /// /// Returns: @@ -163,7 +163,7 @@ impl DecoherenceOnIdleModelWrapper { /// Convenience function to add dephasing to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add dephasing to. + /// qubits (List[int]): The qubits to add dephasing to. /// rate (float): The dephasing rate. /// /// Returns: @@ -177,7 +177,7 @@ impl DecoherenceOnIdleModelWrapper { /// Convenience function to add depolarising to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add depolarising to. + /// qubits (List[int]): The qubits to add depolarising to. /// rate (float): The depolarising rate. /// /// Returns: @@ -191,7 +191,7 @@ impl DecoherenceOnIdleModelWrapper { /// Convenience function to add excitation to several qubits /// /// Args: - /// qubits (list[int]): The qubits to add excitation to. + /// qubits (List[int]): The qubits to add excitation to. /// rate (float): The excitation rate. /// /// Returns: diff --git a/qoqo/src/noise_models/imperfect_readout.rs b/qoqo/src/noise_models/imperfect_readout.rs index 77893189..684d4662 100644 --- a/qoqo/src/noise_models/imperfect_readout.rs +++ b/qoqo/src/noise_models/imperfect_readout.rs @@ -176,7 +176,7 @@ impl ImperfectReadoutModelWrapper { /// Return probability to detect 0 as 1 for a qubit /// /// Args: - /// qubit (int) The qubit for which the probability is returned. + /// qubit (int): The qubit for which the probability is returned. /// /// Returns: /// float: The probability to detect 0 as 1 for the qubit @@ -187,7 +187,7 @@ impl ImperfectReadoutModelWrapper { /// Return probability to detect 1 as 0 for a qubit /// /// Args: - /// qubit (int) The qubit for which the probability is returned. + /// qubit (int): The qubit for which the probability is returned. /// /// Returns: /// float: The probability to detect 1 as 0 for the qubit diff --git a/qoqo/src/noise_models/overrotation.rs b/qoqo/src/noise_models/overrotation.rs index 525afb21..d8ae8f55 100644 --- a/qoqo/src/noise_models/overrotation.rs +++ b/qoqo/src/noise_models/overrotation.rs @@ -401,8 +401,8 @@ impl SingleQubitOverrotationOnGateWrapper { /// /// Args: /// gate (str): The name of the gate. - /// control (int) - The control qubit the gate acts on. - /// target (int) - The target qubit the gate acts on. + /// control (int): The control qubit the gate acts on. + /// target (int): The target qubit the gate acts on. /// /// Returns /// Optional[(SingleQubitOverrotationDescription, SingleQubitOverrotationDescription)]: The overrotation applied when gate is applied. diff --git a/qoqo/src/operations/analog_operations.rs b/qoqo/src/operations/analog_operations.rs index b20beed7..8dc23c68 100644 --- a/qoqo/src/operations/analog_operations.rs +++ b/qoqo/src/operations/analog_operations.rs @@ -41,8 +41,8 @@ pub struct ApplyConstantSpinHamiltonian { /// /// Args: /// hamiltonian (SpinHamiltonian): The hamiltonian that is to be simulated. -/// time (Vec): Range of time stored as a vector. The total duration of the simulations is given by the last value in the range. -/// values (HashMap>): /// Values of time-dependent parameters, appearing in `hamiltonian`, at instances given by the vector `time`. +/// time (List[float]): Range of time stored as a vector. The total duration of the simulations is given by the last value in the range. +/// values (Mapping[str, List[float]]): /// Values of time-dependent parameters, appearing in `hamiltonian`, at instances given by the vector `time`. pub struct ApplyTimeDependentSpinHamiltonian { hamiltonian: SpinHamiltonian, time: Vec, diff --git a/qoqo/src/operations/define_operations.rs b/qoqo/src/operations/define_operations.rs index f66f8577..c7de912a 100644 --- a/qoqo/src/operations/define_operations.rs +++ b/qoqo/src/operations/define_operations.rs @@ -10,11 +10,15 @@ // express or implied. See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "unstable_operation_definition")] +use crate::{convert_into_circuit, CircuitWrapper}; use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; use pyo3::types::PySet; use qoqo_macros::*; use roqoqo::operations::*; +#[cfg(feature = "unstable_operation_definition")] +use roqoqo::Circuit; #[cfg(feature = "json_schema")] use roqoqo::ROQOQO_VERSION; use std::collections::HashMap; @@ -99,3 +103,19 @@ pub struct InputBit { index: usize, value: bool, } + +#[cfg(feature = "unstable_operation_definition")] +#[wrap(Operate, Define, OperateMultiQubit, JsonSchema)] +/// GateDefinition is the Definition of a new custom gate. +/// +/// Args: +/// circuit (Circuit): The circuit where the definition is stored. +/// name (str): The name of the gate that is defined. +/// qubits (List[int]): The indices of the qubits used in the internal definition. +/// free_parameter (List[str]): Names of the free CalculatorFloat variables in the internal definition. +pub struct GateDefinition { + circuit: Circuit, + name: String, + qubits: Vec, + free_parameters: Vec, +} diff --git a/qoqo/src/operations/measurement_operations.rs b/qoqo/src/operations/measurement_operations.rs index 210f4918..132fb96e 100644 --- a/qoqo/src/operations/measurement_operations.rs +++ b/qoqo/src/operations/measurement_operations.rs @@ -85,7 +85,7 @@ struct PragmaGetOccupationProbability { /// sothat the actual quantum register remains unchanged. /// /// Args: -/// qubit_paulis (dict[int, int]): The dictionary of the pauli matrix to apply to each qubit in the form +/// qubit_paulis (Dict[int, int]): The dictionary of the pauli matrix to apply to each qubit in the form /// {qubit: pauli}. Allowed values to be provided for 'pauli' are: 0 = identity, 1 = PauliX, 2 = PauliY, 3 = PauliZ. /// readout (string): The name of the classical readout register. /// circuit (Circuit): The measurement preparation Circuit, applied on a copy of the register before measurement. @@ -102,7 +102,7 @@ struct PragmaGetPauliProduct { /// /// Args: /// readout (string): The name of the classical readout register. -/// qubit_mapping (dict[int, int]): The mapping of qubits to indices in readout register. +/// qubit_mapping (Dict[int, int]): The mapping of qubits to indices in readout register. /// number_measurements (int): The number of times to repeat the measurement. /// struct PragmaRepeatedMeasurement { diff --git a/qoqo/src/operations/mod.rs b/qoqo/src/operations/mod.rs index defb2ad4..fa8cd0ed 100644 --- a/qoqo/src/operations/mod.rs +++ b/qoqo/src/operations/mod.rs @@ -170,6 +170,10 @@ pub fn operations(_py: Python, m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + #[cfg(feature = "unstable_operation_definition")] + m.add_class::()?; + #[cfg(feature = "unstable_operation_definition")] + m.add_class::()?; Ok(()) } diff --git a/qoqo/src/operations/multi_qubit_gate_operations.rs b/qoqo/src/operations/multi_qubit_gate_operations.rs index fe0d2990..9b18896d 100644 --- a/qoqo/src/operations/multi_qubit_gate_operations.rs +++ b/qoqo/src/operations/multi_qubit_gate_operations.rs @@ -64,3 +64,306 @@ pub struct MultiQubitZZ { /// The angle of the multi qubit Molmer-Sorensen gate. theta: CalculatorFloat, } + +/// The gate to be replaced by a gate defined with GateDefinition gate. +/// The gate applies a gate previously defined by GateDefinition with the name gate_name. +/// +/// Args: +/// gate_name (str) : The name of the called defined operations. +/// qubits (List[int]) : The qubits that for this call replace the qubits in the internal definition of the called gate +/// (get replaced in order of apppearance in gate defintion). +/// free_parameters (List[CalculatorFloat]) : List of float values that replace the free parameters in the internal definition of the called gate +/// (get replaced in order of apppearance in gate defintion). +#[cfg(feature = "unstable_operation_definition")] +#[pyclass(name = "CallDefinedGate", module = "qoqo")] +#[derive(Debug, Clone, PartialEq)] +pub struct CallDefinedGateWrapper { + /// Internal storage of [roqoqo::CallDefinedGate] + pub internal: CallDefinedGate, +} + +#[cfg(feature = "unstable_operation_definition")] +insert_pyany_to_operation!( + "CallDefinedGate" =>{ + let gatenm = op.call_method0("gate_name") + .map_err(|_| QoqoError::ConversionError)?; + let gate_name: String = gatenm.extract().map_err(|_| QoqoError::ConversionError)?; + let qbts = op.call_method0("qubits") + .map_err(|_| QoqoError::ConversionError)?; + let qubits: Vec = qbts.extract() + .map_err(|_| QoqoError::ConversionError)?; + + let params = op.call_method0("free_parameters") + .map_err(|_| QoqoError::ConversionError)?; + let param_vec: &pyo3::types::PyList = params.extract().map_err(|_| QoqoError::ConversionError)?; + let mut free_parameters: Vec = vec![]; + for param in param_vec.iter() { + free_parameters.push(convert_into_calculator_float(¶m.as_borrowed()).map_err(|_| QoqoError::ConversionError)?); + } + Ok(CallDefinedGate::new(gate_name, qubits, free_parameters).into()) + } +); +#[cfg(feature = "unstable_operation_definition")] +insert_operation_to_pyobject!( + Operation::CallDefinedGate(internal) => { + { + let pyref: Py = + Py::new(py, CallDefinedGateWrapper { internal }).unwrap(); + let pyobject: PyObject = pyref.to_object(py); + Ok(pyobject) + } + } +); + +#[cfg(feature = "unstable_operation_definition")] +#[pymethods] +impl CallDefinedGateWrapper { + /// Create a new CallDefinedGate. + /// + /// Args: + /// gate_name (str) : The name of the called defined operations. + /// qubits (List[int]) : The qubits that for this call replace the qubits in the internal definition of the called gate + /// (get replaced in order of apppearance in gate defintion). + /// free_parameters (List[CalculatorFloat]) : List of float values that replace the free parameters in the internal defintion of the called gate + /// (get replaced in order of apppearance in gate defintion). + #[new] + fn new( + gate_name: String, + qubits: Vec, + free_parameters: Vec>, + ) -> PyResult { + let free_parameters_cf: Vec = + Python::with_gil(|py| -> PyResult> { + let mut a = vec![]; + for param in free_parameters { + a.push(convert_into_calculator_float(param.bind(py)).map_err(|_| { + pyo3::exceptions::PyTypeError::new_err( + "Argument gate time cannot be converted to CalculatorFloat", + ) + })?) + } + Ok(a) + })?; + + Ok(Self { + internal: CallDefinedGate::new(gate_name, qubits, free_parameters_cf), + }) + } + + /// Return the name of the gate to apply. + /// + /// Returns: + /// str: The name of the gate. + fn gate_name(&self) -> String { + self.internal.gate_name().clone() + } + + /// Return the qubits on which the Gate operation is applied. + /// + /// Returns: + /// List[int]: The qubits of the operation. + fn qubits(&self) -> Vec { + self.internal.qubits().clone() + } + + /// Return the qubits on which the Gate operation is applied. + /// + /// Returns: + /// List[CalculatorFloat]: The qubits of the operation. + fn free_parameters(&self) -> Vec { + self.internal + .free_parameters() + .iter() + .map(|param| CalculatorFloatWrapper { + internal: param.clone(), + }) + .collect::>() + } + + /// List all involved qubits. + /// + /// Returns: + /// Set[int]: The involved qubits of the operation. + fn involved_qubits(&self) -> PyObject { + let pyobject: PyObject = Python::with_gil(|py| -> PyObject { + PySet::new_bound(py, &[self.internal.qubits().clone()]) + .unwrap() + .to_object(py) + }); + pyobject + } + + /// Return tags classifying the type of the operation. + /// + /// Used for the type based dispatch in ffi interfaces. + /// + /// Returns: + /// List[str]: The tags of the Operation. + fn tags(&self) -> Vec { + self.internal.tags().iter().map(|s| s.to_string()).collect() + } + + /// Return hqslang name of the operation. + /// + /// Returns: + /// str: The hqslang name of the operation. + fn hqslang(&self) -> &'static str { + self.internal.hqslang() + } + + /// Return true when the operation has symbolic parameters. + /// + /// Returns: + /// bool: True if the operation contains symbolic parameters, False if it does not. + fn is_parametrized(&self) -> bool { + self.internal.is_parametrized() + } + + /// Substitute the symbolic parameters in a clone of the operation according to the input. + /// + /// Args: + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the operation. + /// + /// Returns: + /// self: The operation with the parameters substituted. + /// + /// Raises: + /// RuntimeError: The parameter substitution failed. + fn substitute_parameters( + &self, + substitution_parameters: std::collections::HashMap, + ) -> PyResult { + let mut calculator = qoqo_calculator::Calculator::new(); + for (key, val) in substitution_parameters.iter() { + calculator.set_variable(key, *val); + } + Ok(Self { + internal: self + .internal + .substitute_parameters(&calculator) + .map_err(|x| { + pyo3::exceptions::PyRuntimeError::new_err(format!( + "Parameter Substitution failed: {:?}", + x + )) + })?, + }) + } + + /// Remap qubits in a clone of the CallDefinedGate operation. + /// + /// Args: + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the operation. + /// + /// Returns: + /// self: The operation with the qubits remapped. + /// + /// Raises: + /// RuntimeError: The qubit remapping failed. + fn remap_qubits(&self, mapping: std::collections::HashMap) -> PyResult { + let new_internal = self + .internal + .remap_qubits(&mapping) + .map_err(|_| pyo3::exceptions::PyRuntimeError::new_err("Qubit remapping failed: "))?; + Ok(Self { + internal: new_internal, + }) + } + + /// Return a copy of the operation (copy here produces a deepcopy). + /// + /// Returns: + /// CallDefinedGate: A deep copy of self. + fn __copy__(&self) -> CallDefinedGateWrapper { + self.clone() + } + + /// Return a deep copy of the operation. + /// + /// Returns: + /// CallDefinedGate: A deep copy of self. + fn __deepcopy__(&self, _memodict: Py) -> CallDefinedGateWrapper { + self.clone() + } + + /// Return a string containing a formatted (string) representation of the operation. + /// + /// Returns: + /// str: The string representation of the operation. + fn __format__(&self, _format_spec: &str) -> PyResult { + Ok(format!("{:?}", self.internal)) + } + + /// Return a string containing a printable representation of the operation. + /// + /// Returns: + /// str: The printable string representation of the operation. + fn __repr__(&self) -> PyResult { + Ok(format!("{:?}", self.internal)) + } + + /// Return the __richcmp__ magic method to perform rich comparison operations on CallDefinedGate. + /// + /// Args: + /// self: The CallDefinedGate object. + /// other: The object to compare self to. + /// op: Type of comparison. + /// + /// Returns: + /// bool: Whether the two operations compared evaluated to True or False. + fn __richcmp__( + &self, + other: &Bound, + op: pyo3::class::basic::CompareOp, + ) -> PyResult { + let other: Operation = + crate::operations::convert_pyany_to_operation(other).map_err(|_| { + pyo3::exceptions::PyTypeError::new_err( + "Right hand side cannot be converted to Operation", + ) + })?; + match op { + pyo3::class::basic::CompareOp::Eq => { + Ok(Operation::from(self.internal.clone()) == other) + } + pyo3::class::basic::CompareOp::Ne => { + Ok(Operation::from(self.internal.clone()) != other) + } + _ => Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Other comparison not implemented.", + )), + } + } + + #[cfg(feature = "json_schema")] + /// Return the JsonSchema for the json serialisation of the class. + /// + /// Returns: + /// str: The json schema serialized to json + #[staticmethod] + pub fn json_schema() -> String { + let schema = schemars::schema_for!(CallDefinedGate); + serde_json::to_string_pretty(&schema).expect("Unexpected failure to serialize schema") + } + + #[cfg(feature = "json_schema")] + /// Returns the current version of the qoqo library . + /// + /// Returns: + /// str: The current version of the library. + #[staticmethod] + pub fn current_version() -> String { + ROQOQO_VERSION.to_string() + } + + #[cfg(feature = "json_schema")] + /// Return the minimum version of qoqo that supports this object. + /// + /// Returns: + /// str: The minimum version of the qoqo library to deserialize this object. + pub fn min_supported_version(&self) -> String { + let min_version: (u32, u32, u32) = + CallDefinedGate::minimum_supported_roqoqo_version(&self.internal); + format!("{}.{}.{}", min_version.0, min_version.1, min_version.2) + } +} diff --git a/qoqo/src/operations/pragma_operations.rs b/qoqo/src/operations/pragma_operations.rs index 776cdd6e..57ea4bf0 100644 --- a/qoqo/src/operations/pragma_operations.rs +++ b/qoqo/src/operations/pragma_operations.rs @@ -105,7 +105,7 @@ impl PragmaSetStateVectorWrapper { /// Create a PragmaSetStateVector. /// /// Args: - /// statevector (list[complex]): The statevector representing the qubit register. + /// statevector (List[complex]): The statevector representing the qubit register. /// /// Returns: /// self: The new PragmaSetStateVector. @@ -159,7 +159,7 @@ impl PragmaSetStateVectorWrapper { /// List all involved qubits (here, all). /// /// Returns: - /// set[int]: The involved qubits of the PRAGMA operation. + /// Set[int]: The involved qubits of the PRAGMA operation. fn involved_qubits(&self) -> PyObject { let pyobject: PyObject = Python::with_gil(|py| -> PyObject { PySet::new_bound(py, &["All"]).unwrap().to_object(py) @@ -172,7 +172,7 @@ impl PragmaSetStateVectorWrapper { /// Used for the type based dispatch in ffi interfaces. /// /// Returns: - /// list[str]: The tags of the operation. + /// List[str]: The tags of the operation. fn tags(&self) -> Vec { self.internal.tags().iter().map(|s| s.to_string()).collect() } @@ -196,7 +196,7 @@ impl PragmaSetStateVectorWrapper { /// Substitute the symbolic parameters in a clone of the PRAGMA operation according to the substitution_parameters input. /// /// Args: - /// substitution_parameters (dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation operation with the parameters substituted. @@ -227,7 +227,7 @@ impl PragmaSetStateVectorWrapper { /// Remap qubits in a clone of the PRAGMA operation. /// /// Args: - /// mapping (dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the qubits remapped. @@ -415,7 +415,7 @@ impl PragmaSetDensityMatrixWrapper { /// List all involved qubits (here, all). /// /// Returns: - /// set[int]: The involved qubits of the PRAGMA operation. + /// Set[int]: The involved qubits of the PRAGMA operation. fn involved_qubits(&self) -> PyObject { let pyobject: PyObject = Python::with_gil(|py| -> PyObject { PySet::new_bound(py, &["All"]).unwrap().to_object(py) @@ -428,7 +428,7 @@ impl PragmaSetDensityMatrixWrapper { /// Used for type based dispatch in ffi interfaces. /// /// Returns: - /// list[str]: The tags of the Operation. + /// List[str]: The tags of the Operation. fn tags(&self) -> Vec { self.internal.tags().iter().map(|s| s.to_string()).collect() } @@ -452,7 +452,7 @@ impl PragmaSetDensityMatrixWrapper { /// Substitute the symbolic parameters in a clone of the PRAGMA operation according to the input. /// /// Args: - /// substitution_parameters (dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the parameters substituted. @@ -483,7 +483,7 @@ impl PragmaSetDensityMatrixWrapper { /// Remap qubits in a clone of the PRAGMA operation. /// /// Args: - /// mapping (dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the qubits remapped. @@ -622,7 +622,7 @@ struct PragmaRepeatGate { /// /// Args: /// gate (str): The unique hqslang name of the gate to overrotate. -/// qubits (list[int]): The qubits of the gate to overrotate. +/// qubits (List[int]): The qubits of the gate to overrotate. /// amplitude (float): The amplitude the random number is multiplied by. /// variance (float): The standard deviation of the normal distribution the random number is drawn from. /// @@ -647,7 +647,7 @@ struct PragmaBoostNoise { /// This PRAGMA operation signals the STOP of a parallel execution block. /// /// Args: -/// qubits (list[int]): The qubits involved in parallel execution block. +/// qubits (List[int]): The qubits involved in parallel execution block. /// execution_time (CalculatorFloat): The time for the execution of the block in seconds. struct PragmaStopParallelBlock { qubits: Vec, @@ -673,7 +673,7 @@ struct PragmaGlobalPhase { /// It can be used to boost the noise on the qubits since it gets worse with time. /// /// Args: -/// qubits (list[int]): The qubits involved in the sleep block. +/// qubits (List[int]): The qubits involved in the sleep block. /// sleep_time (CalculatorFloat): The time for the execution of the block in seconds. pub struct PragmaSleep { qubits: Vec, @@ -695,8 +695,8 @@ pub struct PragmaActiveReset { /// This PRAGMA operation signals the START of a decomposition block. /// /// Args: -/// qubits (list[int]): The qubits involved in the decomposition block. -/// reordering_dictionary (dict[int, int]): The reordering dictionary of the block. +/// qubits (List[int]): The qubits involved in the decomposition block. +/// reordering_dictionary (Dict[int, int]): The reordering dictionary of the block. pub struct PragmaStartDecompositionBlock { qubits: Vec, reordering_dictionary: HashMap, @@ -707,7 +707,7 @@ pub struct PragmaStartDecompositionBlock { /// This PRAGMA operation signals the STOP of a decomposition block. /// /// Args: -/// qubits (list[int]): The qubits involved in the decomposition block. +/// qubits (List[int]): The qubits involved in the decomposition block. pub struct PragmaStopDecompositionBlock { qubits: Vec, } @@ -1106,7 +1106,7 @@ impl PragmaGeneralNoiseWrapper { /// List all involved qubits. /// /// Returns: - /// set[int]: The involved qubits of the PRAGMA operation. + /// Set[int]: The involved qubits of the PRAGMA operation. fn involved_qubits(&self) -> PyObject { let pyobject: PyObject = Python::with_gil(|py| -> PyObject { PySet::new_bound(py, &[*self.internal.qubit()]) @@ -1121,7 +1121,7 @@ impl PragmaGeneralNoiseWrapper { /// Used for the type based dispatch in ffi interfaces. /// /// Returns: - /// list[str]: The tags of the Operation. + /// List[str]: The tags of the Operation. fn tags(&self) -> Vec { self.internal.tags().iter().map(|s| s.to_string()).collect() } @@ -1145,7 +1145,7 @@ impl PragmaGeneralNoiseWrapper { /// Substitute the symbolic parameters in a clone of the PRAGMA operation according to the input. /// /// Args: - /// substitution_parameters (dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the parameters substituted. @@ -1176,7 +1176,7 @@ impl PragmaGeneralNoiseWrapper { /// Remap qubits in a clone of the PRAGMA operation. /// /// Args: - /// mapping (dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the qubits remapped. @@ -1403,7 +1403,7 @@ impl PragmaChangeDeviceWrapper { /// List all involved qubits. /// /// Returns: - /// set[int]: The involved qubits of the PRAGMA operation. + /// Set[int]: The involved qubits of the PRAGMA operation. fn involved_qubits(&self) -> PyObject { let pyobject: PyObject = Python::with_gil(|py| -> PyObject { PySet::new_bound(py, &["All"]).unwrap().to_object(py) @@ -1416,7 +1416,7 @@ impl PragmaChangeDeviceWrapper { /// Used for the type based dispatch in ffi interfaces. /// /// Returns: - /// list[str]: The tags of the Operation. + /// List[str]: The tags of the Operation. fn tags(&self) -> Vec { self.internal.tags().iter().map(|s| s.to_string()).collect() } @@ -1440,7 +1440,7 @@ impl PragmaChangeDeviceWrapper { /// Substitute the symbolic parameters in a clone of the PRAGMA operation according to the input. /// /// Args: - /// substitution_parameters (dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the parameters substituted. @@ -1471,7 +1471,7 @@ impl PragmaChangeDeviceWrapper { /// Remap qubits in a clone of the PRAGMA operation. /// /// Args: - /// mapping (dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the qubits remapped. @@ -1598,7 +1598,7 @@ fn pragma_annotated_op(_py: Python, module: &Bound) -> PyResult<()> { /// /// Args: /// operation (Operation): - The Operation to be annotated. -/// annotation (String): - The annotation. +/// annotation (str): - The annotation. pub struct PragmaAnnotatedOpWrapper { /// PragmaAnnotatedOp to be wrapped and converted to Python. pub internal: PragmaAnnotatedOp, @@ -1633,7 +1633,7 @@ impl PragmaAnnotatedOpWrapper { /// /// Args: /// operation (Operation): - The Operation to be annotated. - /// annotation (String): - The annotation. + /// annotation (str): - The annotation. #[new] fn new(operation: &Bound, annotation: String) -> PyResult { let op = crate::operations::convert_pyany_to_operation(operation).map_err(|_| { @@ -1658,7 +1658,7 @@ impl PragmaAnnotatedOpWrapper { /// Return the annotation. /// /// Returns: - /// String: The annotation. + /// str: The annotation. fn annotation(&self) -> String { self.internal.annotation.clone() } @@ -1666,7 +1666,7 @@ impl PragmaAnnotatedOpWrapper { /// List all involved qubits. /// /// Returns: - /// set[int]: The involved qubits of the PRAGMA operation. + /// Set[int]: The involved qubits of the PRAGMA operation. fn involved_qubits(&self) -> PyObject { Python::with_gil(|py| -> PyObject { let involved = self.internal.involved_qubits(); @@ -1699,7 +1699,7 @@ impl PragmaAnnotatedOpWrapper { /// Used for the type based dispatch in ffi interfaces. /// /// Returns: - /// list[str]: The tags of the Operation. + /// List[str]: The tags of the Operation. fn tags(&self) -> Vec { self.internal.tags().iter().map(|s| s.to_string()).collect() } @@ -1723,7 +1723,7 @@ impl PragmaAnnotatedOpWrapper { /// Substitute the symbolic parameters in a clone of the PRAGMA operation according to the input. /// /// Args: - /// substitution_parameters (dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. + /// substitution_parameters (Dict[str, float]): The dictionary containing the substitutions to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the parameters substituted. @@ -1754,7 +1754,7 @@ impl PragmaAnnotatedOpWrapper { /// Remap qubits in a clone of the PRAGMA operation. /// /// Args: - /// mapping (dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. + /// mapping (Dict[int, int]): The dictionary containing the {qubit: qubit} mapping to use in the PRAGMA operation. /// /// Returns: /// self: The PRAGMA operation with the qubits remapped. diff --git a/qoqo/src/quantum_program.rs b/qoqo/src/quantum_program.rs index 08f3462a..122fbccd 100644 --- a/qoqo/src/quantum_program.rs +++ b/qoqo/src/quantum_program.rs @@ -303,7 +303,7 @@ impl QuantumProgramWrapper { /// Return the roqoqo and qoqo versions from when the code was compiled. /// /// Returns: - /// tuple[str, str]: The roqoqo and qoqo versions. + /// Tuple[str, str]: The roqoqo and qoqo versions. fn _qoqo_versions(&self) -> (String, String) { let mut rsplit = ROQOQO_VERSION.split('.').take(2); let mut qsplit = QOQO_VERSION.split('.').take(2); diff --git a/qoqo/tests/integration/operations/analog_operations.rs b/qoqo/tests/integration/operations/analog_operations.rs index 77bc6146..34dc4b7f 100644 --- a/qoqo/tests/integration/operations/analog_operations.rs +++ b/qoqo/tests/integration/operations/analog_operations.rs @@ -213,13 +213,12 @@ fn test_pyo3_is_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(bool::extract_bound( - &operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -230,13 +229,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - &operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -247,9 +245,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(&operation.call_method0(py, "hqslang").unwrap().bind(py)) - .unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -275,9 +276,12 @@ fn test_pyo3_tags(input_operation: Operation, tags: Vec<&str>) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(&operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -329,10 +333,10 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(&to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(&to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(repr_op, format_repr); }) } @@ -422,9 +426,12 @@ fn test_spin(input_operation: Operation, test_result: Vec) { Python::with_gil(|py| { pyo3::prepare_freethreaded_python(); let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let result: Vec = - Vec::::extract_bound(&operation.call_method1(py, "spin", ()).unwrap().bind(py)) - .unwrap(); + let result: Vec = operation + .call_method1(py, "spin", ()) + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(result, test_result); }) } diff --git a/qoqo/tests/integration/operations/bosonic_operations.rs b/qoqo/tests/integration/operations/bosonic_operations.rs index 33d7cdda..0719e3c5 100644 --- a/qoqo/tests/integration/operations/bosonic_operations.rs +++ b/qoqo/tests/integration/operations/bosonic_operations.rs @@ -352,13 +352,12 @@ fn test_pyo3_is_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -372,13 +371,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -391,8 +389,12 @@ fn test_pyo3_mode(mode: usize, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let mode_op: usize = - usize::extract_bound(operation.call_method0(py, "mode").unwrap().bind(py)).unwrap(); + let mode_op: usize = operation + .call_method0(py, "mode") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_op, mode); }) } @@ -403,11 +405,19 @@ fn test_pyo3_mode0_mode_1(mode_0: usize, mode_1: usize, input_operation: Operati pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let mode_op_0: usize = - usize::extract_bound(operation.call_method0(py, "mode_0").unwrap().bind(py)).unwrap(); + let mode_op_0: usize = operation + .call_method0(py, "mode_0") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_op_0, mode_0); - let mode_op_1: usize = - usize::extract_bound(operation.call_method0(py, "mode_1").unwrap().bind(py)).unwrap(); + let mode_op_1: usize = operation + .call_method0(py, "mode_1") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_op_1, mode_1); }) } @@ -422,8 +432,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -477,9 +491,12 @@ fn test_pyo3_tags(input_operation: Operation, tags: Vec<&str>) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -498,13 +515,12 @@ fn test_pyo3_involved_modes(input_operation: Operation, modes: HashSet) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial mode - let involved_modes: HashSet = HashSet::::extract_bound( - operation - .call_method0(py, "involved_modes") - .unwrap() - .bind(py), - ) - .unwrap(); + let involved_modes: HashSet = operation + .call_method0(py, "involved_modes") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(involved_modes, modes); }) } @@ -520,23 +536,24 @@ fn test_pyo3_remapqubits(input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial qubit - let involved_qubits: HashSet = HashSet::::extract_bound( - operation - .call_method0(py, "involved_qubits") - .unwrap() - .bind(py), - ) - .unwrap(); + let involved_qubits: HashSet = operation + .call_method0(py, "involved_qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(involved_qubits, HashSet::::new()); // remap qubits let result = operation .call_method1(py, "remap_qubits", (HashMap::::new(),)) .unwrap(); // test re-mapped qubit - let involved_qubits: HashSet = HashSet::::extract_bound( - result.call_method0(py, "involved_qubits").unwrap().bind(py), - ) - .unwrap(); + let involved_qubits: HashSet = result + .call_method0(py, "involved_qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(involved_qubits, HashSet::::new()); }) } @@ -551,8 +568,12 @@ fn test_pyo3_remapmodes_single(input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial mode - let mode: usize = - usize::extract_bound(operation.call_method0(py, "mode").unwrap().bind(py)).unwrap(); + let mode: usize = operation + .call_method0(py, "mode") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode.clone(), 0); // remap modes let mut mode_mapping: HashMap = HashMap::new(); @@ -562,8 +583,12 @@ fn test_pyo3_remapmodes_single(input_operation: Operation) { .call_method1(py, "remap_modes", (mode_mapping,)) .unwrap(); // test re-mapped mode - let mode_new: usize = - usize::extract_bound(result.call_method0(py, "mode").unwrap().bind(py)).unwrap(); + let mode_new: usize = result + .call_method0(py, "mode") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_new.clone(), 1); // test that initial and rempapped modes are different assert_ne!(mode, mode_new); @@ -577,11 +602,19 @@ fn test_pyo3_remapmodes_two(input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial mode - let mode_0: usize = - usize::extract_bound(operation.call_method0(py, "mode_0").unwrap().bind(py)).unwrap(); + let mode_0: usize = operation + .call_method0(py, "mode_0") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_0.clone(), 0); - let mode_1: usize = - usize::extract_bound(operation.call_method0(py, "mode_1").unwrap().bind(py)).unwrap(); + let mode_1: usize = operation + .call_method0(py, "mode_1") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_1.clone(), 1); // remap modes let mut mode_mapping: HashMap = HashMap::new(); @@ -591,11 +624,19 @@ fn test_pyo3_remapmodes_two(input_operation: Operation) { .call_method1(py, "remap_modes", (mode_mapping,)) .unwrap(); // test re-mapped mode - let mode_new_0: usize = - usize::extract_bound(result.call_method0(py, "mode_0").unwrap().bind(py)).unwrap(); + let mode_new_0: usize = result + .call_method0(py, "mode_0") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_new_0.clone(), 1); - let mode_new_1: usize = - usize::extract_bound(result.call_method0(py, "mode_1").unwrap().bind(py)).unwrap(); + let mode_new_1: usize = result + .call_method0(py, "mode_1") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_new_1.clone(), 0); // test that initial and rempapped modes are different assert_ne!(mode_0, mode_new_0); @@ -681,10 +722,10 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(repr_op, format_repr); }) } diff --git a/qoqo/tests/integration/operations/define_operations.rs b/qoqo/tests/integration/operations/define_operations.rs index 815eec19..41ce8e56 100644 --- a/qoqo/tests/integration/operations/define_operations.rs +++ b/qoqo/tests/integration/operations/define_operations.rs @@ -10,9 +10,13 @@ // express or implied. See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "unstable_operation_definition")] +use super::pragma_operations::new_circuit; use pyo3::prelude::*; use qoqo::operations::*; use roqoqo::operations::*; +#[cfg(feature = "unstable_operation_definition")] +use roqoqo::Circuit; #[cfg(feature = "json_schema")] use roqoqo::ROQOQO_VERSION; use std::collections::{HashMap, HashSet}; @@ -205,7 +209,66 @@ fn test_pyo3_new_input_bit() { }) } -/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic name() function/input +/// Test GateDefinition new() function +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_pyo3_new_gate_definition() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = py.get_type_bound::(); + let binding = operation + .call1(( + new_circuit(py), + String::from("ro"), + vec![1], + vec!["a".to_owned(), "b".to_owned()], + )) + .unwrap(); + let new_op = binding.downcast::().unwrap(); + + let input_definition = Operation::from(GateDefinition::new( + Circuit::new(), + "ro".into(), + vec![1], + vec!["a".into(), "b".into()], + )); + let copy_param = convert_operation_to_pyobject(input_definition) + .unwrap() + .extract::(py) + .unwrap() + .into_py(py); + + let comparison_copy = + bool::extract_bound(&new_op.call_method1("__eq__", (copy_param,)).unwrap()).unwrap(); + assert!(comparison_copy); + + let def_wrapper = new_op.extract::().unwrap(); + let new_op_diff = operation + .call1(( + new_circuit(py), + String::from("ro"), + vec![2], + vec!["a".to_owned(), "c".to_owned()], + )) + .unwrap(); + let def_wrapper_diff = new_op_diff + .downcast::() + .unwrap() + .extract::() + .unwrap(); + let helper_ne: bool = def_wrapper_diff != def_wrapper; + assert!(helper_ne); + let helper_eq: bool = def_wrapper == def_wrapper.clone(); + assert!(helper_eq); + + assert_eq!( + format!("{:?}", def_wrapper), + "GateDefinitionWrapper { internal: GateDefinition { circuit: Circuit { definitions: [], operations: [], _roqoqo_version: RoqoqoVersion }, name: \"ro\", qubits: [1], free_parameters: [\"a\", \"b\"] } }" + ); + }) +} + +/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic, name() function/input #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)); "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)); "DefinitionComplex")] #[test_case(Operation::from(DefinitionUsize::new(String::from("ro"), 1, false)); "DefinitionUsize")] @@ -216,8 +279,12 @@ fn test_pyo3_name(input_definition: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "name").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "name") + .unwrap() + .bind(py) + .extract() + .unwrap(); let name_param: String = String::from("ro"); assert_eq!(name_op, name_param); }) @@ -232,8 +299,12 @@ fn test_pyo3_length(input_definition: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); - let length_op: &usize = - &usize::extract_bound(operation.call_method0(py, "length").unwrap().bind(py)).unwrap(); + let length_op: &usize = &operation + .call_method0(py, "length") + .unwrap() + .bind(py) + .extract() + .unwrap(); let length_param: &usize = &1_usize; assert_eq!(length_op, length_param); }) @@ -248,10 +319,12 @@ fn test_pyo3_is_output(input_definition: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); - assert!( - !bool::extract_bound(operation.call_method0(py, "is_output").unwrap().bind(py)) - .unwrap() - ); + assert!(!&operation + .call_method0(py, "is_output") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -265,8 +338,12 @@ fn test_pyo3_input_symbolic_input() { 1.0, ))) .unwrap(); - let input_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "input").unwrap().bind(py)).unwrap(); + let input_op: &f64 = &operation + .call_method0(py, "input") + .unwrap() + .bind(py) + .extract() + .unwrap(); let input_param: &f64 = &1.0; assert_eq!(input_op, input_param); }) @@ -283,8 +360,12 @@ fn test_pyo3_input_bit_index() { true, ))) .unwrap(); - let input_op: &usize = - &usize::extract_bound(operation.call_method0(py, "index").unwrap().bind(py)).unwrap(); + let input_op: &usize = &operation + .call_method0(py, "index") + .unwrap() + .bind(py) + .extract() + .unwrap(); let input_param: &usize = &1; assert_eq!(input_op, input_param); }) @@ -301,14 +382,70 @@ fn test_pyo3_input_bit_value() { true, ))) .unwrap(); - let input_op: &bool = - &bool::extract_bound(operation.call_method0(py, "value").unwrap().bind(py)).unwrap(); + let input_op: &bool = &operation + .call_method0(py, "value") + .unwrap() + .bind(py) + .extract() + .unwrap(); let input_param: &bool = &true; assert_eq!(input_op, input_param); }) } -/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic involved_qubits function +#[cfg(feature = "unstable_operation_definition")] +/// Test inputs for GateDefinition +#[test] +fn test_pyo3_gate_definition_inputs() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![1, 2], + vec!["test".into()], + ))) + .unwrap(); + + // Test circuit() + let to_circuit = operation.call_method0(py, "circuit").unwrap(); + let circuit_op = to_circuit.bind(py); + let circuit = new_circuit(py); + let comparison_circuit = + bool::extract_bound(&circuit_op.call_method1("__eq__", (circuit,)).unwrap()).unwrap(); + assert!(comparison_circuit); + + // Test name() + let name_op: String = operation + .call_method0(py, "name") + .unwrap() + .bind(py) + .extract() + .unwrap(); + let name_param: String = String::from("name"); + assert_eq!(name_op, name_param); + + // Test qubits() + let qubits: Vec = operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(qubits, vec![1, 2]); + + // Test free_parameters() + let free_parameters: Vec = operation + .call_method0(py, "free_parameters") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(free_parameters, vec!["test".to_owned()]); + }) +} + +/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic, involved_qubits function #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)); "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)); "DefinitionComplex")] #[test_case(Operation::from(DefinitionUsize::new(String::from("ro"), 1, false)); "DefinitionUsize")] @@ -319,17 +456,35 @@ fn test_pyo3_involved_qubits(input_definition: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); - let involved_op: HashSet = HashSet::extract_bound( - operation - .call_method0(py, "involved_qubits") - .unwrap() - .bind(py), - ) - .unwrap(); + let involved_op: HashSet = operation + .call_method0(py, "involved_qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); + let involved_param: HashSet<_> = HashSet::new(); + assert_eq!(involved_op, involved_param); + }) +} + +/// Test GateDefinition involved_qubits function +#[cfg(feature = "unstable_operation_definition")] +#[test_case(Operation::from(GateDefinition::new(Circuit::new(), String::from("ro"), vec![1], vec!["test".into()])); "GateDefinition")] +fn test_pyo3_involved_qubits_gate_definition(input_definition: Operation) { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(input_definition).unwrap(); + let involved_op: HashSet = operation + .call_method0(py, "involved_qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); let involved_param: HashSet<_> = HashSet::new(); assert_eq!(involved_op, involved_param); }) } + /// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit format and repr functions #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)), "DefinitionFloat"; "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)), "DefinitionComplex"; "DefinitionComplex")] @@ -340,9 +495,9 @@ fn test_pyo3_format_repr(input_definition: Operation, format_repr: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); let mut format_repr_param: String = String::from(format_repr); format_repr_param.push_str(" { name: \"ro\", length: 1, is_output: false }"); let comparison = format_repr_param.as_str(); @@ -362,10 +517,34 @@ fn test_pyo3_input_symbolic_format_repr() { ))) .unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); + let to_repr = operation.call_method0(py, "__repr__").unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); + let format_repr_param: String = String::from("InputSymbolic { name: \"ro\", input: 1.0 }"); + let comparison = format_repr_param.as_str(); + assert_eq!(format_op, comparison); + assert_eq!(repr_op, comparison); + }) +} + +/// Test GateDefinition format and repr functions +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_gate_definition_format_repr() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("ro"), + vec![1], + vec!["test".into()], + ))) + .unwrap(); + let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); - let format_repr_param: String = String::from("InputSymbolic { name: \"ro\", input: 1.0 }"); + let format_repr_param: String = String::from("GateDefinition { circuit: Circuit { definitions: [], operations: [], _roqoqo_version: RoqoqoVersion }, name: \"ro\", qubits: [1], free_parameters: [\"test\"] }"); let comparison = format_repr_param.as_str(); assert_eq!(format_op, comparison); assert_eq!(repr_op, comparison); @@ -406,6 +585,41 @@ fn test_pyo3_copy_deepcopy(input_definition: Operation) { }) } +/// Test GateDefinition copy and deepcopy functions +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_pyo3_copy_deepcopy_gate_definition() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + "name".to_owned(), + vec![0], + vec!["param".to_owned()], + ))) + .unwrap(); + let copy_op = operation.call_method0(py, "__copy__").unwrap(); + let deepcopy_op = operation.call_method1(py, "__deepcopy__", ("",)).unwrap(); + let copy_deepcopy_param = operation; + + let comparison_copy = bool::extract_bound( + ©_op + .bind(py) + .call_method1("__eq__", (copy_deepcopy_param.clone(),)) + .unwrap(), + ) + .unwrap(); + assert!(comparison_copy); + let comparison_deepcopy = bool::extract_bound( + &deepcopy_op + .bind(py) + .call_method1("__eq__", (copy_deepcopy_param,)) + .unwrap(), + ) + .unwrap(); + assert!(comparison_deepcopy); + }) +} /// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic tags function #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)), "DefinitionFloat"; "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)), "DefinitionComplex"; "DefinitionComplex")] @@ -418,7 +632,7 @@ fn test_pyo3_tags(input_definition: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &["Operation", "Definition", tag_name]; assert_eq!(tags_op, tags_param); }) @@ -435,8 +649,12 @@ fn test_pyo3_hqslang(input_definition: Operation, hqslang_param: String) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); - let hqslang_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let hqslang_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(hqslang_op, hqslang_param); }) } @@ -452,17 +670,46 @@ fn test_pyo3_is_parametrized(input_definition: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } -/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit substitute_parameters functions +// Test GateDefinitions's tags, hslang and is_parametrized functions +#[cfg(feature = "unstable_operation_definition")] +#[test_case(Operation::from(GateDefinition::new(Circuit::new(), String::from("ro"), vec![1], vec!["test".into()])); "GateDefinition")] +fn test_pyo3_gate_definition(input_definition: Operation) { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(input_definition).unwrap(); + + let to_tag = operation.call_method0(py, "tags").unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); + let tags_param: &[&str] = &["Operation", "Definition", "GateDefinition"]; + assert_eq!(tags_op, tags_param); + + let hqslang_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(hqslang_op, "GateDefinition"); + + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); + }) +} + +/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic, InputBit substitute_parameters functions #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)); "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)); "DefinitionComplex")] #[test_case(Operation::from(DefinitionUsize::new(String::from("ro"), 1, false)); "DefinitionUsize")] @@ -491,6 +738,37 @@ fn test_pyo3_substitute_parameters(input_definition: Operation) { }) } +/// Test GateDefinitions's substitute_parameters functions +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_substitute_parameters_gate_definition() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![1], + vec!["test".into()], + ))) + .unwrap(); + let mut substitution_dict: HashMap<&str, f64> = HashMap::new(); + substitution_dict.insert("name", 1.0); + let substitute_op = operation + .call_method1(py, "substitute_parameters", (substitution_dict,)) + .unwrap(); + let substitute_param = operation; + + let comparison_copy = bool::extract_bound( + &substitute_op + .bind(py) + .call_method1("__eq__", (substitute_param,)) + .unwrap(), + ) + .unwrap(); + assert!(comparison_copy); + }) +} + /// Test substitute_parameters() causing an error `not-a-real-number` #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)); "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)); "DefinitionComplex")] @@ -509,7 +787,27 @@ fn test_pyo3_substitute_parameters_error(input_operation: Operation) { }) } -/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit remap_qubits functions +/// Test GateDefinitions's substitute_parameters() causing an error `not-a-real-number` +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_substitute_parameters_error_gate_definition() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![1], + vec!["test".into()], + ))) + .unwrap(); + let mut substitution_dict: HashMap<&str, &str> = HashMap::new(); + substitution_dict.insert("name", "test"); + let result = operation.call_method1(py, "substitute_parameters", (substitution_dict,)); + assert!(result.is_err()); + }) +} + +/// Test DefinitionFloat, DefinitionComplex, DefinitionUsize, DefinitionBit, InputSymbolic, InputBit remap_qubits functions #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)); "DefinitionFloat")] #[test_case(Operation::from(DefinitionComplex::new(String::from("ro"), 1, false)); "DefinitionComplex")] #[test_case(Operation::from(DefinitionUsize::new(String::from("ro"), 1, false)); "DefinitionUsize")] @@ -539,6 +837,46 @@ fn test_pyo3_remap_qubits(input_definition: Operation) { }) } +/// Test GateDefinitions's remap_qubits functions +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_remap_qubits_gate_definition() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![0], + vec!["test".into()], + ))) + .unwrap(); + let remaped_operation = + convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![1], + vec!["test".into()], + ))) + .unwrap(); + let mut qubit_mapping: HashMap = HashMap::new(); + qubit_mapping.insert(0, 1); + qubit_mapping.insert(1, 0); + let remap_op = operation + .call_method1(py, "remap_qubits", (qubit_mapping,)) + .unwrap(); + let remap_param = remaped_operation; + + let comparison_copy = bool::extract_bound( + &remap_op + .bind(py) + .call_method1("__eq__", (remap_param,)) + .unwrap(), + ) + .unwrap(); + assert!(comparison_copy); + }) +} + /// Test the __richcmp__ function #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)), Operation::from(DefinitionFloat::new(String::from("ro"), 1, true)); @@ -590,6 +928,53 @@ fn test_pyo3_richcmp(definition_1: Operation, definition_2: Operation) { }) } +/// Test the __richcmp__ function for GateDefinitions +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_pyo3_richcmp_gate_definition() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation_one = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![0], + vec!["test".into()], + ))) + .unwrap(); + let operation_two = convert_operation_to_pyobject(Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![1], + vec!["testing".into()], + ))) + .unwrap(); + + let comparison = bool::extract_bound( + &operation_one + .bind(py) + .call_method1("__eq__", (operation_two.clone(),)) + .unwrap(), + ) + .unwrap(); + assert!(!comparison); + + let comparison = bool::extract_bound( + &operation_one + .bind(py) + .call_method1("__ne__", (operation_two.clone(),)) + .unwrap(), + ) + .unwrap(); + assert!(comparison); + + let comparison = operation_one.call_method1(py, "__eq__", (vec!["fails"],)); + assert!(comparison.is_err()); + + let comparison = operation_one.call_method1(py, "__ge__", (operation_two,)); + assert!(comparison.is_err()); + }) +} + /// Test json_schema function for all define operations #[cfg(feature = "json_schema")] #[test_case(Operation::from(DefinitionFloat::new(String::from("ro"), 1, false)); "DefinitionFloat")] @@ -644,3 +1029,37 @@ fn test_pyo3_json_schema(operation: Operation) { assert_eq!(minimum_supported_version_string, minimum_version); }); } + +/// Test json_schema function for GateDefinitions +#[test] +#[cfg(feature = "unstable_operation_definition")] +#[cfg(feature = "json_schema")] +fn test_pyo3_json_schema_gate_definition() { + let operation = Operation::from(GateDefinition::new( + Circuit::new(), + String::from("name"), + vec![0], + vec!["test".into()], + )); + let rust_schema = serde_json::to_string_pretty(&schemars::schema_for!(GateDefinition)).unwrap(); + pyo3::prepare_freethreaded_python(); + pyo3::Python::with_gil(|py| { + let minimum_version: String = "1.10.1".to_owned(); + let pyobject = convert_operation_to_pyobject(operation).unwrap(); + let operation = pyobject.bind(py); + + let schema: String = + String::extract_bound(&operation.call_method0("json_schema").unwrap()).unwrap(); + + assert_eq!(schema, rust_schema); + + let current_version_string = + String::extract_bound(&operation.call_method0("current_version").unwrap()).unwrap(); + let minimum_supported_version_string = + String::extract_bound(&operation.call_method0("min_supported_version").unwrap()) + .unwrap(); + + assert_eq!(current_version_string, ROQOQO_VERSION); + assert_eq!(minimum_supported_version_string, minimum_version); + }); +} diff --git a/qoqo/tests/integration/operations/measurement_operations.rs b/qoqo/tests/integration/operations/measurement_operations.rs index b9b78254..24b0811e 100644 --- a/qoqo/tests/integration/operations/measurement_operations.rs +++ b/qoqo/tests/integration/operations/measurement_operations.rs @@ -80,9 +80,12 @@ fn test_pyo3_readout(input_measurement: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - let readout_op: &String = - &String::extract_bound(operation.call_method0(py, "readout").unwrap().bind(py)) - .unwrap(); + let readout_op: &String = &operation + .call_method0(py, "readout") + .unwrap() + .bind(py) + .extract() + .unwrap(); let readout_param: String = String::from("ro"); assert_eq!(readout_op, &readout_param); }) @@ -95,9 +98,12 @@ fn test_pyo3_qubit_mapping(input_measurement: Operation, operation_name: &str) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - let readout_op: &HashMap = - &HashMap::extract_bound(operation.call_method0(py, operation_name).unwrap().bind(py)) - .unwrap(); + let readout_op: &HashMap = &operation + .call_method0(py, operation_name) + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(readout_op, &create_qubit_mapping()); }) } @@ -136,18 +142,21 @@ fn test_pyo3_input_measurequbit_input() { ))) .unwrap(); - let qubit_op: &usize = - &usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: &usize = &operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubit_param: &usize = &0; assert_eq!(qubit_op, qubit_param); - let ro_index_op: &usize = &usize::extract_bound( - operation - .call_method0(py, "readout_index") - .unwrap() - .bind(py), - ) - .unwrap(); + let ro_index_op: &usize = &operation + .call_method0(py, "readout_index") + .unwrap() + .bind(py) + .extract() + .unwrap(); let ro_index_param: &usize = &1; assert_eq!(ro_index_op, ro_index_param); }) @@ -163,13 +172,12 @@ fn test_pyo3_input_pragmarepeatedmeasurements_input() { )) .unwrap(); - let nbr_meas_op: &usize = &usize::extract_bound( - operation - .call_method0(py, "number_measurements") - .unwrap() - .bind(py), - ) - .unwrap(); + let nbr_meas_op: &usize = &operation + .call_method0(py, "number_measurements") + .unwrap() + .bind(py) + .extract() + .unwrap(); let nbr_meas_param: &usize = &2; assert_eq!(nbr_meas_op, nbr_meas_param); }) @@ -185,7 +193,7 @@ fn test_pyo3_involved_qubits_all(input_definition: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_involved = operation.call_method0(py, "involved_qubits").unwrap(); - let involved_op: HashSet = HashSet::extract_bound(to_involved.bind(py)).unwrap(); + let involved_op: HashSet = to_involved.bind(py).extract().unwrap(); let mut involved_param: HashSet = HashSet::new(); involved_param.insert("All".to_owned()); assert_eq!(involved_op, involved_param); @@ -200,7 +208,7 @@ fn test_pyo3_involved_qubits_0(input_definition: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_involved = operation.call_method0(py, "involved_qubits").unwrap(); - let involved_op: HashSet = HashSet::extract_bound(to_involved.bind(py)).unwrap(); + let involved_op: HashSet = to_involved.bind(py).extract().unwrap(); let mut involved_param: HashSet = HashSet::new(); involved_param.insert(0); assert_eq!(involved_op, involved_param); @@ -219,9 +227,9 @@ fn test_pyo3_format_repr(input_measurement: Operation, format_repr: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); assert_eq!(repr_op, format_repr); }) @@ -272,7 +280,7 @@ fn test_pyo3_tags(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &["Operation", "Measurement", "PragmaOperation", tag_name]; assert_eq!(tags_op, tags_param); }) @@ -290,7 +298,7 @@ fn test_pyo3_tags_measure_qubits() { ))) .unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &["Operation", "Measurement", "MeasureQubit"]; assert_eq!(tags_op, tags_param); }) @@ -307,8 +315,12 @@ fn test_pyo3_hqslang(input_measurement: Operation, hqslang_param: String) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - let hqslang_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let hqslang_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(hqslang_op, hqslang_param); }) } @@ -324,13 +336,12 @@ fn test_pyo3_is_parametrized(input_measurement: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!&operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -416,13 +427,12 @@ fn test_pyo3_remap_qubits(first_op: Operation, second_op: Operation) { .unwrap(); let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); let mut qubit_mapping_error = HashMap::new(); diff --git a/qoqo/tests/integration/operations/multi_qubit_gate_operations.rs b/qoqo/tests/integration/operations/multi_qubit_gate_operations.rs index 37ef7fd9..1322b2e4 100644 --- a/qoqo/tests/integration/operations/multi_qubit_gate_operations.rs +++ b/qoqo/tests/integration/operations/multi_qubit_gate_operations.rs @@ -16,6 +16,8 @@ use numpy::PyArray2; use pyo3::prelude::*; use pyo3::Python; use qoqo::operations::convert_operation_to_pyobject; +#[cfg(feature = "unstable_operation_definition")] +use qoqo::operations::CallDefinedGateWrapper; use qoqo::operations::{MultiQubitMSWrapper, MultiQubitZZWrapper}; use qoqo::CircuitWrapper; use qoqo_calculator::Calculator; @@ -112,6 +114,56 @@ fn test_new_multi_qubit_zz(input_operation: Operation, arguments: (Vec, f64 }) } +#[cfg(feature = "unstable_operation_definition")] +#[test_case(Operation::from(CallDefinedGate::new("name".to_owned(), vec![0, 1], vec![CalculatorFloat::from(0.0)])), ("name".to_owned(), vec![0, 1], vec![0.0],), "__eq__"; "CallDefinedGate_eq")] +#[test_case(Operation::from(CallDefinedGate::new("name".to_owned(), vec![2, 3], vec![CalculatorFloat::from(0.0)])), ("name".to_owned(), vec![0, 1], vec![0.0],), "__ne__"; "CallDefinedGate_ne")] +fn test_new_call_defined_gate( + input_operation: Operation, + arguments: (String, Vec, Vec), + method: &str, +) { + let operation = convert_operation_to_pyobject(input_operation).unwrap(); + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + // Basic initialisation, no errors + let operation_type = py.get_type_bound::(); + let binding = operation_type.call1(arguments).unwrap(); + let operation_py = binding.downcast::().unwrap(); + let comparison = bool::extract_bound( + &operation + .bind(py) + .call_method1(method, (operation_py,)) + .unwrap(), + ) + .unwrap(); + assert!(comparison); + + // Error initialisation + let result = operation_type.call1(([0, 1], vec!["fails"])); + assert!(result.is_err()); + + // Testing PartialEq, Clone and Debug + let def_wrapper = operation_py.extract::().unwrap(); + let new_op_diff = operation_type + .call1(("name".to_owned(), vec![1, 2], vec![0.0])) + .unwrap(); + let def_wrapper_diff = new_op_diff + .downcast::() + .unwrap() + .extract::() + .unwrap(); + let helper_ne: bool = def_wrapper_diff != def_wrapper; + assert!(helper_ne); + let helper_eq: bool = def_wrapper == def_wrapper.clone(); + assert!(helper_eq); + + assert_eq!( + format!("{:?}", def_wrapper_diff), + "CallDefinedGateWrapper { internal: CallDefinedGate { gate_name: \"name\", qubits: [1, 2], free_parameters: [Float(0.0)] } }" + ); + }) +} + /// Test is_parametrized() function for MultiQubitGate Operations #[test_case(Operation::from(MultiQubitMS::new(vec![0, 1], CalculatorFloat::from("theta"))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![0, 1], CalculatorFloat::from("theta"))); "MultiQubitZZ")] @@ -119,13 +171,12 @@ fn test_pyo3_is_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -136,13 +187,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -155,10 +205,12 @@ fn test_pyo3_theta(theta: CalculatorFloat, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let theta_op: CalculatorFloatWrapper = CalculatorFloatWrapper::extract_bound( - operation.call_method0(py, "theta").unwrap().bind(py), - ) - .unwrap(); + let theta_op: CalculatorFloatWrapper = operation + .call_method0(py, "theta") + .unwrap() + .bind(py) + .extract() + .unwrap(); let theta_param: CalculatorFloatWrapper = CalculatorFloatWrapper::extract_bound(&convert_cf_to_pyobject(py, theta)).unwrap(); assert_eq!(theta_op.internal, theta_param.internal); @@ -191,8 +243,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -222,9 +278,12 @@ fn test_pyo3_tags(input_operation: Operation, tags: Vec<&str>) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -232,6 +291,81 @@ fn test_pyo3_tags(input_operation: Operation, tags: Vec<&str>) { }) } +// Test CallDefinedGate's tags, hslang and is_parametrized functions +#[cfg(feature = "unstable_operation_definition")] +#[test_case(Operation::from(CallDefinedGate::new("name".to_owned(), vec![0, 1], vec![CalculatorFloat::from(0.0)])); "CallDefinedGate")] +fn test_pyo3_gate_definition(input_definition: Operation) { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(input_definition).unwrap(); + + let to_tag = operation.call_method0(py, "tags").unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); + let tags_param: &[&str] = &["Operation", "MultiQubitGateOperation", "CallDefinedGate"]; + assert_eq!(tags_op, tags_param); + + let hqslang_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(hqslang_op, "CallDefinedGate"); + + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); + }) +} + +/// Test inputs for CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_call_defined_gate_inputs() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + + // Test gate_name() + let name_op: String = operation + .call_method0(py, "gate_name") + .unwrap() + .bind(py) + .extract() + .unwrap(); + let name_param: String = String::from("name"); + assert_eq!(name_op, name_param); + + // Test qubits() + let qubits: Vec = operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(qubits, vec![1, 2]); + + // Test free_parameters() + let mut free_parameters: Vec = vec![]; + let py_params = operation.call_method0(py, "free_parameters").unwrap(); + let params: &pyo3::types::PyList = py_params.bind(py).extract().unwrap(); + for param in params.iter() { + free_parameters.push( + qoqo_calculator_pyo3::convert_into_calculator_float(¶m.as_borrowed()).unwrap(), + ); + } + assert_eq!(free_parameters, vec![CalculatorFloat::from(0.0)]); + }) +} + /// Test remap_qubits() function for MultiQubitGate Operations #[test_case(Operation::from(MultiQubitMS::new(vec![0, 1, 2], CalculatorFloat::from(1.3))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![0, 1, 2], CalculatorFloat::from(1.3))); "MultiQubitZZ")] @@ -268,6 +402,47 @@ fn test_pyo3_remapqubits(input_operation: Operation) { }) } +/// Test remap_qubits() function for CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_remapqubits_call_defined_gate() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![0, 1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + // test initial qubit + let qubits: Vec = operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(qubits, vec![0, 1, 2]); + // remap qubits + let mut qubit_mapping: HashMap = HashMap::new(); + qubit_mapping.insert(0, 1); + qubit_mapping.insert(1, 2); + qubit_mapping.insert(2, 0); + let result = operation + .call_method1(py, "remap_qubits", (qubit_mapping,)) + .unwrap(); + // test re-mapped qubit + let qubits_new: Vec = result + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); + assert_eq!(qubits_new, vec![1, 2, 0]); + // test that initial and rempapped qubits are different + assert_ne!(qubits, qubits_new); + }) +} + // test remap_qubits() function returning an error. #[test_case(Operation::from(MultiQubitMS::new(vec![0, 1, 2], CalculatorFloat::from(1.3))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![0, 1, 2], CalculatorFloat::from(1.3))); "MultiQubitZZ")] @@ -284,6 +459,27 @@ fn test_pyo3_remapqubits_error(input_operation: Operation) { }) } +/// test remap_qubits() function returning an error. +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_remapqubits_error_call_defined_gate() { + // preparation + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + // remap qubits + let mut qubit_mapping: HashMap = HashMap::new(); + qubit_mapping.insert(2, 0); + let result = operation.call_method1(py, "remap_qubits", (qubit_mapping,)); + assert!(result.is_err()); + }) +} + /// Test unitary_matrix() function for MultiQubitGate Operations #[test_case(Operation::from(MultiQubitMS::new(vec![0, 1, 2], CalculatorFloat::from(1.3))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![0, 1, 2], CalculatorFloat::from(1.3))); "MultiQubitZZ")] @@ -401,6 +597,41 @@ fn test_pyo3_copy_deepcopy(input_operation: Operation) { }) } +/// Test copy and deepcopy functions for CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_copy_deepcopy_call_defined_gate() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + let copy_op = operation.call_method0(py, "__copy__").unwrap(); + let deepcopy_op = operation.call_method1(py, "__deepcopy__", ("",)).unwrap(); + let copy_deepcopy_param = operation; + + let comparison_copy = bool::extract_bound( + ©_op + .bind(py) + .call_method1("__eq__", (copy_deepcopy_param.clone(),)) + .unwrap(), + ) + .unwrap(); + assert!(comparison_copy); + let comparison_deepcopy = bool::extract_bound( + &deepcopy_op + .bind(py) + .call_method1("__eq__", (copy_deepcopy_param,)) + .unwrap(), + ) + .unwrap(); + assert!(comparison_deepcopy); + }) +} + /// Test format and repr functions #[test_case( "MultiQubitMS { qubits: [0, 1, 2], theta: Float(0.0) }", @@ -415,14 +646,41 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(repr_op, format_repr); }) } +/// Test format and repr functions for CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_format_repr_call_defined_gate() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); + assert_eq!( + format_op, + "CallDefinedGate { gate_name: \"name\", qubits: [1, 2], free_parameters: [Float(0.0)] }" + ); + let to_repr = operation.call_method0(py, "__repr__").unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); + assert_eq!( + repr_op, + "CallDefinedGate { gate_name: \"name\", qubits: [1, 2], free_parameters: [Float(0.0)] }" + ); + }) +} + /// Test substitute_parameters() function for one parameter #[test_case(Operation::from(MultiQubitMS::new(vec![1, 2, 3], CalculatorFloat::from("theta"))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![1, 2, 3], CalculatorFloat::from("theta"))); "MultiQubitZZ")] @@ -454,6 +712,45 @@ fn test_pyo3_substitute_params_rotate(input_operation: Operation) { }) } +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_substitute_call_defined_gate() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from("theta")], + ))) + .unwrap(); + let mut substitution_dict_py: HashMap<&str, f64> = HashMap::new(); + substitution_dict_py.insert("theta", 1.0); + let substitute_op = operation + .call_method1(py, "substitute_parameters", (substitution_dict_py,)) + .unwrap(); + + let mut substitution_dict: Calculator = Calculator::new(); + substitution_dict.set_variable("theta", 1.0); + let substitute_param = Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from("theta")], + )) + .substitute_parameters(&substitution_dict) + .unwrap(); + let test_operation = convert_operation_to_pyobject(substitute_param).unwrap(); + + let comparison = bool::extract_bound( + &substitute_op + .bind(py) + .call_method1("__eq__", (test_operation,)) + .unwrap(), + ) + .unwrap(); + assert!(comparison); + }) +} + /// Test substitute_parameters() causing an error `None` #[test_case(Operation::from(MultiQubitMS::new(vec![1, 2], CalculatorFloat::from("test"))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![1, 2], CalculatorFloat::from("test"))); "MultiQubitZZ")] @@ -467,6 +764,23 @@ fn test_pyo3_substitute_params_error(input_operation: Operation) { }) } +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_substitute_params_error_call_defined_gate() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from("test")], + ))) + .unwrap(); + let substitution_dict: HashMap<&str, f64> = HashMap::new(); + let result = operation.call_method1(py, "substitute_parameters", (substitution_dict,)); + assert!(result.is_err()); + }) +} + #[test_case( Operation::from(MultiQubitMS::new(vec![0, 1, 2], CalculatorFloat::from(0.005))), Operation::from(MultiQubitMS::new(vec![0, 1, 2], CalculatorFloat::from(0.005 * 1.5))); "MultiQubitMS")] @@ -482,13 +796,12 @@ fn test_pyo3_rotate_powercf(first_op: Operation, second_op: Operation) { let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); let remapped_op = operation.call_method1(py, "powercf", (power,)).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); }) } @@ -532,6 +845,51 @@ fn test_pyo3_richcmp(definition_1: Operation, definition_2: Operation) { }) } +/// Test the __richcmp__ function for CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_pyo3_richcmp_call_defined_gate() { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation_one = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![0, 1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + let operation_two = convert_operation_to_pyobject(Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from(0.0)], + ))) + .unwrap(); + + let comparison = bool::extract_bound( + &operation_one + .bind(py) + .call_method1("__eq__", (operation_two.clone(),)) + .unwrap(), + ) + .unwrap(); + assert!(!comparison); + + let comparison = bool::extract_bound( + &operation_one + .bind(py) + .call_method1("__ne__", (operation_two.clone(),)) + .unwrap(), + ) + .unwrap(); + assert!(comparison); + + let comparison = operation_one.call_method1(py, "__eq__", (vec!["fails"],)); + assert!(comparison.is_err()); + + let comparison = operation_one.call_method1(py, "__ge__", (operation_two,)); + assert!(comparison.is_err()); + }) +} + #[cfg(feature = "json_schema")] #[test_case(Operation::from(MultiQubitMS::new(vec![0, 1, 2], CalculatorFloat::from(0))); "MultiQubitMS")] #[test_case(Operation::from(MultiQubitZZ::new(vec![0, 1, 2], CalculatorFloat::from(0))); "MultiQubitZZ")] @@ -565,3 +923,36 @@ fn test_pyo3_json_schema(operation: Operation) { assert_eq!(minimum_supported_version_string, "1.0.0"); }); } + +/// Test the json schema for CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[cfg(feature = "json_schema")] +#[test] +fn test_pyo3_json_schema_call_defined_gate() { + let operation = Operation::from(CallDefinedGate::new( + "name".to_owned(), + vec![1, 2], + vec![CalculatorFloat::from(0.0)], + )); + let rust_schema = + serde_json::to_string_pretty(&schemars::schema_for!(CallDefinedGate)).unwrap(); + pyo3::prepare_freethreaded_python(); + pyo3::Python::with_gil(|py| { + let pyobject = convert_operation_to_pyobject(operation).unwrap(); + let operation = pyobject.bind(py); + + let schema: String = + String::extract_bound(&operation.call_method0("json_schema").unwrap()).unwrap(); + + assert_eq!(schema, rust_schema); + + let current_version_string = + String::extract_bound(&operation.call_method0("current_version").unwrap()).unwrap(); + let minimum_supported_version_string = + String::extract_bound(&operation.call_method0("min_supported_version").unwrap()) + .unwrap(); + + assert_eq!(current_version_string, ROQOQO_VERSION); + assert_eq!(minimum_supported_version_string, "1.10.1"); + }); +} diff --git a/qoqo/tests/integration/operations/operation_conversions.rs b/qoqo/tests/integration/operations/operation_conversions.rs index 5bf50600..27fe900f 100644 --- a/qoqo/tests/integration/operations/operation_conversions.rs +++ b/qoqo/tests/integration/operations/operation_conversions.rs @@ -156,7 +156,7 @@ where hamiltonian .add_operator_product(pp.clone(), CalculatorFloat::from(p)) .unwrap(); - return ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()); + ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()) } #[cfg(feature = "unstable_analog_operations")] fn create_apply_timedependent_spin_hamiltonian(p: T) -> ApplyTimeDependentSpinHamiltonian @@ -172,7 +172,7 @@ where let mut values = HashMap::new(); values.insert("omega".to_string(), vec![1.0]); - return ApplyTimeDependentSpinHamiltonian::new(hamiltonian, vec![1.0], values.clone()); + ApplyTimeDependentSpinHamiltonian::new(hamiltonian, vec![1.0], values.clone()) } #[cfg(feature = "unstable_analog_operations")] @@ -187,6 +187,18 @@ fn test_conversion_feature(input: Operation) { }) } +#[cfg(feature = "unstable_operation_definition")] +#[test_case(Operation::from(GateDefinition::new(create_circuit(), "name".into(), vec![1, 2], vec!["test".into()])); "GateDefinition")] +#[test_case(Operation::from(CallDefinedGate::new("name".into(), vec![1, 2], vec![CalculatorFloat::from(0.6)])); "CallDefinedGate")] +fn test_conversion_operation_definition(input: Operation) { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|py| { + let operation = convert_operation_to_pyobject(input.clone()).unwrap(); + let output = convert_pyany_to_operation(operation.bind(py)).unwrap(); + assert_eq!(input, output) + }) +} + // ---------------- Helper functions ---------------- // fn reordering() -> HashMap { diff --git a/qoqo/tests/integration/operations/pragma_operations.rs b/qoqo/tests/integration/operations/pragma_operations.rs index 7d418856..2a3ecc02 100644 --- a/qoqo/tests/integration/operations/pragma_operations.rs +++ b/qoqo/tests/integration/operations/pragma_operations.rs @@ -89,7 +89,7 @@ fn circuit_remapped() -> Circuit { circuit } -fn new_circuit(py: Python) -> Bound { +pub(crate) fn new_circuit(py: Python) -> Bound { let circuit_type = py.get_type_bound::(); circuit_type .call0() @@ -107,19 +107,21 @@ fn test_pyo3_inputs_setnumbermeasurements() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let nbr_meas_op: &usize = &usize::extract_bound( - operation - .call_method0(py, "number_measurements") - .unwrap() - .bind(py), - ) - .unwrap(); + let nbr_meas_op: &usize = &operation + .call_method0(py, "number_measurements") + .unwrap() + .bind(py) + .extract() + .unwrap(); let nbr_meas_param: &usize = &1_usize; assert_eq!(nbr_meas_op, nbr_meas_param); - let readout_op: &String = - &String::extract_bound(operation.call_method0(py, "readout").unwrap().bind(py)) - .unwrap(); + let readout_op: &String = &operation + .call_method0(py, "readout") + .unwrap() + .bind(py) + .extract() + .unwrap(); let readout_param: &String = &String::from("ro"); assert_eq!(readout_op, readout_param); }) @@ -136,18 +138,23 @@ fn test_pyo3_inputs_loop() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let nbr_meas_op: &CalculatorFloatWrapper = &CalculatorFloatWrapper::extract_bound( - operation.call_method0(py, "repetitions").unwrap().bind(py), - ) - .unwrap(); + let nbr_meas_op: &CalculatorFloatWrapper = &operation + .call_method0(py, "repetitions") + .unwrap() + .bind(py) + .extract() + .unwrap(); let nbr_meas_param: &CalculatorFloatWrapper = &CalculatorFloatWrapper { internal: CalculatorFloat::from("number_t"), }; assert_eq!(nbr_meas_op.internal, nbr_meas_param.internal); - let readout_op: &CircuitWrapper = - &CircuitWrapper::extract_bound(operation.call_method0(py, "circuit").unwrap().bind(py)) - .unwrap(); + let readout_op: &CircuitWrapper = &operation + .call_method0(py, "circuit") + .unwrap() + .bind(py) + .extract() + .unwrap(); let readout_param: &CircuitWrapper = &CircuitWrapper { internal: Circuit::new(), }; @@ -201,13 +208,12 @@ fn test_pyo3_inputs_repeatgate() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let repeat_op: &usize = &usize::extract_bound( - operation - .call_method0(py, "repetition_coefficient") - .unwrap() - .bind(py), - ) - .unwrap(); + let repeat_op: &usize = &operation + .call_method0(py, "repetition_coefficient") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(repeat_op, &3_usize); }) } @@ -225,18 +231,33 @@ fn test_pyo3_inputs_overrotation() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let string_op: &String = - &String::extract_bound(operation.call_method0(py, "gate_hqslang").unwrap().bind(py)) - .unwrap(); + let string_op: &String = &operation + .call_method0(py, "gate_hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(string_op, &"RotateX".to_string()); - let qubits_op: &Vec = - &Vec::extract_bound(operation.call_method0(py, "qubits").unwrap().bind(py)).unwrap(); + let qubits_op: &Vec = &operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubits_op, &vec![0]); - let amp_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "amplitude").unwrap().bind(py)).unwrap(); + let amp_op: &f64 = &operation + .call_method0(py, "amplitude") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(amp_op, &0.03); - let var_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "variance").unwrap().bind(py)).unwrap(); + let var_op: &f64 = &operation + .call_method0(py, "variance") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(var_op, &0.001); }) } @@ -249,13 +270,12 @@ fn test_pyo3_inputs_boostnoise() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let boost_op: &f64 = &f64::extract_bound( - operation - .call_method0(py, "noise_coefficient") - .unwrap() - .bind(py), - ) - .unwrap(); + let boost_op: &f64 = &operation + .call_method0(py, "noise_coefficient") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(boost_op), CalculatorFloat::from(0.003), @@ -274,18 +294,21 @@ fn test_pyo3_inputs_stop() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubits_op: &Vec = - &Vec::extract_bound(operation.call_method0(py, "qubits").unwrap().bind(py)).unwrap(); + let qubits_op: &Vec = &operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubits_param: Vec = vec![0, 1]; assert_eq!(qubits_op, &qubits_param); - let boost_op: &f64 = &f64::extract_bound( - operation - .call_method0(py, "execution_time") - .unwrap() - .bind(py), - ) - .unwrap(); + let boost_op: &f64 = &operation + .call_method0(py, "execution_time") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(boost_op), CalculatorFloat::from(0.0000001), @@ -301,8 +324,12 @@ fn test_pyo3_inputs_globalphase() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let boost_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "phase").unwrap().bind(py)).unwrap(); + let boost_op: &f64 = &operation + .call_method0(py, "phase") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(CalculatorFloat::from(boost_op), CalculatorFloat::from(0.05)); }) } @@ -318,14 +345,21 @@ fn test_pyo3_inputs_sleep() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubits_op: &Vec = - &Vec::extract_bound(operation.call_method0(py, "qubits").unwrap().bind(py)).unwrap(); + let qubits_op: &Vec = &operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubits_param: Vec = vec![0, 1]; assert_eq!(qubits_op, &qubits_param); - let boost_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "sleep_time").unwrap().bind(py)) - .unwrap(); + let boost_op: &f64 = &operation + .call_method0(py, "sleep_time") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(boost_op), CalculatorFloat::from(0.0000001), @@ -341,8 +375,12 @@ fn test_pyo3_inputs_activereset() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubit_op: &usize = - &usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: &usize = &operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubit_param: &usize = &0_usize; assert_eq!(qubit_op, qubit_param); }) @@ -357,18 +395,21 @@ fn test_pyo3_inputs_startdecompblock() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubits_op: &Vec = - &Vec::extract_bound(operation.call_method0(py, "qubits").unwrap().bind(py)).unwrap(); + let qubits_op: &Vec = &operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubits_param: Vec = vec![0, 1]; assert_eq!(qubits_op, &qubits_param); - let boost_op: HashMap = HashMap::extract_bound( - operation - .call_method0(py, "reordering_dictionary") - .unwrap() - .bind(py), - ) - .unwrap(); + let boost_op: HashMap = operation + .call_method0(py, "reordering_dictionary") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(boost_op, reordering()); }) } @@ -381,8 +422,12 @@ fn test_pyo3_inputs_stopdecompblock() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubits_op: &Vec = - &Vec::extract_bound(operation.call_method0(py, "qubits").unwrap().bind(py)).unwrap(); + let qubits_op: &Vec = &operation + .call_method0(py, "qubits") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubits_param: Vec = vec![0, 1]; assert_eq!(qubits_op, &qubits_param); }) @@ -397,20 +442,32 @@ fn test_pyo3_inputs_noise(input_pragma: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubit_op: &usize = - &usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: &usize = &operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubit_param: &usize = &0_usize; assert_eq!(qubit_op, qubit_param); - let gate_time_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "gate_time").unwrap().bind(py)).unwrap(); + let gate_time_op: &f64 = &operation + .call_method0(py, "gate_time") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(gate_time_op), CalculatorFloat::from(0.005), ); - let rate_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "rate").unwrap().bind(py)).unwrap(); + let rate_op: &f64 = &operation + .call_method0(py, "rate") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(CalculatorFloat::from(rate_op), CalculatorFloat::from(0.02)); }) } @@ -428,37 +485,43 @@ fn test_pyo3_inputs_randomnoise() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubit_op: &usize = - &usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: &usize = &operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubit_param: &usize = &0_usize; assert_eq!(qubit_op, qubit_param); - let gate_time_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "gate_time").unwrap().bind(py)).unwrap(); + let gate_time_op: &f64 = &operation + .call_method0(py, "gate_time") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(gate_time_op), CalculatorFloat::from(0.005), ); - let depol_rate_op: &f64 = &f64::extract_bound( - operation - .call_method0(py, "depolarising_rate") - .unwrap() - .bind(py), - ) - .unwrap(); + let depol_rate_op: &f64 = &operation + .call_method0(py, "depolarising_rate") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(depol_rate_op), CalculatorFloat::from(0.02) ); - let dephas_rate_op: &f64 = &f64::extract_bound( - operation - .call_method0(py, "dephasing_rate") - .unwrap() - .bind(py), - ) - .unwrap(); + let dephas_rate_op: &f64 = &operation + .call_method0(py, "dephasing_rate") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(dephas_rate_op), CalculatorFloat::from(0.01) @@ -478,13 +541,21 @@ fn test_pyo3_inputs_generalnoise() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let qubit_op: &usize = - &usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: &usize = &operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); let qubit_param: &usize = &0_usize; assert_eq!(qubit_op, qubit_param); - let gate_time_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "gate_time").unwrap().bind(py)).unwrap(); + let gate_time_op: &f64 = &operation + .call_method0(py, "gate_time") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(gate_time_op), CalculatorFloat::from(0.005), @@ -516,23 +587,21 @@ fn test_pyo3_inputs_conditional() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let condition_register_op: &String = &String::extract_bound( - operation - .call_method0(py, "condition_register") - .unwrap() - .bind(py), - ) - .unwrap(); + let condition_register_op: &String = &operation + .call_method0(py, "condition_register") + .unwrap() + .bind(py) + .extract() + .unwrap(); let condition_register_param: &String = &String::from("ro"); assert_eq!(condition_register_op, condition_register_param); - let condition_index_op: &usize = &usize::extract_bound( - operation - .call_method0(py, "condition_index") - .unwrap() - .bind(py), - ) - .unwrap(); + let condition_index_op: &usize = &operation + .call_method0(py, "condition_index") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(condition_index_op, &1_usize); let to_circuit = operation.call_method0(py, "circuit").unwrap(); @@ -554,13 +623,12 @@ fn test_pyo3_inputs_controlled_circuit() { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - let condition_index_op: &usize = &usize::extract_bound( - operation - .call_method0(py, "controlling_qubit") - .unwrap() - .bind(py), - ) - .unwrap(); + let condition_index_op: &usize = &operation + .call_method0(py, "controlling_qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(condition_index_op, &1_usize); let to_circuit = operation.call_method0(py, "circuit").unwrap(); @@ -597,9 +665,12 @@ fn test_pyo3_inputs_annotated_op() { .unwrap(); assert!(comparison_op); - let annotation: String = - String::extract_bound(operation.call_method0(py, "annotation").unwrap().bind(py)) - .unwrap(); + let annotation: String = operation + .call_method0(py, "annotation") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(annotation, "test".to_string()); }) } @@ -615,7 +686,7 @@ fn test_pyo3_involved_qubits_none(input_definition: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_involved = operation.call_method0(py, "involved_qubits").unwrap(); - let involved_op: HashSet = HashSet::extract_bound(to_involved.bind(py)).unwrap(); + let involved_op: HashSet = to_involved.bind(py).extract().unwrap(); let involved_param: HashSet = HashSet::new(); assert_eq!(involved_op, involved_param); }) @@ -631,7 +702,7 @@ fn test_pyo3_involved_qubits_all(input_definition: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_involved = operation.call_method0(py, "involved_qubits").unwrap(); - let involved_op: HashSet = HashSet::extract_bound(to_involved.bind(py)).unwrap(); + let involved_op: HashSet = to_involved.bind(py).extract().unwrap(); let mut involved_param: HashSet = HashSet::new(); involved_param.insert("All".to_owned()); assert_eq!(involved_op, involved_param); @@ -657,7 +728,7 @@ fn test_pyo3_involved_qubits_qubit(input_definition: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_involved = operation.call_method0(py, "involved_qubits").unwrap(); - let involved_op: HashSet = HashSet::extract_bound(to_involved.bind(py)).unwrap(); + let involved_op: HashSet = to_involved.bind(py).extract().unwrap(); let mut involved_param: HashSet = HashSet::new(); involved_param.insert(0); assert_eq!(involved_op, involved_param); @@ -670,7 +741,7 @@ fn test_pyo3_involved_qubits_qubit_overrotation(input_definition: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_definition).unwrap(); let to_involved = operation.call_method0(py, "involved_qubits").unwrap(); - let involved_op: HashSet = HashSet::extract_bound(to_involved.bind(py)).unwrap(); + let involved_op: HashSet = to_involved.bind(py).extract().unwrap(); let mut involved_param: HashSet = HashSet::new(); involved_param.insert(0); assert_eq!(involved_op, involved_param); @@ -723,9 +794,9 @@ fn test_pyo3_format_repr(input_measurement: Operation, format_repr: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); assert_eq!(repr_op, format_repr); }) @@ -738,9 +809,9 @@ fn test_pyo3_format_repr_overrotation(input_measurement: Operation, format_repr: Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); assert_eq!(repr_op, format_repr); }) @@ -808,8 +879,7 @@ fn test_pyo3_copy_deepcopy_overrotation() { let copy_op = operation.call_method0(py, "__copy__").unwrap(); let deepcopy_op = operation.call_method1(py, "__deepcopy__", ("",)).unwrap(); - let extracted_copy: PragmaOverrotationWrapper = - PragmaOverrotationWrapper::extract_bound(copy_op.bind(py)).unwrap(); + let extracted_copy: PragmaOverrotationWrapper = copy_op.bind(py).extract().unwrap(); assert_eq!( extracted_copy.internal, PragmaOverrotation::new("RotateX".to_string(), vec![0], 0.03, 0.001) @@ -823,8 +893,7 @@ fn test_pyo3_copy_deepcopy_overrotation() { .unwrap(); assert!(comparison_copy); - let extracted_copy: PragmaOverrotationWrapper = - PragmaOverrotationWrapper::extract_bound(copy_op.bind(py)).unwrap(); + let extracted_copy: PragmaOverrotationWrapper = copy_op.bind(py).extract().unwrap(); assert_eq!( extracted_copy.internal, PragmaOverrotation::new("RotateX".to_string(), vec![0], 0.03, 0.001) @@ -854,7 +923,7 @@ fn test_pyo3_tags_simple(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &["Operation", "PragmaOperation", tag_name]; assert_eq!(tags_op, tags_param); }) @@ -870,7 +939,7 @@ fn test_pyo3_tags_multi(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &[ "Operation", "MultiQubitOperation", @@ -887,7 +956,7 @@ fn test_pyo3_tags_multi_overrotation(input_measurement: Operation, tag_name: &st Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &[ "Operation", "MultiQubitOperation", @@ -905,7 +974,7 @@ fn test_pyo3_tags_single(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &[ "Operation", "SingleQubitOperation", @@ -924,7 +993,7 @@ fn test_pyo3_tags_conditional(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &["Operation", "PragmaOperation", tag_name]; assert_eq!(tags_op, tags_param); }) @@ -937,7 +1006,7 @@ fn test_pyo3_tags_general_noise(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &[ "Operation", "SingleQubitOperation", @@ -959,7 +1028,7 @@ fn test_pyo3_tags_noise(input_measurement: Operation, tag_name: &str) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); let to_tag = operation.call_method0(py, "tags").unwrap(); - let tags_op: &Vec = &Vec::extract_bound(to_tag.bind(py)).unwrap(); + let tags_op: &Vec = &to_tag.bind(py).extract().unwrap(); let tags_param: &[&str] = &[ "Operation", "SingleQubitOperation", @@ -997,8 +1066,12 @@ fn test_pyo3_hqslang(input_measurement: Operation, hqslang_param: &str) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - let hqslang_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let hqslang_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(hqslang_op, hqslang_param.to_string()); }) } @@ -1008,8 +1081,12 @@ fn test_pyo3_hqslang_overrotation(input_measurement: Operation, hqslang_param: & pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - let hqslang_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let hqslang_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(hqslang_op, hqslang_param.to_string()); }) } @@ -1039,13 +1116,12 @@ fn test_pyo3_is_parametrized_false(input_pragma: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -1055,13 +1131,12 @@ fn test_pyo3_is_parametrized_true(input_pragma: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_pragma).unwrap(); - assert!(bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -1070,13 +1145,12 @@ fn test_pyo3_is_parametrized_overrotation(input_measurement: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_measurement).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -1181,20 +1255,18 @@ fn test_pyo3_substitute_parameters_overrotation() { .call_method1(py, "substitute_parameters", (substitution_dict,)) .unwrap(); - let extracted: PragmaOverrotationWrapper = - PragmaOverrotationWrapper::extract_bound(substitute_op.bind(py)).unwrap(); + let extracted: PragmaOverrotationWrapper = substitute_op.bind(py).extract().unwrap(); assert_eq!( extracted.internal, PragmaOverrotation::new("RotateX".to_string(), vec![0], 0.03, 0.001) ); - let comparison = bool::extract_bound( - &substitute_op - .bind(py) - .call_method1("__eq__", (operation,)) - .unwrap(), - ) - .unwrap(); + let comparison = substitute_op + .bind(py) + .call_method1("__eq__", (operation,)) + .unwrap() + .extract::() + .unwrap(); assert!(comparison); }) } @@ -1328,13 +1400,12 @@ fn test_pyo3_remap_qubits(first_op: Operation, second_op: Operation) { .unwrap(); let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); }) } @@ -1354,8 +1425,7 @@ fn test_pyo3_remap_qubits_overrotation() { let remapped_op = operation .call_method1(py, "remap_qubits", (qubit_remapping(),)) .unwrap(); - let extracted: PragmaOverrotationWrapper = - PragmaOverrotationWrapper::extract_bound(remapped_op.bind(py)).unwrap(); + let extracted: PragmaOverrotationWrapper = remapped_op.bind(py).extract().unwrap(); assert_eq!( extracted.internal, PragmaOverrotation::new("RotateX".to_string(), vec![2], 0.03, 0.001) @@ -1365,13 +1435,12 @@ fn test_pyo3_remap_qubits_overrotation() { PragmaOverrotation::new("RotateX".to_string(), vec![2], 0.03, 0.001), )) .unwrap(); - let comparison = bool::extract_bound( - &remapped_op - .bind(py) - .call_method1("__eq__", (operation_two,)) - .unwrap(), - ) - .unwrap(); + let comparison = remapped_op + .bind(py) + .call_method1("__eq__", (operation_two,)) + .unwrap() + .extract::() + .unwrap(); assert!(comparison); let mut qubit_mapping: HashMap = HashMap::new(); @@ -1529,9 +1598,12 @@ fn test_pyo3_noise_proba(noise_pragma: Operation, proba: f64) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(noise_pragma).unwrap(); - let gate_time_op: &f64 = - &f64::extract_bound(operation.call_method0(py, "probability").unwrap().bind(py)) - .unwrap(); + let gate_time_op: &f64 = &operation + .call_method0(py, "probability") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!( CalculatorFloat::from(gate_time_op), CalculatorFloat::from(proba), @@ -1561,13 +1633,12 @@ fn test_pyo3_noise_powercf(first_op: Operation, second_op: Operation) { let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); let remapped_op = operation.call_method1(py, "powercf", (power,)).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = &remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); }) } @@ -1678,8 +1749,7 @@ fn test_pyo3_richcmp_overrotation() { )) .unwrap(); - let extracted_one: PragmaOverrotationWrapper = - PragmaOverrotationWrapper::extract_bound(operation_one.bind(py)).unwrap(); + let extracted_one: PragmaOverrotationWrapper = operation_one.bind(py).extract().unwrap(); assert_eq!( extracted_one.internal, PragmaOverrotation::new("RotateX".to_string(), vec![0], 0.03, 0.001) diff --git a/qoqo/tests/integration/operations/single_qubit_gate_operations.rs b/qoqo/tests/integration/operations/single_qubit_gate_operations.rs index 3736235d..adf387a2 100644 --- a/qoqo/tests/integration/operations/single_qubit_gate_operations.rs +++ b/qoqo/tests/integration/operations/single_qubit_gate_operations.rs @@ -880,13 +880,12 @@ fn test_pyo3_is_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -939,13 +938,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -971,10 +969,12 @@ fn test_pyo3_theta(theta: CalculatorFloat, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let theta_op: CalculatorFloatWrapper = CalculatorFloatWrapper::extract_bound( - operation.call_method0(py, "theta").unwrap().bind(py), - ) - .unwrap(); + let theta_op: CalculatorFloatWrapper = operation + .call_method0(py, "theta") + .unwrap() + .bind(py) + .extract() + .unwrap(); let theta_param: CalculatorFloatWrapper = CalculatorFloatWrapper::extract_bound(&convert_cf_to_pyobject(py, theta)).unwrap(); assert_eq!(theta_op.internal, theta_param.internal); @@ -1019,8 +1019,12 @@ fn test_pyo3_qubit(qubit: usize, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let qubit_op: usize = - usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: usize = operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubit_op, qubit); }) } @@ -1073,8 +1077,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -1268,9 +1276,12 @@ fn test_pyo3_tags(input_operation: Operation, tags: Vec<&str>) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -1328,8 +1339,12 @@ fn test_pyo3_remapqubits(input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial qubit - let qubit: usize = - usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit: usize = operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubit.clone(), 0); // remap qubits let mut qubit_mapping: HashMap = HashMap::new(); @@ -1339,8 +1354,12 @@ fn test_pyo3_remapqubits(input_operation: Operation) { .call_method1(py, "remap_qubits", (qubit_mapping,)) .unwrap(); // test re-mapped qubit - let qubit_new: usize = - usize::extract_bound(result.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_new: usize = result + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubit_new.clone(), 1); // test that initial and rempapped qubits are different assert_ne!(qubit, qubit_new); @@ -2034,10 +2053,10 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(repr_op, format_repr); }) } @@ -2252,13 +2271,12 @@ fn test_pyo3_rotate_powercf(first_op: Operation, second_op: Operation) { let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); let remapped_op = operation.call_method1(py, "powercf", (power,)).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); }) } diff --git a/qoqo/tests/integration/operations/spin_boson_operations.rs b/qoqo/tests/integration/operations/spin_boson_operations.rs index f71cb3da..c6cb807a 100644 --- a/qoqo/tests/integration/operations/spin_boson_operations.rs +++ b/qoqo/tests/integration/operations/spin_boson_operations.rs @@ -317,13 +317,12 @@ fn test_pyo3_is_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -338,13 +337,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -359,8 +357,12 @@ fn test_pyo3_mode(mode: usize, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let mode_op: usize = - usize::extract_bound(operation.call_method0(py, "mode").unwrap().bind(py)).unwrap(); + let mode_op: usize = operation + .call_method0(py, "mode") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_op, mode); }) } @@ -375,8 +377,12 @@ fn test_pyo3_qubit(qubit: usize, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let qubit_op: usize = - usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_op: usize = operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubit_op, qubit); }) } @@ -392,8 +398,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -469,9 +479,12 @@ fn test_pyo3_tags(input_operation: Operation, tags: Vec<&str>) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -491,13 +504,12 @@ fn test_pyo3_involved_modes(input_operation: Operation, modes: HashSet) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial mode - let involved_modes: HashSet = HashSet::::extract_bound( - operation - .call_method0(py, "involved_modes") - .unwrap() - .bind(py), - ) - .unwrap(); + let involved_modes: HashSet = operation + .call_method0(py, "involved_modes") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(involved_modes, modes); }) } @@ -514,8 +526,12 @@ fn test_pyo3_remapqubits(input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial qubit - let qubit: usize = - usize::extract_bound(operation.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit: usize = operation + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubit.clone(), 1); // remap qubits let mut qubit_mapping: HashMap = HashMap::new(); @@ -525,8 +541,12 @@ fn test_pyo3_remapqubits(input_operation: Operation) { .call_method1(py, "remap_qubits", (qubit_mapping,)) .unwrap(); // test re-mapped qubit - let qubit_new: usize = - usize::extract_bound(result.call_method0(py, "qubit").unwrap().bind(py)).unwrap(); + let qubit_new: usize = result + .call_method0(py, "qubit") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(qubit_new.clone(), 0); // test that initial and rempapped qubits are different assert_ne!(qubit, qubit_new); @@ -545,8 +565,12 @@ fn test_pyo3_remapmodes_single(input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial mode - let mode: usize = - usize::extract_bound(operation.call_method0(py, "mode").unwrap().bind(py)).unwrap(); + let mode: usize = operation + .call_method0(py, "mode") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode.clone(), 0); // remap modes let mut mode_mapping: HashMap = HashMap::new(); @@ -556,8 +580,12 @@ fn test_pyo3_remapmodes_single(input_operation: Operation) { .call_method1(py, "remap_modes", (mode_mapping,)) .unwrap(); // test re-mapped mode - let mode_new: usize = - usize::extract_bound(result.call_method0(py, "mode").unwrap().bind(py)).unwrap(); + let mode_new: usize = result + .call_method0(py, "mode") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(mode_new.clone(), 1); // test that initial and rempapped modes are different assert_ne!(mode, mode_new); @@ -668,10 +696,10 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(repr_op, format_repr); }) } diff --git a/qoqo/tests/integration/operations/three_qubit_gate_operations.rs b/qoqo/tests/integration/operations/three_qubit_gate_operations.rs index 0019d05e..a05d02de 100644 --- a/qoqo/tests/integration/operations/three_qubit_gate_operations.rs +++ b/qoqo/tests/integration/operations/three_qubit_gate_operations.rs @@ -41,13 +41,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -80,9 +79,12 @@ fn test_pyo3_tags(tags: Vec<&str>, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -97,8 +99,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -112,16 +118,26 @@ fn test_pyo3_remapqubits(input_operation: Operation) { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial qubits - let control_0: usize = - usize::extract_bound(operation.call_method0(py, "control_0").unwrap().bind(py)) - .unwrap(); + let control_0: usize = operation + .call_method0(py, "control_0") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(control_0.clone(), 0); - let control_1: usize = - usize::extract_bound(operation.call_method0(py, "control_1").unwrap().bind(py)) - .unwrap(); + let control_1: usize = operation + .call_method0(py, "control_1") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(control_1.clone(), 1); - let target: usize = - usize::extract_bound(operation.call_method0(py, "target").unwrap().bind(py)).unwrap(); + let target: usize = operation + .call_method0(py, "target") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(target.clone(), 2); // remap qubits @@ -135,14 +151,26 @@ fn test_pyo3_remapqubits(input_operation: Operation) { .unwrap(); // test re-mapped qubit - let control_0_new: usize = - usize::extract_bound(result.call_method0(py, "control_0").unwrap().bind(py)).unwrap(); + let control_0_new: usize = result + .call_method0(py, "control_0") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(control_0_new.clone(), 2); - let control_1_new: usize = - usize::extract_bound(result.call_method0(py, "control_1").unwrap().bind(py)).unwrap(); + let control_1_new: usize = result + .call_method0(py, "control_1") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(control_1_new.clone(), 3); - let target_new: usize = - usize::extract_bound(result.call_method0(py, "target").unwrap().bind(py)).unwrap(); + let target_new: usize = result + .call_method0(py, "target") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(target_new.clone(), 0); // test that initial and rempapped qubits are different @@ -217,9 +245,9 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); assert_eq!(repr_op, format_repr); }) @@ -236,13 +264,12 @@ fn test_pyo3_copy_deepcopy(input_operation: Operation) { let deepcopy_op = operation.call_method1(py, "__deepcopy__", ("",)).unwrap(); let copy_deepcopy_param = operation; - let comparison_copy = bool::extract_bound( - ©_op - .bind(py) - .call_method1("__eq__", (copy_deepcopy_param.clone(),)) - .unwrap(), - ) - .unwrap(); + let comparison_copy = copy_op + .bind(py) + .call_method1("__eq__", (copy_deepcopy_param.clone(),)) + .unwrap() + .extract::() + .unwrap(); assert!(comparison_copy); let comparison_deepcopy = bool::extract_bound( &deepcopy_op @@ -305,13 +332,12 @@ fn test_pyo3_powercf(first_op: Operation, second_op: Operation) { let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); let remapped_op = operation.call_method1(py, "powercf", (power,)).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); }) } diff --git a/qoqo/tests/integration/operations/two_qubit_gate_operations.rs b/qoqo/tests/integration/operations/two_qubit_gate_operations.rs index a16b7d2a..d3a07548 100644 --- a/qoqo/tests/integration/operations/two_qubit_gate_operations.rs +++ b/qoqo/tests/integration/operations/two_qubit_gate_operations.rs @@ -67,13 +67,12 @@ fn test_pyo3_is_not_parametrized(input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - assert!(!bool::extract_bound( - operation - .call_method0(py, "is_parametrized") - .unwrap() - .bind(py) - ) - .unwrap()); + assert!(!operation + .call_method0(py, "is_parametrized") + .unwrap() + .bind(py) + .extract::() + .unwrap()); }) } @@ -289,9 +288,12 @@ fn test_pyo3_tags(tags: Vec<&str>, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let tags_op: Vec = - Vec::::extract_bound(operation.call_method0(py, "tags").unwrap().bind(py)) - .unwrap(); + let tags_op: Vec = operation + .call_method0(py, "tags") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(tags_op.len(), tags.len()); for i in 0..tags.len() { assert_eq!(tags_op[i], tags[i]); @@ -332,8 +334,12 @@ fn test_pyo3_hqslang(name: &'static str, input_operation: Operation) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); - let name_op: String = - String::extract_bound(operation.call_method0(py, "hqslang").unwrap().bind(py)).unwrap(); + let name_op: String = operation + .call_method0(py, "hqslang") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(name_op, name.to_string()); }) } @@ -370,11 +376,19 @@ fn test_pyo3_remapqubits(input_operation: Operation) { let operation = convert_operation_to_pyobject(input_operation).unwrap(); // test initial qubits - let control: usize = - usize::extract_bound(operation.call_method0(py, "control").unwrap().bind(py)).unwrap(); + let control: usize = operation + .call_method0(py, "control") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(control.clone(), 0); - let target: usize = - usize::extract_bound(operation.call_method0(py, "target").unwrap().bind(py)).unwrap(); + let target: usize = operation + .call_method0(py, "target") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(target.clone(), 1); // remap qubits @@ -388,11 +402,19 @@ fn test_pyo3_remapqubits(input_operation: Operation) { .unwrap(); // test re-mapped qubit - let control_new: usize = - usize::extract_bound(result.call_method0(py, "control").unwrap().bind(py)).unwrap(); + let control_new: usize = result + .call_method0(py, "control") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(control_new.clone(), 2); - let target_new: usize = - usize::extract_bound(result.call_method0(py, "target").unwrap().bind(py)).unwrap(); + let target_new: usize = result + .call_method0(py, "target") + .unwrap() + .bind(py) + .extract() + .unwrap(); assert_eq!(target_new.clone(), 3); // test that initial and rempapped qubits are different @@ -595,9 +617,9 @@ fn test_pyo3_format_repr(format_repr: &str, input_operation: Operation) { Python::with_gil(|py| { let operation = convert_operation_to_pyobject(input_operation).unwrap(); let to_format = operation.call_method1(py, "__format__", ("",)).unwrap(); - let format_op: String = String::extract_bound(to_format.bind(py)).unwrap(); + let format_op: String = to_format.bind(py).extract().unwrap(); let to_repr = operation.call_method0(py, "__repr__").unwrap(); - let repr_op: String = String::extract_bound(to_repr.bind(py)).unwrap(); + let repr_op: String = to_repr.bind(py).extract().unwrap(); assert_eq!(format_op, format_repr); assert_eq!(repr_op, format_repr); }) @@ -823,13 +845,12 @@ fn test_pyo3_powercf(first_op: Operation, second_op: Operation) { let comparison_op = convert_operation_to_pyobject(second_op).unwrap(); let remapped_op = operation.call_method1(py, "powercf", (power,)).unwrap(); - let comparison = bool::extract_bound( - remapped_op - .call_method1(py, "__eq__", (comparison_op,)) - .unwrap() - .bind(py), - ) - .unwrap(); + let comparison = remapped_op + .call_method1(py, "__eq__", (comparison_op,)) + .unwrap() + .bind(py) + .extract::() + .unwrap(); assert!(comparison); }) } @@ -1557,7 +1578,8 @@ fn test_new_qsim(input_operation: Operation, arguments: (u32, u32, f64, f64, f64 let result = operation_type.call1((0, 1, 0.0, vec!["fails"], 0.0)); assert!(result.is_err()); - let result = operation_type.call1((0, 1, 0.0, 0.0, vec!["fails"])); + let result: Result, PyErr> = + operation_type.call1((0, 1, 0.0, 0.0, vec!["fails"])); assert!(result.is_err()); // Testing PartialEq, Clone and Debug diff --git a/roqoqo-derive/Cargo.toml b/roqoqo-derive/Cargo.toml index f1677cb4..9ed27fa6 100644 --- a/roqoqo-derive/Cargo.toml +++ b/roqoqo-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roqoqo-derive" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" diff --git a/roqoqo-test/Cargo.toml b/roqoqo-test/Cargo.toml index 0cb3a2ee..90ba9dd7 100644 --- a/roqoqo-test/Cargo.toml +++ b/roqoqo-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roqoqo-test" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -19,7 +19,7 @@ crate-type = ["rlib"] [dependencies] qoqo_calculator = { version = "1.2" } -roqoqo = { version = "1.12.1", path = "../roqoqo", features = ["serialize"] } +roqoqo = { version = "1.13.0", path = "../roqoqo", features = ["serialize"] } rand = "0.8" nalgebra = "0.32" ndarray = { version = "0.15" } diff --git a/roqoqo/Cargo.toml b/roqoqo/Cargo.toml index 4c75c977..a00db5a8 100644 --- a/roqoqo/Cargo.toml +++ b/roqoqo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roqoqo" -version = "1.12.1" +version = "1.13.0" authors = ["HQS Quantum Simulations "] license = "Apache-2.0" edition = "2021" @@ -28,7 +28,7 @@ num-complex = { version = "0.4" } thiserror = "1.0" dyn-clone = { version = "1.0", optional = true } qoqo_calculator = { version = "1.2" } -roqoqo-derive = { version = "1.12.1", path = "../roqoqo-derive" } +roqoqo-derive = { version = "1.13.0", path = "../roqoqo-derive" } typetag = { version = "0.2", optional = true } nalgebra = "0.32" schemars = { version = "0.8", optional = true } @@ -56,6 +56,7 @@ rand = { version = "0.8" } rustdoc-args = ["--document-private-items"] [features] + default = ["serialize", "circuitdag"] dynamic = ["typetag", "dyn-clone"] unstable_qoqo_devices = [] @@ -77,3 +78,4 @@ json_schema = [ circuitdag = ["petgraph"] unstable_chain_with_environment = [] unstable_analog_operations = [] +unstable_operation_definition = [] diff --git a/roqoqo/build.rs b/roqoqo/build.rs index 581aa1d2..752ba83c 100644 --- a/roqoqo/build.rs +++ b/roqoqo/build.rs @@ -19,7 +19,7 @@ use std::str::FromStr; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::visit::{self, Visit}; -use syn::{AttrStyle, File, Ident, ItemImpl, ItemStruct, Path, Token, Type, TypePath}; +use syn::{AttrStyle, File, Ident, ItemImpl, ItemStruct, LitStr, Path, Token, Type, TypePath}; const NUMBER_OF_MINOR_VERSIONS: usize = 12; @@ -115,6 +115,18 @@ impl Visitor { } } +#[derive(Debug, Eq, PartialEq)] +struct CfgFeatureMacroArgument(String); + +impl Parse for CfgFeatureMacroArgument { + fn parse(input: ParseStream) -> syn::parse::Result { + input.parse::()?; + input.parse::()?; + let feature_name: LitStr = input.parse()?; + Ok(Self(feature_name.value())) + } +} + /// Struct for parsed derive macro arguments. Used to identify structs belonging to enums #[derive(Debug)] struct DeriveMacroArguments(HashSet); @@ -153,6 +165,17 @@ impl<'ast> Visit<'ast> for Visitor { // Check attributes for att in i.attrs.clone() { let path = att.path().get_ident().map(|id| id.to_string()); + // TOFIX: REMOVE WHEN STABILISED + if matches!(att.style, AttrStyle::Outer) + && path == Some("cfg".to_string()) + && !cfg!(feature = "unstable_operation_definition") + { + let cfg_feature_name: CfgFeatureMacroArgument = + att.parse_args().expect("parsing failed 1"); + if cfg_feature_name.0.contains("unstable_operation_definition") { + return; + } + } // only consider the derive attribute, if no derive attribute is present don't add anything // to the internal storage of the visitor if matches!(att.style, AttrStyle::Outer) && path == Some("derive".to_string()) { diff --git a/roqoqo/src/circuit.rs b/roqoqo/src/circuit.rs index f02e772a..ea36ecf4 100644 --- a/roqoqo/src/circuit.rs +++ b/roqoqo/src/circuit.rs @@ -176,6 +176,10 @@ impl Circuit { Operation::InputSymbolic(_) => { self.definitions.push(input); } + #[cfg(feature = "unstable_operation_definition")] + Operation::GateDefinition(_) => { + self.definitions.push(input); + } _ => self.operations.push(input), } } diff --git a/roqoqo/src/operations/define_operations.rs b/roqoqo/src/operations/define_operations.rs index 8ac12e6a..9a1a71ea 100644 --- a/roqoqo/src/operations/define_operations.rs +++ b/roqoqo/src/operations/define_operations.rs @@ -31,9 +31,10 @@ //! (5) InputSymbolic, where the user can define a floating point type value to replace a certain symbolic parameter. //! -use std::collections::HashSet; - use crate::operations::{Define, InvolveQubits, InvolvedQubits, Operate, RoqoqoError, Substitute}; +#[cfg(feature = "unstable_operation_definition")] +use crate::{operations::OperateMultiQubit, Circuit}; +use std::collections::HashSet; use super::SupportedVersion; @@ -272,3 +273,59 @@ impl InvolveQubits for InputBit { super::InvolvedClassical::Set(a) } } + +/// GateDefinition is the Definition of a new custom gate defined by a circuit that can be used with the CallDefinedGate Operation. +/// +#[cfg(feature = "unstable_operation_definition")] +#[derive( + Debug, + Clone, + PartialEq, + roqoqo_derive::OperateMultiQubit, + roqoqo_derive::Operate, + roqoqo_derive::Substitute, + roqoqo_derive::Define, +)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))] +pub struct GateDefinition { + /// The circuit where the definition is stored. + circuit: Circuit, + /// The name of the gate that is defined. + name: String, + /// The indices of the qubits used in the internal definition. + qubits: Vec, + /// Names of the free CalculatorFloat variables in the internal definition. + free_parameters: Vec, +} + +#[cfg(feature = "unstable_operation_definition")] +impl super::ImplementedIn1point13 for GateDefinition {} + +#[cfg(feature = "unstable_operation_definition")] +impl SupportedVersion for GateDefinition { + fn minimum_supported_roqoqo_version(&self) -> (u32, u32, u32) { + (1, 13, 0) + } +} + +#[cfg(feature = "unstable_operation_definition")] +#[allow(non_upper_case_globals)] +const TAGS_GateDefinition: &[&str; 3] = &["Operation", "Definition", "GateDefinition"]; + +#[cfg(feature = "unstable_operation_definition")] +// Implementing the InvolveQubits trait for GateDefinition. +impl InvolveQubits for GateDefinition { + /// Lists all involved Qubits (here, none). + fn involved_qubits(&self) -> InvolvedQubits { + InvolvedQubits::None + } + + fn involved_classical(&self) -> super::InvolvedClassical { + let mut classical_set: HashSet<(String, usize)> = HashSet::new(); + for parameter in &self.free_parameters { + classical_set.insert((parameter.to_owned(), 0)); + } + super::InvolvedClassical::Set(classical_set) + } +} diff --git a/roqoqo/src/operations/mod.rs b/roqoqo/src/operations/mod.rs index 7e621ce7..7a80c11f 100644 --- a/roqoqo/src/operations/mod.rs +++ b/roqoqo/src/operations/mod.rs @@ -844,6 +844,9 @@ pub trait ImplementedIn1point10: Operate {} /// Marker trait to show that some operation has been implemented in roqoqo 1.11.0 pub trait ImplementedIn1point11: Operate {} + +/// Marker trait to show that some operation has been implemented in roqoqo 1.13.0 +pub trait ImplementedIn1point13: Operate {} #[cfg(feature = "dynamic")] /// A wrapper for Operate trait objects. /// diff --git a/roqoqo/src/operations/multi_qubit_gate_operations.rs b/roqoqo/src/operations/multi_qubit_gate_operations.rs index afe8a755..90d3027d 100644 --- a/roqoqo/src/operations/multi_qubit_gate_operations.rs +++ b/roqoqo/src/operations/multi_qubit_gate_operations.rs @@ -160,3 +160,88 @@ impl OperateMultiQubitGate for MultiQubitZZ { circuit } } + +/// The gate to be replaced by a gate defined with GateDefinition gate. +/// +/// The gate applies a gate previously defined by GateDefinition with the name gate_name. +#[cfg(feature = "unstable_operation_definition")] +#[allow(clippy::upper_case_acronyms)] +#[derive( + Debug, + Clone, + PartialEq, + roqoqo_derive::OperateMultiQubit, + roqoqo_derive::Operate, + roqoqo_derive::InvolveQubits, +)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))] +pub struct CallDefinedGate { + /// The name of the called defined operations. + gate_name: String, + /// The qubits that for this call replace the qubits in the internal definition of the called gate + /// (get replaced in order of apppearance in gate defintion). + qubits: Vec, + /// List of float values that replace the free parameters in the internal defintion of the called gate + /// (get replaced in order of apppearance in gate defintion). + free_parameters: Vec, +} + +#[cfg(feature = "unstable_operation_definition")] +impl Substitute for CallDefinedGate { + fn substitute_parameters( + &self, + calculator: &qoqo_calculator::Calculator, + ) -> Result { + let mut new_params: Vec = vec![]; + for param in &self.free_parameters.clone() { + new_params.push(CalculatorFloat::from( + calculator + .parse_get(param.clone()) + .map_err(RoqoqoError::CalculatorError)?, + )); + } + + Ok(CallDefinedGate::new( + self.gate_name.clone(), + self.qubits.clone(), + new_params, + )) + } + + fn remap_qubits( + &self, + mapping: &std::collections::HashMap, + ) -> Result { + crate::operations::check_valid_mapping(mapping)?; + let mut new_qubits: Vec = Vec::new(); + for q in &self.qubits { + new_qubits.push(*mapping.get(q).ok_or(Err("")).map_err( + |_x: std::result::Result<&usize, &str>| RoqoqoError::QubitMappingError { + qubit: *q, + }, + )?) + } + + Ok(CallDefinedGate::new( + self.gate_name.clone(), + new_qubits, + self.free_parameters.clone(), + )) + } +} + +#[cfg(feature = "unstable_operation_definition")] +impl super::ImplementedIn1point13 for CallDefinedGate {} + +#[cfg(feature = "unstable_operation_definition")] +impl SupportedVersion for CallDefinedGate { + fn minimum_supported_roqoqo_version(&self) -> (u32, u32, u32) { + (1, 13, 0) + } +} + +#[cfg(feature = "unstable_operation_definition")] +#[allow(non_upper_case_globals)] +const TAGS_CallDefinedGate: &[&str; 3] = + &["Operation", "MultiQubitGateOperation", "CallDefinedGate"]; diff --git a/roqoqo/tests/integration/operations/analog_operations.rs b/roqoqo/tests/integration/operations/analog_operations.rs index 89174a1b..5bd783af 100644 --- a/roqoqo/tests/integration/operations/analog_operations.rs +++ b/roqoqo/tests/integration/operations/analog_operations.rs @@ -35,7 +35,7 @@ where hamiltonian .add_operator_product(pp.clone(), CalculatorFloat::from(p)) .unwrap(); - return ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()); + ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()) } fn create_apply_constant_spin_hamiltonian_param_time() -> ApplyConstantSpinHamiltonian { @@ -44,7 +44,7 @@ fn create_apply_constant_spin_hamiltonian_param_time() -> ApplyConstantSpinHamil hamiltonian .add_operator_product(pp.clone(), CalculatorFloat::from(1.0)) .unwrap(); - return ApplyConstantSpinHamiltonian::new(hamiltonian, "time".into()); + ApplyConstantSpinHamiltonian::new(hamiltonian, "time".into()) } fn create_param_apply_constant_spin_hamiltonian(p: T) -> ApplyConstantSpinHamiltonian @@ -59,7 +59,7 @@ where let pp = PauliProduct::new().x(1); hamiltonian.add_operator_product(pp, 1.0.into()).unwrap(); - return ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()); + ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()) } fn create_apply_timedependent_spin_hamiltonian(p: T) -> ApplyTimeDependentSpinHamiltonian @@ -75,7 +75,7 @@ where let mut values = HashMap::new(); values.insert("omega".to_string(), vec![1.0]); - return ApplyTimeDependentSpinHamiltonian::new(hamiltonian, vec![1.0], values.clone()); + ApplyTimeDependentSpinHamiltonian::new(hamiltonian, vec![1.0], values.clone()) } /// Test inputs diff --git a/roqoqo/tests/integration/operations/define_operations.rs b/roqoqo/tests/integration/operations/define_operations.rs index 8872f3f7..1b4acc7f 100644 --- a/roqoqo/tests/integration/operations/define_operations.rs +++ b/roqoqo/tests/integration/operations/define_operations.rs @@ -16,6 +16,8 @@ use jsonschema::{Draft, JSONSchema}; use qoqo_calculator::Calculator; use roqoqo::operations::*; +#[cfg(feature = "unstable_operation_definition")] +use roqoqo::Circuit; #[cfg(feature = "json_schema")] use schemars::schema_for; #[cfg(feature = "serialize")] @@ -880,3 +882,263 @@ pub fn input_bit_json_schema() { let validation_result = compiled_schema.validate(&test_value); assert!(validation_result.is_ok()); } + +/// Test GateDefinition inputs and involved qubits +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn gate_definition_inputs_qubits() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + + // Test inputs are correct + assert_eq!(def.circuit(), &Circuit::new()); + assert_eq!(def.name(), &String::from("test")); + assert_eq!(def.qubits(), &[0_usize]); + assert_eq!(def.free_parameters(), &["test"]); + + // Test InvolveQubits trait + assert_eq!(def.involved_qubits(), InvolvedQubits::None); +} + +/// Test GateDefinition standard derived traits (Debug, Clone, PartialEq) +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn gate_definition_simple_traits() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + + // Test Debug trait + assert_eq!( + format!("{:?}", def), + "GateDefinition { circuit: Circuit { definitions: [], operations: [], _roqoqo_version: RoqoqoVersion }, name: \"test\", qubits: [0], free_parameters: [\"test\"] }" + ); + + // Test Clone trait + assert_eq!(def.clone(), def); + + // Test PartialEq trait + let def_0 = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + let def_1 = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![1], + vec!["test1".to_owned()], + ); + assert!(def_0 == def); + assert!(def == def_0); + assert!(def_1 != def); + assert!(def != def_1); +} + +/// Test GateDefinition tags, hslang and is_parametized() trait +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn gate_definition_operate_trait() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + + // (1) Test tags function + let tags: &[&str; 3] = &["Operation", "Definition", "GateDefinition"]; + assert_eq!(def.tags(), tags); + + // (2) Test hqslang function + assert_eq!(def.hqslang(), String::from("GateDefinition")); + + // (3) Test is_parametrized function + assert!(!def.is_parametrized()); +} + +/// Test GateDefinition Substitute and remap qubits functions +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn gate_definition_substitute_trait() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + let def_test = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + let def_test2 = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![2], + vec!["test".to_owned()], + ); + + // (1) Substitute parameters function + let mut substitution_dict: Calculator = Calculator::new(); + substitution_dict.set_variable("test", 0.0); + let result = def_test.substitute_parameters(&substitution_dict).unwrap(); + assert_eq!(def, result); + + // (2) Remap qubits function + let newqubit: usize = 2; + let mut qubit_mapping_test: HashMap = HashMap::new(); + qubit_mapping_test.insert(0, newqubit); + qubit_mapping_test.insert(newqubit, 0); + let result = def.remap_qubits(&qubit_mapping_test).unwrap(); + assert_eq!(result, def_test2); +} + +/// Test GateDefinition Serialization and Deserialization traits (readable) +#[cfg(feature = "serialize")] +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn gate_definition_serde_readable() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + + assert_tokens( + &def.readable(), + &[ + Token::Struct { + name: "GateDefinition", + len: 4, + }, + Token::Str("circuit"), + Token::Struct { + name: "Circuit", + len: 3, + }, + Token::Str("definitions"), + Token::Seq { len: Some(0) }, + Token::SeqEnd, + Token::Str("operations"), + Token::Seq { len: Some(0) }, + Token::SeqEnd, + Token::Str("_roqoqo_version"), + Token::Struct { + name: "RoqoqoVersionSerializable", + len: 2, + }, + Token::Str("major_version"), + Token::U32(1), + Token::Str("minor_version"), + Token::U32(0), + Token::StructEnd, + Token::StructEnd, + Token::Str("name"), + Token::Str("test"), + Token::Str("qubits"), + Token::Seq { len: Some(1) }, + Token::U64(0), + Token::SeqEnd, + Token::Str("free_parameters"), + Token::Seq { len: Some(1) }, + Token::Str("test"), + Token::SeqEnd, + Token::StructEnd, + ], + ); +} + +/// Test GateDefinition Serialization and Deserialization traits (compact) +#[cfg(feature = "serialize")] +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn gate_definition_serde_compact() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + + assert_tokens( + &def.compact(), + &[ + Token::Struct { + name: "GateDefinition", + len: 4, + }, + Token::Str("circuit"), + Token::Struct { + name: "Circuit", + len: 3, + }, + Token::Str("definitions"), + Token::Seq { len: Some(0) }, + Token::SeqEnd, + Token::Str("operations"), + Token::Seq { len: Some(0) }, + Token::SeqEnd, + Token::Str("_roqoqo_version"), + Token::Struct { + name: "RoqoqoVersionSerializable", + len: 2, + }, + Token::Str("major_version"), + Token::U32(1), + Token::Str("minor_version"), + Token::U32(0), + Token::StructEnd, + Token::StructEnd, + Token::Str("name"), + Token::Str("test"), + Token::Str("qubits"), + Token::Seq { len: Some(1) }, + Token::U64(0), + Token::SeqEnd, + Token::Str("free_parameters"), + Token::Seq { len: Some(1) }, + Token::Str("test"), + Token::SeqEnd, + Token::StructEnd, + ], + ); +} + +/// Test GateDefinition JsonSchema trait +#[cfg(feature = "json_schema")] +#[cfg(feature = "unstable_operation_definition")] +#[test] +pub fn gate_definition_json_schema() { + let def = GateDefinition::new( + Circuit::new(), + String::from("test"), + vec![0], + vec!["test".to_owned()], + ); + // Serialize + let test_json = serde_json::to_string(&def).unwrap(); + let test_value: serde_json::Value = serde_json::from_str(&test_json).unwrap(); + + // Create JSONSchema + let test_schema = schema_for!(GateDefinition); + let schema = serde_json::to_string(&test_schema).unwrap(); + let schema_value: serde_json::Value = serde_json::from_str(&schema).unwrap(); + let compiled_schema = JSONSchema::options() + .with_draft(Draft::Draft7) + .compile(&schema_value) + .unwrap(); + + let validation_result = compiled_schema.validate(&test_value); + assert!(validation_result.is_ok()); +} diff --git a/roqoqo/tests/integration/operations/multi_qubit_gate_operations.rs b/roqoqo/tests/integration/operations/multi_qubit_gate_operations.rs index 46c049cc..928619ab 100644 --- a/roqoqo/tests/integration/operations/multi_qubit_gate_operations.rs +++ b/roqoqo/tests/integration/operations/multi_qubit_gate_operations.rs @@ -601,3 +601,157 @@ pub fn test_json_schema_multi_qubit_gate_operations(gate: MultiQubitGateOperatio let validation_result = compiled_schema.validate(&test_value); assert!(validation_result.is_ok()); } + +// Test partialEq function of CallDefinedGate +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_clone_partial_eq_call_defined_gate() { + let qubits = vec![0, 1, 2]; + + let gate = CallDefinedGate::new( + "name".into(), + qubits.clone(), + vec![CalculatorFloat::from(0.6)], + ); + assert_eq!(gate.hqslang(), "CallDefinedGate"); + assert_eq!( + gate.tags(), + &["Operation", "MultiQubitGateOperation", "CallDefinedGate",] + ); + assert!(!gate.is_parametrized()); + let gate1 = CallDefinedGate::new("name".into(), qubits, vec![CalculatorFloat::from(0.7)]); + let helper = gate != gate1; + assert!(helper); + #[allow(clippy::redundant_clone)] + let gate2 = gate1.clone(); + assert_eq!(gate2, gate1); +} + +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_substitute_call_defined_gate() { + let qubits = vec![0, 1, 2]; + let gate1 = CallDefinedGate::new("name".to_owned(), qubits.clone(), vec!["theta".into()]); + let gate = CallDefinedGate::new("name".to_owned(), qubits, vec![CalculatorFloat::FRAC_PI_2]); + let mut calc = Calculator::new(); + calc.set_variable("theta", std::f64::consts::FRAC_PI_2); + let gate_substituted = roqoqo::operations::Substitute::substitute_parameters(&gate1, &calc); + let subs = gate_substituted.unwrap(); + assert_eq!(gate, subs); + let mut mapping: HashMap = std::collections::HashMap::new(); + let _ = mapping.insert(0, 1); + let _ = mapping.insert(1, 2); + let _ = mapping.insert(2, 0); + let remapped = gate1.remap_qubits(&mapping).unwrap(); + let qubits = remapped.qubits(); + assert_eq!(qubits, &vec![1, 2, 0]); +} + +#[cfg(feature = "unstable_operation_definition")] +#[test] +fn test_substitute_error_call_defined_gate() { + let qubits = vec![0, 1, 2]; + let gate1 = CallDefinedGate::new("name".to_owned(), qubits, vec!["theta".into()]); + let calc = Calculator::new(); + let gate_substituted = gate1.substitute_parameters(&calc); + assert!(gate_substituted.is_err()); + let mut mapping: HashMap = std::collections::HashMap::new(); + let _ = mapping.insert(1, 2); + let _ = mapping.insert(2, 0); + let remapped = gate1.remap_qubits(&mapping); + assert!(remapped.is_err()); +} + +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_format_call_defined_gate() { + let qubits = vec![0, 1, 2]; + let gate = CallDefinedGate::new( + "name".into(), + qubits.clone(), + vec![CalculatorFloat::from(0.6)], + ); + let string = format!("{:?}", gate); + assert!( + string + == "CallDefinedGate { gate_name: \"name\", qubits: [0, 1, 2], free_parameters: [Float(0.6)] }" + ); +} + +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_remap_defined_gate() { + let qubits = vec![0, 1, 2]; + let gate = CallDefinedGate::new( + "name".into(), + qubits.clone(), + vec![CalculatorFloat::from(0.6)], + ); + let mut mapping: HashMap = std::collections::HashMap::new(); + let _ = mapping.insert(0, 1); + let _ = mapping.insert(1, 2); + let _ = mapping.insert(2, 0); + let remapped = gate.remap_qubits(&mapping).unwrap(); + let qubits = remapped.qubits(); + assert_eq!(qubits, &vec![1, 2, 0]); +} + +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_remap_error_call_defined_gate() { + let qubits = vec![0, 1, 2]; + let gate = CallDefinedGate::new( + "name".into(), + qubits.clone(), + vec![CalculatorFloat::from(0.6)], + ); + let mut mapping: HashMap = std::collections::HashMap::new(); + let _ = mapping.insert(1, 2); + let _ = mapping.insert(2, 0); + let remapped = gate.remap_qubits(&mapping); + assert!(remapped.is_err()); +} + +#[test] +#[cfg(feature = "unstable_operation_definition")] +fn test_involved_qubits_call_defined_gate() { + let qubits = vec![0, 1, 2]; + let gate = CallDefinedGate::new( + "name".into(), + qubits.clone(), + vec![CalculatorFloat::Float(0.6)], + ); + let involved_qubits = gate.involved_qubits(); + let mut comp_set: HashSet = HashSet::new(); + let _ = comp_set.insert(0); + let _ = comp_set.insert(1); + let _ = comp_set.insert(2); + assert_eq!(involved_qubits, InvolvedQubits::Set(comp_set)); +} + +#[test] +#[cfg(feature = "unstable_operation_definition")] +#[cfg(feature = "json_schema")] +pub fn test_json_schema_multi_qubit_call_gate() { + let qubits = vec![0, 1, 2]; + let gate = CallDefinedGate::new( + "name".into(), + qubits.clone(), + vec![CalculatorFloat::Float(0.6)], + ); + // Serialize + let test_json = serde_json::to_string(&gate).unwrap(); + let test_value: serde_json::Value = serde_json::from_str(&test_json).unwrap(); + + // Create JSONSchema + let test_schema = schema_for!(CallDefinedGate); + let schema = serde_json::to_string(&test_schema).unwrap(); + let schema_value: serde_json::Value = serde_json::from_str(&schema).unwrap(); + let compiled_schema = JSONSchema::options() + .with_draft(Draft::Draft7) + .compile(&schema_value) + .unwrap(); + + let validation_result = compiled_schema.validate(&test_value); + assert!(validation_result.is_ok()); +} diff --git a/roqoqo/tests/integration/operations/supported_version.rs b/roqoqo/tests/integration/operations/supported_version.rs index 33c42d0a..06232787 100644 --- a/roqoqo/tests/integration/operations/supported_version.rs +++ b/roqoqo/tests/integration/operations/supported_version.rs @@ -13,7 +13,7 @@ //! Integration test for supported version trait use ndarray::array; -#[cfg(feature = "unstable_analog_operations")] +#[cfg(feature = "unstable_operation_definition")] use qoqo_calculator::CalculatorFloat; #[cfg(feature = "circuitdag")] use roqoqo::measurements::Cheated; @@ -128,6 +128,14 @@ fn test_version_1_0_0_multi_qubit_gate(operation: operations::MultiQubitGateOper assert_eq!(op.minimum_supported_roqoqo_version(), (1, 0, 0)); } +#[cfg(feature = "unstable_operation_definition")] +#[test_case(operations::MultiQubitOperation::from(operations::CallDefinedGate::new("test".into(), vec![0,1,2,3], vec![CalculatorFloat::Float(1.0)])); "CallDefinedGate")] +fn test_version_1_13_0_multi_qubit_gate(operation: operations::MultiQubitOperation) { + assert_eq!(operation.minimum_supported_roqoqo_version(), (1, 13, 0)); + let op = operations::Operation::from(operation); + assert_eq!(op.minimum_supported_roqoqo_version(), (1, 13, 0)); +} + #[test_case(operations::SingleModeGateOperation::from(operations::Squeezing::new(0, 1.0.into(), 0.0.into())); "Squeezing")] #[test_case(operations::SingleModeGateOperation::from(operations::PhaseShift::new(0, 1.0.into())); "PhaseShift")] fn test_version_1_6_0_single_mode_gate(operation: operations::SingleModeGateOperation) { @@ -165,7 +173,7 @@ where hamiltonian .add_operator_product(pp.clone(), CalculatorFloat::from(p)) .unwrap(); - return operations::ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()); + operations::ApplyConstantSpinHamiltonian::new(hamiltonian, 1.0.into()) } #[cfg(feature = "unstable_analog_operations")] fn create_apply_timedependent_spin_hamiltonian( @@ -183,11 +191,7 @@ where let mut values = HashMap::new(); values.insert("omega".to_string(), vec![1.0]); - return operations::ApplyTimeDependentSpinHamiltonian::new( - hamiltonian, - vec![1.0], - values.clone(), - ); + operations::ApplyTimeDependentSpinHamiltonian::new(hamiltonian, vec![1.0], values.clone()) } #[cfg(feature = "unstable_analog_operations")] @@ -195,7 +199,7 @@ where #[test_case(operations::SpinsAnalogOperation::from(create_apply_timedependent_spin_hamiltonian("omega"));"ApplyTimeDependentHamiltonian")] fn test_version_1_11_0_spin_analog_operations(operation: operations::SpinsAnalogOperation) { assert_eq!(operation.minimum_supported_roqoqo_version(), (1, 11, 0)); - let op = operations::Operation::try_from(operation).unwrap(); + let op = operations::Operation::from(operation); assert_eq!(op.minimum_supported_roqoqo_version(), (1, 11, 0)); } @@ -348,3 +352,9 @@ fn test_version_circuit(circuit: roqoqo::Circuit, version: (u32, u32, u32)) { }; assert_eq!(program.minimum_supported_roqoqo_version(), version); } + +#[cfg(feature = "unstable_operation_definition")] +#[test_case(operations::Operation::from(operations::GateDefinition::new(roqoqo::Circuit::new(), "name".to_string(), vec![2], vec!["name".to_owned()])); "GateDefinition")] +fn test_version_1_13_0_gate_definition(operation: operations::Operation) { + assert_eq!(operation.minimum_supported_roqoqo_version(), (1, 13, 0)); +}