Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions src/Simulation/Common/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
// Licensed under the MIT License.

using Microsoft.Quantum.Simulation.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Microsoft.Quantum.Simulation.Common
{
public class CommonUtils
public static class CommonUtils
{
/// <summary>
/// Removes PauliI terms from observable and corresponding qubits from qubits.
Expand All @@ -25,7 +27,7 @@ public static void PruneObservable(IQArray<Pauli> observable, IQArray<Qubit> qub
/// <summary>
/// Returns IEnumerable&lt;T&gt; that contains sub-sequence of <paramref name="sequenceToPrune"/>[i], such that <paramref name="sequence"/>[i] is not equal to <paramref name="value"/>.
/// </summary>
public static IEnumerable<T> PrunedSequence<U,T>(IQArray<U> sequence, U value, IQArray<T> sequenceToPrune )
public static IEnumerable<T> PrunedSequence<U,T>(IQArray<U> sequence, U value, IQArray<T> sequenceToPrune)
{
for (uint i = 0; i < sequence.Length; ++i)
{
Expand Down Expand Up @@ -63,5 +65,65 @@ public static (long, long) Reduce(long numerator, long denominatorPower)

return (numNew, denomPowerNew);
}

/// <summary>
/// Takes an array of doubles as
/// input, and returns a randomly-selected index into the array
/// as an `Int`. The probability of selecting a specific index
/// is proportional to the value of the array element at that index.
/// Array elements that are equal to zero are ignored and their indices
/// are never returned.If any array element is less than zero, or if
/// no array element is greater than zero, then the operation fails.
/// As a source of randomness uses a number uniformly distributed between 0 and 1.
/// Used for Quantum.Intrinsic.Random
/// </summary>
/// <param name="uniformZeroOneSample"> Number between Zero and one, uniformly distributed</param>
public static long SampleDistribution(IQArray<double> unnormalizedDistribution, double uniformZeroOneSample)
{
if (unnormalizedDistribution.Any(prob => prob < 0.0))
{
throw new ExecutionFailException("Random expects array of non-negative doubles.");
}

var total = unnormalizedDistribution.Sum();
if (total == 0)
{
throw new ExecutionFailException("Random expects array of non-negative doubles with positive sum.");
}

var sample = uniformZeroOneSample * total;

return unnormalizedDistribution
// Get the unnormalized CDF of the distribution.
.SelectAggregates((double acc, double x) => acc + x)
// Look for the first index at which the CDF is bigger
// than the random sample of 𝑈(0, 1) that we were given
// as a parameter.
.Select((cumulativeProb, idx) => (cumulativeProb, idx))
.Where(item => item.cumulativeProb >= sample)
// Cast that index to long, and default to returning
// the last item.
.Select(
item => (long)item.idx
)
.DefaultIfEmpty(
unnormalizedDistribution.Length - 1
)
.First();
}

internal static IEnumerable<TResult> SelectAggregates<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TResult, TSource, TResult> aggregate,
TResult initial = default
)
{
var acc = initial;
foreach (var element in source)
{
acc = aggregate(acc, element);
yield return acc;
}
}
}
}
14 changes: 0 additions & 14 deletions src/Simulation/Simulators/QCTraceSimulator/InterfaceUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,5 @@ public static partial class Extensions
{
return InterfaceType(t, typeof(IControllable<>));
}

internal static IEnumerable<TResult> SelectAggregates<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TResult, TSource, TResult> aggregate,
TResult initial = default
)
{
var acc = initial;
foreach (var element in source)
{
acc = aggregate(acc, element);
yield return acc;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
using System;

Expand All @@ -18,7 +19,7 @@ public TracerRandom(QCTraceSimulatorImpl m) : base(m)

public override Func<IQArray<double>, Int64> Body => (p) =>
{
return SimulatorsUtils.SampleDistribution(p, core.random.NextDouble());
return CommonUtils.SampleDistribution(p, core.random.NextDouble());
};
}
}
Expand Down
50 changes: 1 addition & 49 deletions src/Simulation/Simulators/QCTraceSimulator/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime;

Expand Down Expand Up @@ -199,53 +200,4 @@ public static class MetricsCountersNames
/// </summary>
public const string widthCounter = nameof(WidthCounter);
}

static class SimulatorsUtils
{
/// <summary>
/// Takes an array of doubles as
/// input, and returns a randomly-selected index into the array
/// as an `Int`. The probability of selecting a specific index
/// is proportional to the value of the array element at that index.
/// Array elements that are equal to zero are ignored and their indices
/// are never returned.If any array element is less than zero, or if
/// no array element is greater than zero, then the operation fails.
/// As a source of randomness uses a number uniformly distributed between 0 and 1.
/// Used for Quantum.Intrinsic.Random
/// </summary>
/// <param name="uniformZeroOneSample"> Number between Zero and one, uniformly distributed</param>
public static long SampleDistribution(IQArray<double> unnormalizedDistribution, double uniformZeroOneSample)
{
if (unnormalizedDistribution.Any(prob => prob < 0.0))
{
throw new ExecutionFailException("Random expects array of non-negative doubles.");
}

var total = unnormalizedDistribution.Sum();
if (total == 0)
{
throw new ExecutionFailException("Random expects array of non-negative doubles with positive sum.");
}

var sample = uniformZeroOneSample * total;

return unnormalizedDistribution
// Get the unnormalized CDF of the distribution.
.SelectAggregates((double acc, double x) => acc + x)
// Look for the first index at which the CDF is bigger
// than the random sample of 𝑈(0, 1) that we were given
// as a parameter.
.Select((cumulativeProb, idx) => (cumulativeProb, idx))
.Where(item => item.cumulativeProb >= sample)
// Cast that index to long, and default to returning
// the last item.
.Select(
item => (long)item.idx
)
.DefaultIfEmpty(
unnormalizedDistribution.Length - 1
)
.First();
}
}
}
34 changes: 3 additions & 31 deletions src/Simulation/Simulators/QuantumProcessor/random.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,13 @@

using Microsoft.Quantum.Simulation.Core;
using System;
using System.Linq;
using Microsoft.Quantum.Simulation.Common;

namespace Microsoft.Quantum.Simulation.QuantumProcessor
{
public partial class QuantumProcessorDispatcher
{
public static long SampleDistribution(IQArray<double> unnormalizedDistribution, double uniformZeroOneSample)
{
double total = 0.0;
foreach (double prob in unnormalizedDistribution)
{
if (prob < 0)
{
throw new ExecutionFailException("Random expects array of non-negative doubles.");
}
total += prob;
}

if (total == 0)
{
throw new ExecutionFailException("Random expects array of non-negative doubles with positive sum.");
}

double sample = uniformZeroOneSample * total;
double sum = unnormalizedDistribution[0];
for (int i = 0; i < unnormalizedDistribution.Length - 1; ++i)
{
if (sum >= sample)
{
return i;
}
sum += unnormalizedDistribution[i];
}
return unnormalizedDistribution.Length;
}

public class QuantumProcessorDispatcherRandom : Quantum.Intrinsic.Random
{
private QuantumProcessorDispatcher Simulator { get; }
Expand All @@ -48,7 +20,7 @@ public QuantumProcessorDispatcherRandom(QuantumProcessorDispatcher m) : base(m)

public override Func<IQArray<double>, Int64> Body => (p) =>
{
return SampleDistribution(p, Simulator.random.NextDouble());
return CommonUtils.SampleDistribution(p, Simulator.random.NextDouble());
};
}
}
Expand Down