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
6 changes: 3 additions & 3 deletions MachineLearning/src/Classification.qs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.Quantum.MachineLearning {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Convert;

internal operation _PrepareClassification(
internal operation PrepareClassification(
encoder : (LittleEndian => Unit is Adj + Ctl),
model : SequentialModel,
target : Qubit[]
Expand Down Expand Up @@ -48,8 +48,8 @@ namespace Microsoft.Quantum.MachineLearning {
: Double {
let encodedSample = ApproximateInputEncoder(tolerance / IntAsDouble(Length(model::Structure)), sample);
return 1.0 - EstimateFrequencyA(
_PrepareClassification(encodedSample::Prepare, model, _),
_TailMeasurement(encodedSample::NQubits),
PrepareClassification(encodedSample::Prepare, model, _),
TailMeasurement(encodedSample::NQubits),
encodedSample::NQubits,
nMeasurements
);
Expand Down
17 changes: 6 additions & 11 deletions MachineLearning/src/GradientEstimation.qs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,15 @@ namespace Microsoft.Quantum.MachineLearning {
open Microsoft.Quantum.Preparation;
open Microsoft.Quantum.Characterization;

// NOTE: the last qubit of 'reg' in this context is the auxiliary qubit used in the Hadamard test.
internal operation _ApplyLEOperationToRawRegister(op : (LittleEndian => Unit is Adj), target : Qubit[]) : Unit is Adj {
op(LittleEndian(target));
}

internal operation _EstimateDerivativeWithParameterShift(
internal operation EstimateDerivativeWithParameterShift(
inputEncoder : StateGenerator,
model : SequentialModel,
parameters : (Double[], Double[]),
nQubits : Int,
nMeasurements : Int
) : Double {
return EstimateRealOverlapBetweenStates(
_ApplyLEOperationToRawRegister(inputEncoder::Prepare, _),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should test to make sure that the library still works when used from IQ#, given microsoft/iqsharp#606.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most likely it won't, I ran into this when trying to update the Katas - even if the lambda is in the "backend" and not in the notebook itself, compilation fails

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this information. Maybe it makes sense to leave this open until microsoft/iqsharp#606 is resolved.

target => inputEncoder::Prepare(LittleEndian(target)),
ApplySequentialClassifier(model w/ Parameters <- Fst(parameters), _),
ApplySequentialClassifier(model w/ Parameters <- Snd(parameters), _),
nQubits, nMeasurements
Expand Down Expand Up @@ -71,7 +66,7 @@ namespace Microsoft.Quantum.MachineLearning {
// Now, suppose a gate at which we differentiate is the (Controlled R(\theta))([k0,k1,...,kr],[target])
// and we want a unitary description of its \theta-derivative. It can be written as
// 1/2 {(Controlled R(\theta'))([k0,k1,...,kr],[target]) - (Controlled Z)([k1,...,kr],[k0])(Controlled R(\theta'))([k0,k1,...,kr],[target])}
mutable grad = ConstantArray(Length(model::Parameters), 0.0);
mutable grad = [0.0, size = Length(model::Parameters)];
let nQubits = MaxI(NQubitsRequired(model), encodedInput::NQubits);

for gate in model::Structure {
Expand All @@ -80,10 +75,10 @@ namespace Microsoft.Quantum.MachineLearning {
w/ gate::ParameterIndex <- (model::Parameters[gate::ParameterIndex] + PI());

// NB: This the *antiderivative* of the bracket
let newDer = _EstimateDerivativeWithParameterShift(
let newDer = EstimateDerivativeWithParameterShift(
encodedInput, model, (model::Parameters, paramShift), nQubits, nMeasurements
);
if (IsEmpty(gate::ControlIndices)) {
if IsEmpty(gate::ControlIndices) {
//uncontrolled gate
set grad w/= gate::ParameterIndex <- grad[gate::ParameterIndex] + newDer;
} else {
Expand All @@ -92,7 +87,7 @@ namespace Microsoft.Quantum.MachineLearning {
w/ gate::ParameterIndex <- (model::Parameters[gate::ParameterIndex] + 3.0 * PI());
// Assumption: any rotation R has the property that R(\theta + 2 Pi) = (-1) R(\theta).
// NB: This the *antiderivative* of the bracket
let newDer1 = _EstimateDerivativeWithParameterShift(
let newDer1 = EstimateDerivativeWithParameterShift(
encodedInput, model, (model::Parameters, controlledShift), nQubits, nMeasurements
);
set grad w/= gate::ParameterIndex <- (grad[gate::ParameterIndex] + 0.5 * (newDer - newDer1));
Expand Down
34 changes: 17 additions & 17 deletions MachineLearning/src/InputEncoding.qs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ namespace Microsoft.Quantum.MachineLearning {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;

internal function _CanApplyTwoQubitCase(datum: Double[]) : Bool {
return((Length(datum)==4) and (Microsoft.Quantum.Math.AbsD(datum[0]*datum[3]-datum[1]*datum[2])< 1E-12) and (Microsoft.Quantum.Math.AbsD(datum[0])> 1E-4));
internal function CanApplyTwoQubitCase(datum: Double[]) : Bool {
return ((Length(datum)==4) and (Microsoft.Quantum.Math.AbsD(datum[0]*datum[3]-datum[1]*datum[2])< 1E-12) and (Microsoft.Quantum.Math.AbsD(datum[0])> 1E-4));
}

internal operation _ApplyTwoQubitCase(datum: Double[], reg: LittleEndian) : Unit is Adj + Ctl {
internal operation ApplyTwoQubitCase(datum: Double[], reg: LittleEndian) : Unit is Adj + Ctl {
let x = datum[1]/datum[0];
let y = datum[2]/datum[0];
// we now encoding [1,x,y,x*y]
Expand All @@ -24,7 +24,7 @@ namespace Microsoft.Quantum.MachineLearning {
R(PauliY, ax, (reg!)[0]);
}

internal function _Unnegate(negLocs: Int[], coefficients : ComplexPolar[]) : ComplexPolar[] {
internal function Unnegate(negLocs: Int[], coefficients : ComplexPolar[]) : ComplexPolar[] {
mutable ret = coefficients;
for idxNegative in negLocs {
if idxNegative >= Length(coefficients) {
Expand All @@ -36,18 +36,18 @@ namespace Microsoft.Quantum.MachineLearning {
return ret;
}

internal function _NegativeLocations(cNegative: Int, coefficients : ComplexPolar[]) : Int[] {
internal function NegativeLocations(cNegative: Int, coefficients : ComplexPolar[]) : Int[] {
mutable negLocs = [];
for (idx, coefficient) in Enumerated(coefficients) {
if (AbsD(coefficient::Argument - PI()) < 1E-9) {
if AbsD(coefficient::Argument - PI()) < 1E-9 {
set negLocs += [idx];
}
}
return Length(negLocs) > cNegative ? negLocs[...cNegative - 1] | negLocs;
}

/// Do special processing on the first cNegative entries
internal operation _ReflectAboutNegativeCoefficients(
internal operation ReflectAboutNegativeCoefficients(
negLocs : Int[],
coefficients : ComplexPolar[],
reg: LittleEndian
Expand Down Expand Up @@ -96,11 +96,11 @@ namespace Microsoft.Quantum.MachineLearning {
mutable cNegative = 0;
for (idx, coef) in Enumerated(coefficients) {
mutable magnitude = coef;
if (tolerance > 1E-9) {
if tolerance > 1E-9 {
set magnitude = tolerance * IntAsDouble(Round(coefficients[idx] / tolerance)); //quantization
}
mutable ang = 0.0;
if (magnitude < 0.0) {
if magnitude < 0.0 {
set cNegative += 1;
set magnitude = -magnitude;
set ang = PI();
Expand All @@ -109,8 +109,8 @@ namespace Microsoft.Quantum.MachineLearning {
}

// Check if we can apply the explicit two-qubit case.
if (_CanApplyTwoQubitCase(coefficients)) {
return StateGenerator(2, _ApplyTwoQubitCase(coefficients, _));
if CanApplyTwoQubitCase(coefficients) {
return StateGenerator(2, ApplyTwoQubitCase(coefficients, _));
}

let nQubits = FeatureRegisterSize(coefficients);
Expand All @@ -119,18 +119,18 @@ namespace Microsoft.Quantum.MachineLearning {
// there are only a few negative coefficients.
// Here, by a "few," we mean fewer than the number of qubits required
// to encode features.
if ((cNegative > 0) and (IntAsDouble(cNegative) < Lg(IntAsDouble(Length(coefficients))) + 1.0)) {
let negLocs = _NegativeLocations(cNegative, complexCoefficients);
if (cNegative > 0) and (IntAsDouble(cNegative) < Lg(IntAsDouble(Length(coefficients))) + 1.0) {
let negLocs = NegativeLocations(cNegative, complexCoefficients);
return StateGenerator(
nQubits,
BoundCA([
// Prepare the state disregarding the sign of negative components.
_CompileApproximateArbitraryStatePreparation(
tolerance, _Unnegate(negLocs, complexCoefficients), nQubits
tolerance, Unnegate(negLocs, complexCoefficients), nQubits
),
// Reflect about the negative coefficients to apply the negative signs
// at the end.
_ReflectAboutNegativeCoefficients(negLocs, complexCoefficients, _)
ReflectAboutNegativeCoefficients(negLocs, complexCoefficients, _)
])
);
}
Expand Down Expand Up @@ -165,8 +165,8 @@ namespace Microsoft.Quantum.MachineLearning {
| (-coefficient, PI())
);
}
if (_CanApplyTwoQubitCase(coefficients)) {
return StateGenerator(2, _ApplyTwoQubitCase(coefficients, _));
if CanApplyTwoQubitCase(coefficients) {
return StateGenerator(2, ApplyTwoQubitCase(coefficients, _));
}
//this is preparing the state almost exactly so far
return StateGenerator(
Expand Down
6 changes: 3 additions & 3 deletions MachineLearning/src/Private.qs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace Microsoft.Quantum.MachineLearning {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Math;

internal function _AllNearlyEqualD(v1 : Double[], v2 : Double[]) : Bool {
internal function AllNearlyEqualD(v1 : Double[], v2 : Double[]) : Bool {
return Length(v1) == Length(v2) and All(NearlyEqualD, Zipped(v1, v2));
}

internal function _TailMeasurement(nQubits : Int) : (Qubit[] => Result) {
let paulis = ConstantArray(nQubits, PauliI) w/ (nQubits - 1) <- PauliZ;
internal function TailMeasurement(nQubits : Int) : (Qubit[] => Result) {
let paulis = [PauliI, size = nQubits] w/ (nQubits - 1) <- PauliZ;
return Measure(paulis, _);
}

Expand Down
27 changes: 7 additions & 20 deletions MachineLearning/src/Structure.qs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace Microsoft.Quantum.MachineLearning {
model : SequentialModel,
qubits : Qubit[]
)
: (Unit) is Adj + Ctl {
: Unit is Adj + Ctl {
for gate in model::Structure {
if gate::ParameterIndex < Length(model::Parameters) {
let input = (gate::Axis, model::Parameters[gate::ParameterIndex], qubits[gate::TargetIndex]);
Expand All @@ -58,26 +58,13 @@ namespace Microsoft.Quantum.MachineLearning {
}
}

function _UncontrolledSpanSequence(idxsQubits : Int[]) : (Int, Int[])[] {
internal function UncontrolledSpanSequence(idxsQubits : Int[]) : (Int, Int[])[] {
return Zipped(
idxsQubits,
ConstantArray(Length(idxsQubits), [])
[[], size = Length(idxsQubits)]
);
}

function _CallFlipped<'TInput1, 'TInput2, 'TOutput>(
fn : (('TInput1, 'TInput2) -> 'TOutput),
y : 'TInput2, x : 'TInput1
) : 'TOutput {
return fn(x, y);
}

function _Flipped<'TInput1, 'TInput2, 'TOutput>(
fn : (('TInput1, 'TInput2) -> 'TOutput)
) : (('TInput2, 'TInput1) -> 'TOutput) {
return _CallFlipped(fn, _, _);
}

/// # Summary
/// Returns an array of uncontrolled (single-qubit) rotations along a given
/// axis, with one rotation for each qubit in a register, parameterized by
Expand All @@ -95,9 +82,9 @@ namespace Microsoft.Quantum.MachineLearning {
function LocalRotationsLayer(nQubits : Int, axis : Pauli) : ControlledRotation[] {
// [parameterIndex, pauliCode, targetQubit\,sequence of control qubits\]
return Mapped(
_Flipped(ControlledRotation(_, axis, _)),
(idx, seq) -> ControlledRotation(seq, axis, idx),
Enumerated(
_UncontrolledSpanSequence(SequenceI(0, nQubits - 1))
UncontrolledSpanSequence(SequenceI(0, nQubits - 1))
)
);
}
Expand All @@ -118,9 +105,9 @@ namespace Microsoft.Quantum.MachineLearning {
/// `nQubits` qubits.
function PartialRotationsLayer(idxsQubits : Int[], axis : Pauli) : ControlledRotation[] {
return Mapped(
_Flipped(ControlledRotation(_, axis, _)),
(idx, seq) -> ControlledRotation(seq, axis, idx),
Enumerated(
_UncontrolledSpanSequence(idxsQubits)
UncontrolledSpanSequence(idxsQubits)
)
);
}
Expand Down
34 changes: 17 additions & 17 deletions MachineLearning/src/Training.qs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ namespace Microsoft.Quantum.MachineLearning {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Optimization;

internal function _MisclassificationRate(probabilities : Double[], labels : Int[], bias : Double) : Double {
internal function MisclassificationRate(probabilities : Double[], labels : Int[], bias : Double) : Double {
let proposedLabels = InferredLabels(bias, probabilities);
return IntAsDouble(NMisclassifications(proposedLabels, labels)) / IntAsDouble(Length(probabilities));
}

/// # Summary
/// Returns a bias value that leads to near-minimum misclassification score.
internal function _UpdatedBias(labeledProbabilities: (Double, Int)[], bias: Double, tolerance: Double) : Double {
internal function UpdatedBias(labeledProbabilities: (Double, Int)[], bias: Double, tolerance: Double) : Double {
mutable (min1, max0) = (1.0, 0.0);

// Find the range of classification probabilities for each class.
Expand All @@ -42,7 +42,7 @@ namespace Microsoft.Quantum.MachineLearning {
// If we can't find a perfect classification, minimize to find
// the best feasible bias.
let optimum = LocalUnivariateMinimum(
_MisclassificationRate(Mapped(Fst, labeledProbabilities), Mapped(Snd, labeledProbabilities), _),
MisclassificationRate(Mapped(Fst, labeledProbabilities), Mapped(Snd, labeledProbabilities), _),
(0.5 - max0, 0.5 - min1),
tolerance
);
Expand Down Expand Up @@ -122,13 +122,13 @@ namespace Microsoft.Quantum.MachineLearning {
///
/// # Output
/// (utility, (new)parameters) pair
internal operation _RunSingleTrainingStep(
internal operation RunSingleTrainingStep(
miniBatch : (LabeledSample, StateGenerator)[],
options : TrainingOptions,
model : SequentialModel
)
: (Double, SequentialModel) {
mutable batchGradient = ConstantArray(Length(model::Parameters), 0.0);
mutable batchGradient = [0.0, size = Length(model::Parameters)];

for (idxSample, (sample, stateGenerator)) in Enumerated(miniBatch) {
mutable err = IntAsDouble(sample::Label);
Expand Down Expand Up @@ -179,7 +179,7 @@ namespace Microsoft.Quantum.MachineLearning {
/// - The smallest number of misclassifications observed through to this
/// epoch.
/// - The new best sequential model found.
internal operation _RunSingleTrainingEpoch(
internal operation RunSingleTrainingEpoch(
encodedSamples : (LabeledSample, StateGenerator)[],
schedule : SamplingSchedule, periodScore: Int,
options : TrainingOptions,
Expand Down Expand Up @@ -212,7 +212,7 @@ namespace Microsoft.Quantum.MachineLearning {
);
for (idxMinibatch, minibatch) in Enumerated(minibatches) {
options::VerboseMessage($" Beginning minibatch {idxMinibatch} of {Length(minibatches)}.");
let (utility, updatedModel) = _RunSingleTrainingStep(
let (utility, updatedModel) = RunSingleTrainingStep(
minibatch, options, bestSoFar
);
if utility > 1e-7 {
Expand All @@ -224,7 +224,7 @@ namespace Microsoft.Quantum.MachineLearning {
options::Tolerance, updatedModel,
features, options::NMeasurements
);
let updatedBias = _UpdatedBias(
let updatedBias = UpdatedBias(
Zipped(probabilities, actualLabels), model::Bias, options::Tolerance
);
let updatedLabels = InferredLabels(
Expand All @@ -246,13 +246,13 @@ namespace Microsoft.Quantum.MachineLearning {

/// # Summary
/// Randomly rescales an input to either grow or shrink by a given factor.
internal operation _RandomlyRescale(scale : Double, value : Double) : Double {
internal operation RandomlyRescale(scale : Double, value : Double) : Double {
return value * (
1.0 + scale * (DrawRandomBool(0.5) ? 1.0 | -1.0)
);
}

internal function _EncodeSample(effectiveTolerance : Double, nQubits : Int, sample : LabeledSample)
internal function EncodeSample(effectiveTolerance : Double, nQubits : Int, sample : LabeledSample)
: (LabeledSample, StateGenerator) {
return (
sample,
Expand Down Expand Up @@ -313,7 +313,7 @@ namespace Microsoft.Quantum.MachineLearning {
options::NMeasurements
);
// Find the best bias for the new classification parameters.
let localBias = _UpdatedBias(
let localBias = UpdatedBias(
Zipped(probabilities, Sampled(validationSchedule, labels)),
0.0,
options::Tolerance
Expand Down Expand Up @@ -342,7 +342,7 @@ namespace Microsoft.Quantum.MachineLearning {
features, options::NMeasurements
);
mutable bestSoFar = model
w/ Bias <- _UpdatedBias(
w/ Bias <- UpdatedBias(
Zipped(probabilities, actualLabels),
model::Bias, options::Tolerance
);
Expand All @@ -358,7 +358,7 @@ namespace Microsoft.Quantum.MachineLearning {
options::VerboseMessage(" Pre-encoding samples...");
let effectiveTolerance = options::Tolerance / IntAsDouble(Length(model::Structure));
let nQubits = MaxI(FeatureRegisterSize(samples[0]::Features), NQubitsRequired(model));
let encodedSamples = Mapped(_EncodeSample(effectiveTolerance, nQubits, _), samples);
let encodedSamples = Mapped(EncodeSample(effectiveTolerance, nQubits, _), samples);

//reintroducing learning rate heuristics
mutable lrate = options::LearningRate;
Expand All @@ -369,7 +369,7 @@ namespace Microsoft.Quantum.MachineLearning {

for ep in 1..options::MaxEpochs {
options::VerboseMessage($" Beginning epoch {ep}.");
let (nMisses, proposedUpdate) = _RunSingleTrainingEpoch(
let (nMisses, proposedUpdate) = RunSingleTrainingEpoch(
encodedSamples, schedule, options::ScoringPeriod,
options w/ LearningRate <- lrate
w/ MinibatchSize <- batchSize,
Expand All @@ -389,7 +389,7 @@ namespace Microsoft.Quantum.MachineLearning {

if
NearlyEqualD(current::Bias, proposedUpdate::Bias) and
_AllNearlyEqualD(current::Parameters, proposedUpdate::Parameters)
AllNearlyEqualD(current::Parameters, proposedUpdate::Parameters)
{
set nStalls += 1;
// If we're more than halfway through our maximum allowed number of stalls,
Expand All @@ -408,8 +408,8 @@ namespace Microsoft.Quantum.MachineLearning {
if nStalls > options::MaxStalls / 2 {
set current = SequentialModel(
model::Structure,
ForEach(_RandomlyRescale(options::StochasticRescaleFactor, _), proposedUpdate::Parameters),
_RandomlyRescale(options::StochasticRescaleFactor, proposedUpdate::Bias)
ForEach(RandomlyRescale(options::StochasticRescaleFactor, _), proposedUpdate::Parameters),
RandomlyRescale(options::StochasticRescaleFactor, proposedUpdate::Bias)
);
}
} else {
Expand Down
Loading