diff --git a/compiler/qsc_eval/src/intrinsic.rs b/compiler/qsc_eval/src/intrinsic.rs index 21c1f19407..16aecd1f88 100644 --- a/compiler/qsc_eval/src/intrinsic.rs +++ b/compiler/qsc_eval/src/intrinsic.rs @@ -100,6 +100,10 @@ pub(crate) fn call( Ok(Value::Double(rng.gen_range(lo..=hi))) } } + "DrawRandomBool" => { + let p = arg.unwrap_double(); + Ok(Value::Bool(rng.gen_bool(p))) + } #[allow(clippy::cast_possible_truncation)] "Truncate" => Ok(Value::Int(arg.unwrap_double() as i64)), "__quantum__rt__qubit_allocate" => Ok(Value::Qubit(Qubit(sim.qubit_allocate()))), diff --git a/compiler/qsc_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs index b3a4001802..de795bbf76 100644 --- a/compiler/qsc_eval/src/intrinsic/tests.rs +++ b/compiler/qsc_eval/src/intrinsic/tests.rs @@ -680,6 +680,20 @@ fn draw_random_double() { ); } +#[test] +fn draw_random_bool() { + check_intrinsic_value( + "", + "Microsoft.Quantum.Random.DrawRandomBool(0.0)", + &Value::Bool(false), + ); + check_intrinsic_value( + "", + "Microsoft.Quantum.Random.DrawRandomBool(1.0)", + &Value::Bool(true), + ); +} + #[test] fn truncate() { check_intrinsic_value("", "Microsoft.Quantum.Math.Truncate(3.1)", &Value::Int(3)); diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs index 39e7d9bcb2..cf153abc56 100644 --- a/compiler/qsc_partial_eval/src/lib.rs +++ b/compiler/qsc_partial_eval/src/lib.rs @@ -1298,7 +1298,7 @@ impl<'a> PartialEvaluator<'a> { | "GlobalPhase" => Ok(Value::unit()), // The following intrinsic functions and operations should never make it past conditional compilation and // the capabilities check pass. - "CheckZero" | "DrawRandomInt" | "DrawRandomDouble" | "Length" => { + "CheckZero" | "DrawRandomInt" | "DrawRandomDouble" | "DrawRandomBool" | "Length" => { Err(Error::Unexpected( format!( "`{}` is not a supported by partial evaluation", diff --git a/compiler/qsc_partial_eval/tests/intrinsics.rs b/compiler/qsc_partial_eval/tests/intrinsics.rs index e985b23694..6133f70d63 100644 --- a/compiler/qsc_partial_eval/tests/intrinsics.rs +++ b/compiler/qsc_partial_eval/tests/intrinsics.rs @@ -974,6 +974,22 @@ fn call_to_draw_random_double_panics() { }); } +#[test] +#[should_panic(expected = "`DrawRandomBool` is not a supported by partial evaluation")] +fn call_to_draw_random_bool_panics() { + _ = get_rir_program(indoc! { + r#" + namespace Test { + open Microsoft.Quantum.Random; + @EntryPoint() + operation Main() : Unit { + let _ = DrawRandomBool(0.0); + } + } + "#, + }); +} + #[test] fn call_to_length_in_inner_function_succeeds() { let program = get_rir_program(indoc! { diff --git a/compiler/qsc_rca/tests/intrinsics.rs b/compiler/qsc_rca/tests/intrinsics.rs index feb6bb81aa..37b3926580 100644 --- a/compiler/qsc_rca/tests/intrinsics.rs +++ b/compiler/qsc_rca/tests/intrinsics.rs @@ -1148,6 +1148,31 @@ fn check_rca_for_draw_random_double() { ); } +#[test] +fn check_rca_for_draw_random_bool() { + let compilation_context = CompilationContext::default(); + check_callable_compute_properties( + &compilation_context.fir_store, + compilation_context.get_compute_properties(), + "DrawRandomBool", + &expect![ + r#" + Callable: CallableComputeProperties: + body: ApplicationsGeneratorSet: + inherent: Quantum: QuantumProperties: + runtime_features: RuntimeFeatureFlags(0x0) + value_kind: Element(Dynamic) + dynamic_param_applications: + [0]: [Parameter Type Element] Quantum: QuantumProperties: + runtime_features: RuntimeFeatureFlags(UseOfDynamicDouble) + value_kind: Element(Dynamic) + adj: + ctl: + ctl-adj: "# + ], + ); +} + #[test] fn check_rca_for_begin_estimate_caching() { let compilation_context = CompilationContext::default(); diff --git a/library/std/random.qs b/library/std/random.qs index c568ccbcb2..805e1e46fc 100644 --- a/library/std/random.qs +++ b/library/std/random.qs @@ -51,4 +51,25 @@ namespace Microsoft.Quantum.Random { body intrinsic; } + /// # Summary + /// Given a success probability, returns a single Bernoulli trial + /// that is true with the given probability. + /// + /// # Input + /// ## successProbability + /// The probability with which true should be returned. + /// + /// # Output + /// `true` with probability `successProbability` + /// and `false` with probability `1.0 - successProbability`. + /// + /// # Example + /// The following Q# snippet samples flips from a biased coin: + /// ```qsharp + /// let flips = DrawMany(DrawRandomBool, 10, 0.6); + /// ``` + @Config(Unrestricted) + operation DrawRandomBool(successProbability : Double) : Bool { + body intrinsic; + } }