/// <summary>
        /// Ensures that measurement of given observable on given qubits will
        /// lead to result given by value
        /// </summary>
        public void ForceMeasure(IQArray <Pauli> observable, IQArray <Qubit> qubits, Result value)
        {
            Debug.Assert(observable != null);
            Debug.Assert(qubits != null);
            Debug.Assert(observable.Length == qubits.Length);

            Utils.PruneObservable(observable, qubits, out var observablePr, out var _);
            var constr = MeasurementConstraint.ForceMeasurement(observablePr, value);

            QubitConstraint.SetConstraint(QubitConstraints(qubits), constr);
        }
        /// <summary>
        /// Implements the Q# standard library callable AssertProb
        /// </summary>
        public void AssertProb(IQArray <Pauli> observable, IQArray <Qubit> qubits, Result value, double probability)
        {
            Debug.Assert(observable != null);
            Debug.Assert(qubits != null);
            Debug.Assert(observable.Length == qubits.Length);

            Utils.PruneObservable(observable, qubits, out var observablePr, out var qubitsPr);
            Debug.Assert((probability >= 0.0) && (probability <= 1.0));
            MeasurementConstraint constr = MeasurementConstraint.AssertMeasurement(observablePr, value, probability);

            QubitConstraint.SetConstraint(QubitConstraints(qubitsPr), constr);
        }
        /// <summary>
        /// Implements the Q# standard library callable Measure.
        /// Not all measurements considered primitive operations. The measurements
        /// that are primitive operations are listed in
        /// MetricsCalculatorConfiguration.MeasurementToPrimitiveOperation
        /// If the measurement is not primitive, the operation will throw
        /// NonPrimitiveMeasurementException.
        /// </summary>
        public Result Measure(IQArray <Pauli> observable, IQArray <Qubit> qubits)
        {
            Debug.Assert(observable != null);
            Debug.Assert(qubits != null);

            Utils.PruneObservable(observable, qubits, out var observablePr, out var qubitsPr);

            if (observablePr.Count == 0)
            {
                return(Result.Zero);
            }

            QubitConstraint[] constr = QubitConstraints(qubitsPr);

            QubitConstraint qubit0Constraint = constr[0];

            if (qubit0Constraint.Constraint == null)
            {
                return(UnconstrainedMeasurementResult());
            }
            else
            {
                for (int i = 0; i < qubitsPr.Count; ++i)
                {
                    QubitConstraint qubitIConstraint = constr[i];

                    // makes sure that none of the qubits constraints have been invalidated
                    if (qubitIConstraint.Constraint == null)
                    {
                        return(UnconstrainedMeasurementResult());
                    }

                    // makes sure that all qubits involved have the same constraint
                    if (qubitIConstraint.Constraint != qubit0Constraint.Constraint)
                    {
                        return(UnconstrainedMeasurementResult());
                    }

                    // makes sure that constrain's observable matches observable being measured
                    if (qubitIConstraint.QubitPauli != observablePr[i])
                    {
                        return(UnconstrainedMeasurementResult());
                    }
                }
            }

            // here we have ensured that all conditions we need to predict the measurement outcome are met
            MeasurementConstraint constraint = qubit0Constraint.Constraint;

            if (constraint.Type == MeasurementConstraint.ConstraintType.Force)
            {
                return(constraint.ConstrainToResult);
            }
            else if (constraint.Type == MeasurementConstraint.ConstraintType.Assert)
            {
                Double sample = randomGenerator.NextDouble();
                if (sample <= constraint.Probability)
                {
                    Debug.WriteLine($"Measurement outcome with probability {constraint.Probability} happened, result is {constraint.ConstrainToResult}");
                    return(constraint.ConstrainToResult);
                }
                else
                {
                    Debug.WriteLine($"Measurement outcome with probability {constraint.Probability} did not happen, result is {Utils.Opposite(constraint.ConstrainToResult)}");
                    return(Utils.Opposite(constraint.ConstrainToResult));
                }
            }
            Debug.Assert(false, "This point should not be reached.");
            return(UnconstrainedMeasurementResult());
        }
 private static object QubitConstraintInit(long id)
 {
     return(QubitConstraint.ZeroStateConstraint());
 }