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
Show all changes
27 commits
Select commit Hold shift + click to select a range
4de89e2
Add tests for default values
Oct 15, 2020
e11cd52
Add tests for default tuples and UDTs
Oct 15, 2020
5cc10cf
Add test for default Unit
Oct 15, 2020
44a8794
Add special-case defaults for a few types
Oct 16, 2020
1bd7b2c
Basic handling for defaults of tuples and UDTs
Oct 16, 2020
bfc3c14
Add defaults for all value tuples
Oct 16, 2020
10565e3
Refactor tuple defaults
Oct 16, 2020
392b081
Factor out different default types
Oct 16, 2020
ebc036e
Update namespace
Oct 16, 2020
4e99d93
Update default value in UDT constructor
Oct 16, 2020
3153fda
Add test for UDT inside tuple
Oct 16, 2020
5eefcb0
Fix range default
Oct 16, 2020
9e60afb
Rename QDefault to Default
Oct 16, 2020
0d3b8b9
Default to null instead of throwing
Oct 16, 2020
6463656
Fix nullable warning
Oct 16, 2020
b01922b
Assert default qubit and callable are null
Oct 16, 2020
d4d22ab
Add doc comments
Oct 16, 2020
afb47a1
Fix C# generation tests
Oct 17, 2020
9e835c8
Fix tuple tests
Oct 17, 2020
6d34172
Merge branch 'main' into samarsha/default-values
bettinaheim Oct 20, 2020
4458809
More efficient array initialization
Oct 20, 2020
e78bbad
Merge branch 'main' into samarsha/default-values
bettinaheim Oct 21, 2020
ecb54db
Merge branch 'main' into samarsha/default-values
bettinaheim Oct 21, 2020
e35488e
Merge branch 'main' into samarsha/default-values
bettinaheim Oct 21, 2020
5e965b5
Merge branch 'main' into samarsha/default-values
bettinaheim Oct 21, 2020
0a13107
Merge branch 'main' into samarsha/default-values
bamarsha Oct 27, 2020
66bdd82
Merge branch 'main' into samarsha/default-values
bamarsha Oct 28, 2020
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
92 changes: 92 additions & 0 deletions src/Simulation/Core/Default.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#nullable enable

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace Microsoft.Quantum.Simulation.Core
{
/// <summary>
/// Creates default values of Q# types.
/// </summary>
public static class Default
{
/// <summary>
/// A dictionary from basic types to their default values.
/// </summary>
private static readonly IReadOnlyDictionary<Type, object> BasicValues = new Dictionary<Type, object>
{
[typeof(QRange)] = QRange.Empty,
[typeof(QVoid)] = QVoid.Instance,
[typeof(Result)] = Result.Zero,
[typeof(string)] = ""
};

/// <summary>
/// A list of all generic tuple types.
/// </summary>
private static readonly IReadOnlyList<Type> Tuples = new List<Type>
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>)
};

/// <summary>
/// Returns the default value of the Q# type. May return null when null is the default value of the type, or if
/// the type is not a valid Q# type.
/// </summary>
[return: MaybeNull]
public static T OfType<T>() => OfType(typeof(T)) is T value ? value : default;

/// <summary>
/// Returns the default value of the Q# type. May return null when null is the default value of the type, or if
/// the type is not a valid Q# type.
/// </summary>
private static object? OfType(Type type) => OfAnyType(type).FirstOrDefault(value => !(value is null));

/// <summary>
/// Enumerates the default values of different kinds of types. Yields null if the given type is not the right
/// kind, and yields a non-null value if a default value is found.
/// </summary>
private static IEnumerable<object?> OfAnyType(Type type)
{
yield return BasicValues.GetValueOrDefault(type);
yield return OfArrayType(type);
yield return OfTupleType(type);
yield return OfUserDefinedType(type);
}

/// <summary>
/// If the given type is a Q# array type, returns the default array of that type, or null otherwise.
/// </summary>
private static object? OfArrayType(Type type) =>
type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IQArray<>)
? Activator.CreateInstance(typeof(QArray<>).MakeGenericType(type.GenericTypeArguments))
: null;

/// <summary>
/// If the given type is a Q# tuple type, returns the default tuple of that type, or null otherwise.
/// </summary>
private static object? OfTupleType(Type type) =>
type.IsGenericType && Tuples.Contains(type.GetGenericTypeDefinition())
? Activator.CreateInstance(type, type.GenericTypeArguments.Select(OfType).ToArray())
: null;

/// <summary>
/// If the given type is a Q# user-defined type, returns the default value of that type, or null otherwise.
/// </summary>
private static object? OfUserDefinedType(Type type) =>
!(type.BaseType is null)
&& type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == typeof(UDTBase<>)
? Activator.CreateInstance(type, type.BaseType.GenericTypeArguments.Select(OfType).ToArray())
: null;
}
}
48 changes: 10 additions & 38 deletions src/Simulation/Core/QArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;

namespace Microsoft.Quantum.Simulation.Core
Expand Down Expand Up @@ -98,17 +97,10 @@ public QArrayInner(params T[] collection)
}

/// <summary>
/// Creates an array of size given by capacity and default-initializes
/// array elements. Uses C# keyword <code>default</code> to initialize array elements.
/// Creates an array of size given by capacity and default-initializes array elements. Uses the default Q#
/// value to initialize array elements.
/// </summary>
public QArrayInner(long capacity)
{
storage = new List<T>((int)capacity);
for (var i = 0L; i < capacity; ++i)
{
storage.Add(CreateDefault());
}
}
public QArrayInner(long capacity) => Extend(capacity);

public T GetElement(long index) =>
storage == null
Expand Down Expand Up @@ -143,20 +135,19 @@ public void UnsafeSetElement(long index, T value)

public void Extend(long newLength)
{
if (storage == null)
var newLengthInt = Convert.ToInt32(newLength);
if (storage is null)
{
storage = new List<T>();
storage = new List<T>(newLengthInt);
}
long oldLength = storage.Count;
for (int i = 0; i < (newLength - oldLength); i++)
else if (storage.Capacity < newLengthInt)
{
T obj = CreateDefault();
storage.Add(obj);
storage.Capacity = newLengthInt;
}
storage.AddRange(Enumerable.Repeat(Default.OfType<T>(), newLengthInt - storage.Count));
}
}


private QArrayInner storage;
private long start = 0;
private long step = 1;
Expand All @@ -174,25 +165,6 @@ private void CopyAndCompress()
step = 1;
}

// Returns the default value of an object of this type of array. Normally null or 0, but for things like
// ValueTuples, it returns an empty instance of that value tuple.
private static T CreateDefault()
{
if (typeof(T).IsValueType || typeof(T).IsAbstract || typeof(T) == typeof(String) || typeof(T) == typeof(QVoid))
{
return default(T);
}
else
{
// First look for an empty constructor
ConstructorInfo defaultConstructor = typeof(T).GetConstructor(Type.EmptyTypes);
return defaultConstructor != null
? (T)(defaultConstructor.Invoke(new object[] { }))
: Activator.CreateInstance<T>();
}
}


/// <summary>
/// Create an array of length 0.
/// </summary>
Expand Down Expand Up @@ -508,7 +480,7 @@ public QArrayEnumerator(QArray<T> qArray)
currentIndex = -1;
}

public T Current => currentIndex >= 0 ? array[currentIndex] : CreateDefault();
public T Current => currentIndex >= 0 ? array[currentIndex] : Default.OfType<T>();

object IEnumerator.Current => this.Current;

Expand Down
5 changes: 2 additions & 3 deletions src/Simulation/Core/QRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Microsoft.Quantum.Simulation.Core
/// </summary>
public class QRange : IEnumerable<long>
{
public QRange() : this(0, 1, 0)
public QRange() : this(1, 1, 0)
{
}

Expand Down Expand Up @@ -61,8 +61,7 @@ public QRange(long start, long end) : this(start, 1, end)
/// <summary>
/// Returns an empty range.
/// </summary>
public static QRange Empty =>
new QRange(0L, -1L);
public static QRange Empty => new QRange();

/// <summary>
/// Returns true if the range is empty.
Expand Down
34 changes: 17 additions & 17 deletions src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2924,7 +2924,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class U : UDTBase<IUnitary>, IApplyData
{
public U() : base(default(IUnitary))
public U() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<IUnitary>())
{
}

Expand All @@ -2950,7 +2950,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class AA : UDTBase<A>, IApplyData
{
public AA() : base(default(A))
public AA() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<A>())
{
}

Expand All @@ -2976,7 +2976,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class Q : UDTBase<Qubit>, IApplyData
{
public Q() : base(default(Qubit))
public Q() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<Qubit>())
{
}

Expand All @@ -3002,7 +3002,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class QQ : UDTBase<Q>, IApplyData
{
public QQ() : base(default(Q))
public QQ() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<Q>())
{
}

Expand All @@ -3028,7 +3028,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class Qubits : UDTBase<IQArray<Qubit>>, IApplyData
{
public Qubits() : base(new QArray<Qubit>())
public Qubits() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<IQArray<Qubit>>())
{
}

Expand All @@ -3054,7 +3054,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class udt_args1 : UDTBase<(Int64,IQArray<Qubit>)>, IApplyData
{
public udt_args1() : base(default((Int64,IQArray<Qubit>)))
public udt_args1() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<(Int64,IQArray<Qubit>)>())
{
}

Expand Down Expand Up @@ -3084,7 +3084,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class udt_Real : UDTBase<Double>, IApplyData
{
public udt_Real() : base(default(Double))
public udt_Real() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<Double>())
{
}

Expand All @@ -3104,7 +3104,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class udt_Complex : UDTBase<(udt_Real,udt_Real)>, IApplyData
{
public udt_Complex() : base(default((udt_Real,udt_Real)))
public udt_Complex() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<(udt_Real,udt_Real)>())
{
}

Expand All @@ -3127,7 +3127,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
public class udt_TwoDimArray : UDTBase<IQArray<IQArray<Result>>>, IApplyData
{
public udt_TwoDimArray() : base(new QArray<IQArray<Result>>())
public udt_TwoDimArray() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<IQArray<IQArray<Result>>>())
{
}

Expand All @@ -3149,7 +3149,7 @@ internal partial class EmptyInternalOperation : Operation<QVoid, QVoid>, ICallab
"""
internal class InternalType : UDTBase<QVoid>, IApplyData
{
public InternalType() : base(default(QVoid))
public InternalType() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<QVoid>())
{
}

Expand All @@ -3171,7 +3171,7 @@ internal class InternalType : UDTBase<QVoid>, IApplyData
"""
public class NamedTuple : UDTBase<((Int64,Double),Int64)>, IApplyData
{
public NamedTuple() : base(default(((Int64,Double),Int64)))
public NamedTuple() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<((Int64,Double),Int64)>())
{
}

Expand Down Expand Up @@ -3231,7 +3231,7 @@ namespace Microsoft.Quantum
{
public class Pair : UDTBase<(Int64,Int64)>, IApplyData
{
public Pair() : base(default((Int64,Int64)))
public Pair() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<(Int64,Int64)>())
{
}

Expand All @@ -3251,7 +3251,7 @@ namespace Microsoft.Quantum

public class Unused : UDTBase<(Int64,Int64)>, IApplyData
{
public Unused() : base(default((Int64,Int64)))
public Unused() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<(Int64,Int64)>())
{
}

Expand Down Expand Up @@ -3337,7 +3337,7 @@ namespace Microsoft.Quantum
{
public class Pair : UDTBase<(Int64,Int64)>, IApplyData
{
public Pair() : base(default((Int64,Int64)))
public Pair() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<(Int64,Int64)>())
{
}

Expand All @@ -3361,7 +3361,7 @@ namespace Microsoft.Quantum

public class NestedPair : UDTBase<(Double,((Boolean,String),Int64))>, IApplyData
{
public NestedPair() : base(default((Double,((Boolean,String),Int64))))
public NestedPair() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<(Double,((Boolean,String),Int64))>())
{
}

Expand Down Expand Up @@ -3616,7 +3616,7 @@ namespace Microsoft.Quantum.Core
{
public class Attribute : UDTBase<QVoid>, IApplyData
{
public Attribute() : base(default(QVoid))
public Attribute() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<QVoid>())
{
}

Expand All @@ -3636,7 +3636,7 @@ namespace Microsoft.Quantum.Diagnostics
{
public class Test : UDTBase<String>, IApplyData
{
public Test() : base(default(String))
public Test() : base(global::Microsoft.Quantum.Simulation.Core.Default.OfType<String>())
{
}

Expand Down
17 changes: 7 additions & 10 deletions src/Simulation/CsharpGeneration/SimulationCode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1461,15 +1461,12 @@ module SimulationCode =
let context = globalContext.setUdt udt
let name = userDefinedName None udt.FullName.Name.Value
let qsharpType = udt.Type
let buildEmtpyConstructor =
let baseTupleType =
match qsharpType.Resolution with
| ArrayType b -> roslynTypeName context b |> sprintf "QArray<%s>"
| _ -> (roslynTypeName context qsharpType)
let defaultValue = match qsharpType.Resolution with | ArrayType _ -> [ sprintf "new %s()" baseTupleType] | _ -> [ sprintf "default(%s)" baseTupleType ]
let args = []
``constructor`` name ``(`` args ``)``
``:`` defaultValue
let buildEmptyConstructor =
let defaultValue =
roslynTypeName context qsharpType
|> sprintf "global::Microsoft.Quantum.Simulation.Core.Default.OfType<%s>()"
``constructor`` name ``(`` [] ``)``
``:`` [ defaultValue ]
[ ``public`` ]
``{``
[]
Expand Down Expand Up @@ -1540,7 +1537,7 @@ module SimulationCode =
let baseClass = ``simpleBase`` baseClassName
let modifiers = [ classAccessModifier udt.Modifiers.Access ]
let interfaces = [ ``simpleBase`` "IApplyData" ]
let constructors = [ buildEmtpyConstructor; buildBaseTupleConstructor ]
let constructors = [ buildEmptyConstructor; buildBaseTupleConstructor ]
let qubitsField = buildQubitsField context qsharpType
let itemFields = buildNamedItemFields @ buildItemFields
let allFields = itemFields @ qubitsField
Expand Down
Loading