diff --git a/.gitignore b/.gitignore index d23c8bcc645..754c9b65976 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,9 @@ bld/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ +# Visual Studio Code cache/options directory +.vscode/ + # Visual Studio Code Ionide-FSharp extension cache directory .ionide/ diff --git a/README.md b/README.md index eab23b86ae4..d20ed0093ae 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,10 @@ To build on Windows: * Install [CMake](https://cmake.org/install/) * Install [Visual Studio 2019 (version 16.3 or later)](https://visualstudio.microsoft.com/downloads/). Make sure you install the following workloads: * **Desktop development with C++** + * **From the Individual Components tab in VS Installer add Spectre-mitigated libs that match your C++ build tools version** * **.NET Core 3 cross-platform development** 2. Run [bootstrap.cmd](bootstrap.cmd) from the `Developer Command Prompt for VS 2019`. + * pre-req (in PowerShell): `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` * This script prepares and builds the native (C++) full-state simulator. * You only need to run it once. 3. Open and build the [`Simulation.sln`](./Simulation.sln) solution in Visual Studio. @@ -57,7 +59,7 @@ To build on other platforms: 2. Run [bootstrap.sh](./bootstrap.sh) * This script prepares and builds the native (C++) full-state simulator. * You only need to run it once. -3. From the command line, run these two commands: +3. From the command line, run: * `dotnet build Simulation.sln` The `Simulation.sln` solution does not include the full-state simulator. To integrate any changes with the rest of the simulation components, you need to manually build it using `make` in the `src\Simulation\Native\build` folder. @@ -70,7 +72,7 @@ All unit tests are part of the `Simulation.sln` solution. To run the tests: * From [Visual Studio](https://docs.microsoft.com/en-us/visualstudio/test/getting-started-with-unit-testing?view=vs-2019#run-unit-tests): * Open Test Explorer by choosing Test > Windows > Test Explorer from the top menu bar. * Run your unit tests by clicking Run All. -* From the command line run: +* From the command line, run: * `dotnet test Simulation.sln` diff --git a/Simulation.sln b/Simulation.sln index 7886189c882..bfe0e7c6315 100644 --- a/Simulation.sln +++ b/Simulation.sln @@ -3,14 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28809.33 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99E234BC-997E-4E63-9F5C-3C3977543404}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure", "Azure", "{A1E878CB-ADF1-457A-9223-06F96ED8F7A6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Quantum.Client", "src\Azure\Azure.Quantum.Client\Microsoft.Azure.Quantum.Client.csproj", "{DF654202-0008-4CDE-B35E-018CEFD0FC68}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Quantum.Client.Test", "src\Azure\Azure.Quantum.Client.Test\Microsoft.Azure.Quantum.Client.Test.csproj", "{1467128C-90E4-4723-B5C7-9469B83F54A6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Runtime.Core", "src\Simulation\Core\Microsoft.Quantum.Runtime.Core.csproj", "{E9123D45-C1B0-4462-8810-D26ED6D31944}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime", "src\Simulation\QCTraceSimulator\Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj", "{058CB08D-BFA7-41E2-BE6B-0A0A72054F91}" @@ -47,15 +39,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestProjects", "TestProject EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QsharpExe", "src\Simulation\Simulators.Tests\TestProjects\QsharpExe\QsharpExe.csproj", "{2F5796A7-4AF8-4B78-928A-0A3A80752F9D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Quantum.EntryPointDriver", "src\Simulation\EntryPointDriver\Microsoft.Quantum.EntryPointDriver.csproj", "{944FE7EF-9220-4CC6-BB20-CE517195B922}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.EntryPointDriver", "src\Simulation\EntryPointDriver\Microsoft.Quantum.EntryPointDriver.csproj", "{944FE7EF-9220-4CC6-BB20-CE517195B922}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Tests.Microsoft.Quantum.EntryPointDriver", "src\Simulation\EntryPointDriver.Tests\Tests.Microsoft.Quantum.EntryPointDriver.fsproj", "{E2F30496-19D8-46A8-9BC0-26936FFE70D2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library1", "src\Simulation\Simulators.Tests\TestProjects\Library1\Library1.csproj", "{7256B986-6705-42FC-9F57-485D72D9DE51}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library2", "src\Simulation\Simulators.Tests\TestProjects\Library2\Library2.csproj", "{A85277B3-4E07-4E15-8F0C-07CC855A3BCB}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests.Microsoft.Quantum.EntryPointDriver", "src\Simulation\EntryPointDriver.Tests\Tests.Microsoft.Quantum.EntryPointDriver.fsproj", "{E2F30496-19D8-46A8-9BC0-26936FFE70D2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "src\Simulation\Simulators.Tests\TestProjects\UnitTests\UnitTests.csproj", "{46278108-D247-4EFC-AC34-23D4A676F62F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library1", "src\Simulation\Simulators.Tests\TestProjects\Library1\Library1.csproj", "{7256B986-6705-42FC-9F57-485D72D9DE51}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure", "Azure", "{37CDC768-16D4-4574-8553-07D99D0A72F7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library2", "src\Simulation\Simulators.Tests\TestProjects\Library2\Library2.csproj", "{A85277B3-4E07-4E15-8F0C-07CC855A3BCB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Quantum.Client", "src\Azure\Azure.Quantum.Client\Microsoft.Azure.Quantum.Client.csproj", "{7F05FD87-A2FB-4915-A988-4EF92AB82179}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "src\Simulation\Simulators.Tests\TestProjects\UnitTests\UnitTests.csproj", "{46278108-D247-4EFC-AC34-23D4A676F62F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Quantum.Client.Test", "src\Azure\Azure.Quantum.Client.Test\Microsoft.Azure.Quantum.Client.Test.csproj", "{4858E5E3-23FA-4928-B99A-54065875A2B9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -69,38 +67,6 @@ Global RelWithDebInfo|x64 = RelWithDebInfo|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Debug|x64.ActiveCfg = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Debug|x64.Build.0 = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.MinSizeRel|x64.Build.0 = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Release|Any CPU.Build.0 = Release|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Release|x64.ActiveCfg = Release|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.Release|x64.Build.0 = Release|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU - {DF654202-0008-4CDE-B35E-018CEFD0FC68}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Debug|x64.ActiveCfg = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Debug|x64.Build.0 = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.MinSizeRel|x64.Build.0 = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Release|Any CPU.Build.0 = Release|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Release|x64.ActiveCfg = Release|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.Release|x64.Build.0 = Release|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU - {1467128C-90E4-4723-B5C7-9469B83F54A6}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU {E9123D45-C1B0-4462-8810-D26ED6D31944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E9123D45-C1B0-4462-8810-D26ED6D31944}.Debug|Any CPU.Build.0 = Debug|Any CPU {E9123D45-C1B0-4462-8810-D26ED6D31944}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -389,14 +355,43 @@ Global {46278108-D247-4EFC-AC34-23D4A676F62F}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {46278108-D247-4EFC-AC34-23D4A676F62F}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {46278108-D247-4EFC-AC34-23D4A676F62F}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Debug|x64.ActiveCfg = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Debug|x64.Build.0 = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Release|Any CPU.Build.0 = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Release|x64.ActiveCfg = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.Release|x64.Build.0 = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {7F05FD87-A2FB-4915-A988-4EF92AB82179}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Debug|x64.ActiveCfg = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Debug|x64.Build.0 = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Release|Any CPU.Build.0 = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Release|x64.ActiveCfg = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.Release|x64.Build.0 = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {4858E5E3-23FA-4928-B99A-54065875A2B9}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A1E878CB-ADF1-457A-9223-06F96ED8F7A6} = {99E234BC-997E-4E63-9F5C-3C3977543404} - {DF654202-0008-4CDE-B35E-018CEFD0FC68} = {A1E878CB-ADF1-457A-9223-06F96ED8F7A6} - {1467128C-90E4-4723-B5C7-9469B83F54A6} = {A1E878CB-ADF1-457A-9223-06F96ED8F7A6} {E9123D45-C1B0-4462-8810-D26ED6D31944} = {03736C2E-DB2A-46A9-B7B2-C1216BDECB4F} {058CB08D-BFA7-41E2-BE6B-0A0A72054F91} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4} {8EC46ADB-7FAA-49EA-BA63-E7B32C4F4445} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4} @@ -416,6 +411,8 @@ Global {7256B986-6705-42FC-9F57-485D72D9DE51} = {09C842CB-930C-4C7D-AD5F-E30DE4A55820} {A85277B3-4E07-4E15-8F0C-07CC855A3BCB} = {09C842CB-930C-4C7D-AD5F-E30DE4A55820} {46278108-D247-4EFC-AC34-23D4A676F62F} = {09C842CB-930C-4C7D-AD5F-E30DE4A55820} + {7F05FD87-A2FB-4915-A988-4EF92AB82179} = {37CDC768-16D4-4574-8553-07D99D0A72F7} + {4858E5E3-23FA-4928-B99A-54065875A2B9} = {37CDC768-16D4-4574-8553-07D99D0A72F7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821} diff --git a/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs b/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs index a953436ceaa..f0c9300de19 100644 --- a/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs +++ b/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs @@ -9,7 +9,6 @@ using Microsoft.Azure.Quantum.Client; using Microsoft.Azure.Quantum.Client.Models; using Microsoft.Azure.Quantum.Exceptions; -using Microsoft.Rest; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; @@ -184,13 +183,13 @@ private static IWorkspace GetWorkspace() workspaceName: TestConstants.WorkspaceName) { // Mock jobs client (only needed for unit tests) - JobsClient = new QuantumClient(MockHelper.GetHttpClientMock(), true) + QuantumClient = new QuantumClient(MockHelper.GetHttpClientMock(), true) { SubscriptionId = TestConstants.SubscriptionId, ResourceGroupName = TestConstants.ResourceGroupName, WorkspaceName = TestConstants.WorkspaceName, BaseUri = new Uri(TestConstants.Endpoint), - }.Jobs, + }, }; } diff --git a/src/Azure/Azure.Quantum.Client/Authentication/CustomAccessTokenProvider.cs b/src/Azure/Azure.Quantum.Client/Authentication/CustomAccessTokenProvider.cs index dfc447c1bc5..b95e03237b1 100644 --- a/src/Azure/Azure.Quantum.Client/Authentication/CustomAccessTokenProvider.cs +++ b/src/Azure/Azure.Quantum.Client/Authentication/CustomAccessTokenProvider.cs @@ -81,7 +81,7 @@ static string GetTenantUriFromHeader(System.Net.Http.Headers.AuthenticationHeade /// A encapsulating the access token. public async Task GetAccessTokenAsync(CancellationToken cancellationToken) { - var application = applicationLazy.Value; + var application = await applicationLazy.Value; try { diff --git a/src/Azure/Azure.Quantum.Client/Exceptions/StorageClientException.cs b/src/Azure/Azure.Quantum.Client/Exceptions/StorageClientException.cs index 9e3bbc53d4a..5bef01d9787 100644 --- a/src/Azure/Azure.Quantum.Client/Exceptions/StorageClientException.cs +++ b/src/Azure/Azure.Quantum.Client/Exceptions/StorageClientException.cs @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; - namespace Microsoft.Azure.Quantum.Exceptions { + using System; + /// /// The exception that is thrown when an error related to the Azure storage client occurs. /// @@ -46,19 +46,16 @@ public StorageClientException( /// Initializes a new instance of the class with a specified error message, a reference to another exception that caused this one and more detailes that are specific to the storage client. /// /// Error message that explains the reason for the exception. - /// Connection string used by the storage client. /// Name of the container involved in the operation that caused the exception. /// Name of the BLOB involved in the operation that caused the exception. /// Exception that is the cause of the current one. public StorageClientException( string message, - string connectionString, string containerName, string blobName, Exception inner) : base( $"{BaseMessage}: {message}{Environment.NewLine}" + - $"ConnectionString: {connectionString}{Environment.NewLine}" + $"ContainerName: {containerName}{Environment.NewLine}" + $"BlobName: {blobName}", inner) diff --git a/src/Azure/Azure.Quantum.Client/JobManagement/CloudJob.cs b/src/Azure/Azure.Quantum.Client/JobManagement/CloudJob.cs index 9f3c54a7be8..746de8c57b1 100644 --- a/src/Azure/Azure.Quantum.Client/JobManagement/CloudJob.cs +++ b/src/Azure/Azure.Quantum.Client/JobManagement/CloudJob.cs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Azure.Quantum.Client.Models; -using Microsoft.Azure.Quantum.Utility; -using Microsoft.Quantum.Runtime; - namespace Microsoft.Azure.Quantum { + using System; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Azure.Quantum.Client.Models; + using Microsoft.Azure.Quantum.Utility; + using Microsoft.Quantum.Runtime; + /// /// Cloud job class. /// diff --git a/src/Azure/Azure.Quantum.Client/JobManagement/IWorkspace.cs b/src/Azure/Azure.Quantum.Client/JobManagement/IWorkspace.cs index 9ad313e8c8f..eaa2db3f1b2 100644 --- a/src/Azure/Azure.Quantum.Client/JobManagement/IWorkspace.cs +++ b/src/Azure/Azure.Quantum.Client/JobManagement/IWorkspace.cs @@ -50,5 +50,17 @@ Task GetJobAsync( /// List of jobs Task> ListJobsAsync( CancellationToken cancellationToken = default); + + /// + /// Gets as SAS Uri for the storage account associated with the workspace. + /// + /// Name of the container. + /// Name of the BLOB. + /// The cancellation token. + /// Sas Uri. + Task GetSasUriAsync( + string containerName, + string blobName = null, + CancellationToken cancellationToken = default); } } diff --git a/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs b/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs index 856b9dc6dca..c123010c18b 100644 --- a/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs +++ b/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs @@ -1,30 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Azure.Core; -using Microsoft.Azure.Quantum.Authentication; -using Microsoft.Azure.Quantum.Client; -using Microsoft.Azure.Quantum.Client.Models; -using Microsoft.Azure.Quantum.Exceptions; -using Microsoft.Azure.Quantum.Utility; - namespace Microsoft.Azure.Quantum { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using global::Azure.Core; + using Microsoft.Azure.Quantum.Authentication; + using Microsoft.Azure.Quantum.Client; + using Microsoft.Azure.Quantum.Client.Models; + using Microsoft.Azure.Quantum.Exceptions; + using Microsoft.Azure.Quantum.Utility; + /// /// Workspace class. /// /// public class Workspace : IWorkspace { - private readonly Uri BaseUri; - private readonly string ResourceGroupName; - private readonly string SubscriptionId; - private readonly string WorkspaceName; + private readonly Uri baseUri; + private readonly string resourceGroupName; + private readonly string subscriptionId; + private readonly string workspaceName; /// /// Initializes a new instance of the class. @@ -79,13 +79,13 @@ private Workspace( IAccessTokenProvider accessTokenProvider, Uri baseUri = null) { - BaseUri = baseUri ?? new Uri(Constants.DefaultBaseUri); + this.baseUri = baseUri ?? new Uri(Constants.DefaultBaseUri); Ensure.NotNullOrWhiteSpace(subscriptionId, nameof(subscriptionId)); - SubscriptionId = subscriptionId; + this.subscriptionId = subscriptionId; Ensure.NotNullOrWhiteSpace(resourceGroupName, nameof(resourceGroupName)); - ResourceGroupName = resourceGroupName; + this.resourceGroupName = resourceGroupName; Ensure.NotNullOrWhiteSpace(workspaceName, nameof(workspaceName)); - WorkspaceName = workspaceName; + this.workspaceName = workspaceName; try { @@ -100,13 +100,13 @@ private Workspace( try { - this.JobsClient = new QuantumClient(new AuthorizationClientHandler(accessTokenProvider)) + this.QuantumClient = new QuantumClient(new AuthorizationClientHandler(accessTokenProvider)) { - BaseUri = BaseUri, + BaseUri = this.baseUri, SubscriptionId = subscriptionId, ResourceGroupName = resourceGroupName, WorkspaceName = workspaceName, - }.Jobs; + }; } catch (Exception ex) { @@ -121,7 +121,7 @@ private Workspace( /// /// The jobs client. /// - internal IJobsOperations JobsClient { get; set; } + internal IQuantumClient QuantumClient { get; set; } /// /// Submits the job. @@ -140,7 +140,7 @@ public async Task SubmitJobAsync( try { - JobDetails jobDetails = await this.JobsClient.PutAsync( + JobDetails jobDetails = await this.QuantumClient.Jobs.PutAsync( jobId: jobDefinition.Details.Id, jobDefinition: jobDefinition.Details, cancellationToken: cancellationToken); @@ -165,7 +165,7 @@ public async Task CancelJobAsync(string jobId, CancellationToken cance try { - JobDetails jobDetails = await this.JobsClient.DeleteAsync( + JobDetails jobDetails = await this.QuantumClient.Jobs.DeleteAsync( jobId: jobId, cancellationToken: cancellationToken); @@ -191,7 +191,7 @@ public async Task GetJobAsync(string jobId, CancellationToken cancella try { - JobDetails jobDetails = await this.JobsClient.GetAsync( + JobDetails jobDetails = await this.QuantumClient.Jobs.GetAsync( jobId: jobId, cancellationToken: cancellationToken); @@ -214,7 +214,7 @@ public async Task> ListJobsAsync(CancellationToken cancell { try { - var jobs = await this.JobsClient.ListAsync( + var jobs = await this.QuantumClient.Jobs.ListAsync( cancellationToken: cancellationToken); return jobs @@ -226,6 +226,27 @@ public async Task> ListJobsAsync(CancellationToken cancell } } + /// + /// Gets as SAS Uri for the linked storage account. + /// + /// Name of the container. + /// Name of the BLOB. + /// The cancellation token. + /// + /// Sas Uri. + /// + public async Task GetSasUriAsync(string containerName, string blobName = null, CancellationToken cancellationToken = default) + { + BlobDetails details = new BlobDetails + { + ContainerName = containerName, + BlobName = blobName, + }; + + var response = await this.QuantumClient.Storage.SasUriAsync(details, cancellationToken); + return response.SasUri; + } + private WorkspaceClientException CreateException( Exception inner, string message, @@ -233,10 +254,10 @@ private WorkspaceClientException CreateException( { return new WorkspaceClientException( message, - SubscriptionId, - ResourceGroupName, - WorkspaceName, - BaseUri, + subscriptionId, + resourceGroupName, + workspaceName, + baseUri, jobId, inner); } diff --git a/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs b/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs index 94ab65f2368..fd709cee94e 100644 --- a/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs +++ b/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using Microsoft.Quantum.Runtime; @@ -13,9 +15,10 @@ public static class QuantumMachineFactory /// /// The Azure Quantum workspace. /// The execution target for job submission. - /// The connection string for the Azure storage account. + /// The connection string for the Azure storage account. /// A quantum machine for job submission targeting targetName. - public static IQuantumMachine? CreateMachine(IWorkspace workspace, string targetName, string storageAccountConnectionString) + public static IQuantumMachine? CreateMachine( + IWorkspace workspace, string targetName, string? storageConnectionString = null) { var machineName = targetName is null @@ -26,7 +29,7 @@ targetName is null ? "Microsoft.Quantum.Providers.Honeywell.Targets.HoneywellQuantumMachine, Microsoft.Quantum.Providers.Honeywell" : null; - Type machineType = null; + Type? machineType = null; if (machineName != null) { // First try to load the signed assembly with the correct version, then try the unsigned one. @@ -47,8 +50,8 @@ targetName is null : (IQuantumMachine)Activator.CreateInstance( machineType, targetName, - storageAccountConnectionString, - workspace); + workspace, + storageConnectionString); } } -} \ No newline at end of file +} diff --git a/src/Azure/Azure.Quantum.Client/Storage/IStorageHelper.cs b/src/Azure/Azure.Quantum.Client/Storage/IStorageHelper.cs index 6b8f937890f..d1e010f9e9e 100644 --- a/src/Azure/Azure.Quantum.Client/Storage/IStorageHelper.cs +++ b/src/Azure/Azure.Quantum.Client/Storage/IStorageHelper.cs @@ -1,27 +1,28 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Bond; -using Microsoft.WindowsAzure.Storage.Blob; - namespace Microsoft.Azure.Quantum.Storage { + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using Bond; + using global::Azure.Storage.Blobs; + using Microsoft.WindowsAzure.Storage.Blob; + public interface IStorageHelper { /// /// Downloads the BLOB. /// - /// Name of the container. + /// Container client. /// Name of the BLOB. /// The destination. /// The cancellation token. /// Serialization protocol of the downloaded BLOB. Task DownloadBlobAsync( - string containerName, + BlobContainerClient containerClient, string blobName, Stream destination, CancellationToken cancellationToken = default); @@ -29,14 +30,14 @@ Task DownloadBlobAsync( /// /// Uploads the BLOB. /// - /// Name of the container. + /// Container client. /// Name of the BLOB. /// The input. /// Serialization protocol of the BLOB to upload. /// The cancellation token. /// async task. Task UploadBlobAsync( - string containerName, + BlobContainerClient containerClient, string blobName, Stream input, ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, @@ -45,12 +46,14 @@ Task UploadBlobAsync( /// /// Gets the BLOB sas URI. /// + /// Storage account connection string. /// Name of the container. /// Name of the BLOB. /// The expiry interval. /// The permissions. /// Blob uri. string GetBlobSasUri( + string connectionString, string containerName, string blobName, TimeSpan expiryInterval, @@ -59,11 +62,13 @@ string GetBlobSasUri( /// /// Gets the BLOB container sas URI. /// + /// Storage account connection string. /// Name of the container. /// The expiry interval. /// The permissions. /// Container uri. string GetBlobContainerSasUri( + string connectionString, string containerName, TimeSpan expiryInterval, SharedAccessBlobPermissions permissions); diff --git a/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelper.cs b/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelper.cs index 17fc10a7103..4898e24c6db 100644 --- a/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelper.cs +++ b/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelper.cs @@ -1,19 +1,22 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Bond; -using Microsoft.Azure.Quantum.Utility; -using Microsoft.WindowsAzure.Storage.Blob; - namespace Microsoft.Azure.Quantum.Storage { - public class JobStorageHelper : IJobStorageHelper + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using Bond; + using global::Azure.Storage.Blobs; + using Microsoft.Azure.Quantum.Exceptions; + using Microsoft.Azure.Quantum.Utility; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Blob; + + public class JobStorageHelper : JobStorageHelperBase { - private readonly TimeSpan expiryInterval; + private readonly string connectionString; /// /// Initializes a new instance of the class. @@ -21,14 +24,19 @@ public class JobStorageHelper : IJobStorageHelper /// The connection string. public JobStorageHelper(string connectionString) { - this.StorageHelper = new StorageHelper(connectionString); - this.expiryInterval = TimeSpan.FromDays(Constants.Storage.ExpiryIntervalInDays); - } + this.connectionString = connectionString; - /// - /// Gets the underlying storage helper. - /// - public IStorageHelper StorageHelper { get; } + try + { + _ = CloudStorageAccount.Parse(connectionString); + } + catch (Exception ex) + { + throw new StorageClientException( + "An error related to the cloud storage account occurred", + ex); + } + } /// /// Uploads the job input. @@ -40,29 +48,34 @@ public JobStorageHelper(string connectionString) /// /// Container uri + Input uri. /// - public async Task<(string containerUri, string inputUri)> UploadJobInputAsync( + public override async Task<(string containerUri, string inputUri)> UploadJobInputAsync( string jobId, Stream input, ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, CancellationToken cancellationToken = default) { string containerName = GetContainerName(jobId); + + BlobContainerClient containerClient = await this.GetContainerClient(containerName); + await this.StorageHelper.UploadBlobAsync( - containerName, + containerClient, Constants.Storage.InputBlobName, input, protocol, cancellationToken); string containerUri = this.StorageHelper.GetBlobContainerSasUri( + this.connectionString, containerName, - this.expiryInterval, + this.ExpiryInterval, SharedAccessBlobPermissions.Create | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read); string inputUri = this.StorageHelper.GetBlobSasUri( + this.connectionString, containerName, Constants.Storage.InputBlobName, - this.expiryInterval, + this.ExpiryInterval, SharedAccessBlobPermissions.Read); return (containerUri, inputUri); @@ -76,57 +89,42 @@ await this.StorageHelper.UploadBlobAsync( /// Serialization protocol of the mapping to upload. /// The cancellation token. /// Container uri + Mapping uri. - public async Task<(string containerUri, string mappingUri)> UploadJobMappingAsync( + public override async Task<(string containerUri, string mappingUri)> UploadJobMappingAsync( string jobId, Stream mapping, ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, CancellationToken cancellationToken = default) { string containerName = GetContainerName(jobId); + BlobContainerClient containerClient = await this.GetContainerClient(containerName); + await this.StorageHelper.UploadBlobAsync( - containerName, + containerClient, Constants.Storage.MappingBlobName, mapping, protocol, cancellationToken); string containerUri = this.StorageHelper.GetBlobContainerSasUri( + this.connectionString, containerName, - this.expiryInterval, + this.ExpiryInterval, SharedAccessBlobPermissions.Create | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read); string mappingUri = this.StorageHelper.GetBlobSasUri( + this.connectionString, containerName, Constants.Storage.MappingBlobName, - this.expiryInterval, + this.ExpiryInterval, SharedAccessBlobPermissions.Read); return (containerUri, mappingUri); } - /// - /// Downloads the job's execution output. - /// - /// The job id. - /// The destination stream. - /// The cancellation token. - /// Serialization protocol of the downloaded execution output. - public Task DownloadJobOutputAsync( - string jobId, - Stream destination, - CancellationToken cancellationToken = default) - { - string containerName = GetContainerName(jobId); - return this.StorageHelper.DownloadBlobAsync( - containerName, - "rawOutputData", // TODO: 14643 - destination, - cancellationToken); - } - - private static string GetContainerName(string jobId) + protected override Task GetContainerClient(string containerName, CancellationToken cancellationToken = default) { - return Constants.Storage.ContainerNamePrefix + jobId.ToLowerInvariant(); + BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString); + return Task.FromResult(blobServiceClient.GetBlobContainerClient(containerName)); } } } diff --git a/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelperBase.cs b/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelperBase.cs new file mode 100644 index 00000000000..29f1c232016 --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/Storage/JobStorageHelperBase.cs @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Azure.Quantum.Storage +{ + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using Bond; + using global::Azure.Storage.Blobs; + using Microsoft.Azure.Quantum.Utility; + + public abstract class JobStorageHelperBase : IJobStorageHelper + { + /// + /// Initializes a new instance of the class. + /// + public JobStorageHelperBase() + { + this.StorageHelper = new StorageHelper(); + this.ExpiryInterval = TimeSpan.FromDays(Constants.Storage.ExpiryIntervalInDays); + } + + /// + /// Gets the underlying storage helper. + /// + public IStorageHelper StorageHelper { get; } + + /// + /// Gets the expiry interval. + /// + protected TimeSpan ExpiryInterval { get; private set; } + + /// + /// Downloads the job's execution output. + /// + /// The job id. + /// The destination stream. + /// The cancellation token. + /// Serialization protocol of the downloaded execution output. + public async Task DownloadJobOutputAsync( + string jobId, + Stream destination, + CancellationToken cancellationToken = default) + { + string containerName = GetContainerName(jobId); + BlobContainerClient containerClient = await this.GetContainerClient(containerName); + + return await this.StorageHelper.DownloadBlobAsync( + containerClient, + "rawOutputData", // TODO: 14643 + destination, + cancellationToken); + } + + /// + /// Uploads the job input. + /// + /// The job id. + /// The input. + /// Serialization protocol of the input to upload. + /// The cancellation token. + /// Container uri + Input uri. + public abstract Task<(string containerUri, string inputUri)> UploadJobInputAsync( + string jobId, + Stream input, + ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, + CancellationToken cancellationToken = default); + + /// + /// Uploads the job program output mapping. + /// + /// The job id. + /// The job program output mapping. + /// Serialization protocol of the mapping to upload. + /// The cancellation token. + /// Container uri + Mapping uri. + public abstract Task<(string containerUri, string mappingUri)> UploadJobMappingAsync( + string jobId, + Stream mapping, + ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, + CancellationToken cancellationToken = default); + + /// + /// Gets the container client. + /// + /// Name of the container. + /// Cancellation token. + /// Container client. + protected abstract Task GetContainerClient(string containerName, CancellationToken cancellationToken = default); + + protected static string GetContainerName(string jobId) + { + return Constants.Storage.ContainerNamePrefix + jobId.ToLowerInvariant(); + } + } +} diff --git a/src/Azure/Azure.Quantum.Client/Storage/LinkedStorageJobHelper.cs b/src/Azure/Azure.Quantum.Client/Storage/LinkedStorageJobHelper.cs new file mode 100644 index 00000000000..4d6dba0334c --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/Storage/LinkedStorageJobHelper.cs @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Azure.Quantum.Storage +{ + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using Bond; + using global::Azure.Storage.Blobs; + using Microsoft.Azure.Quantum.Utility; + + public class LinkedStorageJobHelper : JobStorageHelperBase + { + private readonly IWorkspace workspace; + + /// + /// Initializes a new instance of the class. + /// + /// The workspace. + public LinkedStorageJobHelper(IWorkspace workspace) + { + this.workspace = workspace; + } + + /// + /// Uploads the job input. + /// + /// The job id. + /// The input. + /// Serialization protocol of the input to upload. + /// The cancellation token. + /// + /// Container uri + Input uri without SAS. + /// + public override async Task<(string containerUri, string inputUri)> UploadJobInputAsync( + string jobId, + Stream input, + ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, + CancellationToken cancellationToken = default) + { + string containerName = GetContainerName(jobId); + + BlobContainerClient containerClient = await this.GetContainerClient(containerName); + + await this.StorageHelper.UploadBlobAsync( + containerClient, + Constants.Storage.InputBlobName, + input, + protocol, + cancellationToken); + + Uri inputUri = containerClient + .GetBlobClient(Constants.Storage.InputBlobName) + .Uri; + + return (GetUriPath(containerClient.Uri), GetUriPath(inputUri)); + } + + /// + /// Uploads the job program output mapping. + /// + /// The job id. + /// The job program output mapping. + /// Serialization protocol of the mapping to upload. + /// The cancellation token. + /// Container uri + Mapping uri without SAS. + public override async Task<(string containerUri, string mappingUri)> UploadJobMappingAsync( + string jobId, + Stream mapping, + ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, + CancellationToken cancellationToken = default) + { + string containerName = GetContainerName(jobId); + BlobContainerClient containerClient = await this.GetContainerClient(containerName); + + await this.StorageHelper.UploadBlobAsync( + containerClient, + Constants.Storage.MappingBlobName, + mapping, + protocol, + cancellationToken); + + Uri mappingUri = containerClient + .GetBlobClient(Constants.Storage.MappingBlobName) + .Uri; + + return (GetUriPath(containerClient.Uri), GetUriPath(mappingUri)); + } + + protected override async Task GetContainerClient(string containerName, CancellationToken cancellationToken = default) + { + // Calls the service to get a container SAS Uri + var containerUri = await this.workspace.GetSasUriAsync( + containerName: containerName, + cancellationToken: cancellationToken); + + return new BlobContainerClient(new Uri(containerUri)); + } + + private string GetUriPath(Uri uri) + { + return uri.GetLeftPart(UriPartial.Path); + } + } +} diff --git a/src/Azure/Azure.Quantum.Client/Storage/StorageHelper.cs b/src/Azure/Azure.Quantum.Client/Storage/StorageHelper.cs index ac97887a266..e3ee0787da2 100644 --- a/src/Azure/Azure.Quantum.Client/Storage/StorageHelper.cs +++ b/src/Azure/Azure.Quantum.Client/Storage/StorageHelper.cs @@ -1,64 +1,43 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Models; -using Bond; -using Microsoft.Azure.Quantum.Exceptions; -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Blob; - namespace Microsoft.Azure.Quantum.Storage { + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using Bond; + using global::Azure.Storage.Blobs; + using global::Azure.Storage.Blobs.Models; + using Microsoft.Azure.Quantum.Exceptions; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Blob; + internal class StorageHelper : IStorageHelper { - private readonly string connectionString; - private readonly CloudStorageAccount storageAccount; - - /// - /// Initializes a new instance of the class. - /// - /// The connection string. - public StorageHelper(string connectionString) - { - this.connectionString = connectionString; - - try - { - this.storageAccount = CloudStorageAccount.Parse(connectionString); - } - catch (Exception ex) - { - throw CreateException(ex, "An error related to the cloud storage account occurred"); - } - } - /// /// Downloads the BLOB. /// - /// Name of the container. + /// Container client. /// Name of the BLOB. /// The destination. /// The cancellation token. /// Serialization protocol of the downloaded BLOB. public async Task DownloadBlobAsync( - string containerName, + BlobContainerClient containerClient, string blobName, Stream destination, CancellationToken cancellationToken = default) { try { - BlobClient blob = await this.GetBlobClient(containerName, blobName, false, cancellationToken); + BlobClient blob = containerClient.GetBlobClient(blobName); await blob.DownloadToAsync(destination, cancellationToken); } catch (Exception ex) { - throw CreateException(ex, "Could not download BLOB", containerName, blobName); + throw CreateException(ex, "Could not download BLOB", containerClient.Name, blobName); } return ProtocolType.COMPACT_PROTOCOL; @@ -67,14 +46,14 @@ public async Task DownloadBlobAsync( /// /// Uploads the BLOB. /// - /// Name of the container. + /// Container client. /// Name of the BLOB. /// The input. /// Serialization protocol of the BLOB to upload. /// The cancellation token. /// Async task. public async Task UploadBlobAsync( - string containerName, + BlobContainerClient containerClient, string blobName, Stream input, ProtocolType protocol = ProtocolType.COMPACT_PROTOCOL, @@ -82,24 +61,30 @@ public async Task UploadBlobAsync( { try { - BlobClient blob = await this.GetBlobClient(containerName, blobName, true, cancellationToken); + // Ensure container is created + await containerClient.CreateIfNotExistsAsync(PublicAccessType.Blob, cancellationToken: cancellationToken); + + // Upload blob + BlobClient blob = containerClient.GetBlobClient(blobName); await blob.UploadAsync(input, overwrite: true, cancellationToken); } catch (Exception ex) { - throw CreateException(ex, "Could not upload BLOB", containerName, blobName); + throw CreateException(ex, "Could not upload BLOB", containerClient.Name, blobName); } } /// /// Gets the BLOB sas URI. /// + /// Storage account connection string. /// Name of the container. /// Name of the BLOB. /// The expiry interval. /// The permissions. /// Blob uri. public string GetBlobSasUri( + string connectionString, string containerName, string blobName, TimeSpan expiryInterval, @@ -109,7 +94,8 @@ public string GetBlobSasUri( { SharedAccessBlobPolicy adHocSAS = CreateSharedAccessBlobPolicy(expiryInterval, permissions); - CloudBlob blob = this.storageAccount + CloudBlob blob = CloudStorageAccount + .Parse(connectionString) .CreateCloudBlobClient() .GetContainerReference(containerName) .GetBlobReference(blobName); @@ -125,11 +111,13 @@ public string GetBlobSasUri( /// /// Gets the BLOB container sas URI. /// + /// Storage account connection string. /// Name of the container. /// The expiry interval. /// The permissions. /// Container uri. public string GetBlobContainerSasUri( + string connectionString, string containerName, TimeSpan expiryInterval, SharedAccessBlobPermissions permissions) @@ -139,7 +127,10 @@ public string GetBlobContainerSasUri( SharedAccessBlobPolicy adHocPolicy = CreateSharedAccessBlobPolicy(expiryInterval, permissions); // Generate the shared access signature on the container, setting the constraints directly on the signature. - CloudBlobContainer container = this.storageAccount.CreateCloudBlobClient().GetContainerReference(containerName); + CloudBlobContainer container = CloudStorageAccount + .Parse(connectionString) + .CreateCloudBlobClient().GetContainerReference(containerName); + return container.Uri + container.GetSharedAccessSignature(adHocPolicy, null); } catch (Exception ex) @@ -156,29 +147,11 @@ private StorageClientException CreateException ( { return new StorageClientException( message, - connectionString, containerName, blobName, inner); } - private async Task GetBlobClient( - string containerName, - string blobName, - bool createContainer, - CancellationToken cancellationToken) - { - BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString); - BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName); - - if (createContainer) - { - await blobContainerClient.CreateIfNotExistsAsync(PublicAccessType.Blob, cancellationToken: cancellationToken); - } - - return blobContainerClient.GetBlobClient(blobName); - } - private static SharedAccessBlobPolicy CreateSharedAccessBlobPolicy( TimeSpan expiryInterval, SharedAccessBlobPermissions permissions) diff --git a/src/Azure/Azure.Quantum.Client/Utility/LazyAsync.cs b/src/Azure/Azure.Quantum.Client/Utility/LazyAsync.cs index 99f27d02124..5e978ff3ba9 100644 --- a/src/Azure/Azure.Quantum.Client/Utility/LazyAsync.cs +++ b/src/Azure/Azure.Quantum.Client/Utility/LazyAsync.cs @@ -9,36 +9,26 @@ namespace Microsoft.Azure.Quantum.Utility { - internal sealed class LazyAsync + internal sealed class LazyAsync : Lazy> { - private readonly Lazy> instance; - private readonly Lazy valueL; - /// - /// Constructor for use with synchronous factories + /// Initializes a new instance of the class. + /// Constructor for use with asynchronous factories. /// - public LazyAsync(Func synchronousFactory) - : this(new Lazy>(() => Task.Run(synchronousFactory))) - { - } + /// Async value factory. + public LazyAsync(Func> taskFactory) + : base(() => Task.Run(taskFactory)) + { } /// - /// Constructor for use with asynchronous factories + /// Initializes a new instance of the class. + /// Constructor for use with synchronous factories. /// - public LazyAsync(Func> asynchronousFactory) - : this(new Lazy>(() => asynchronousFactory())) - { - } - - // private constructor which sets both fields - private LazyAsync(Lazy> instance) - { - this.instance = instance; - this.valueL = new Lazy(() => this.instance.Value.GetAwaiter().GetResult()); - } - - public T Value => valueL.Value; + /// Sync value factory. + public LazyAsync(Func valueFactory) + : base(() => Task.Run(valueFactory)) + { } - public TaskAwaiter GetAwaiter() => instance.Value.GetAwaiter(); + public TaskAwaiter GetAwaiter() => Value.GetAwaiter(); } } \ No newline at end of file diff --git a/src/Azure/Azure.Quantum.Client/generated/IQuantumClient.cs b/src/Azure/Azure.Quantum.Client/generated/IQuantumClient.cs index f4ae50f1a37..db391fa0911 100644 --- a/src/Azure/Azure.Quantum.Client/generated/IQuantumClient.cs +++ b/src/Azure/Azure.Quantum.Client/generated/IQuantumClient.cs @@ -85,5 +85,10 @@ public partial interface IQuantumClient : System.IDisposable /// IProvidersOperations Providers { get; } + /// + /// Gets the IStorageOperations. + /// + IStorageOperations Storage { get; } + } } diff --git a/src/Azure/Azure.Quantum.Client/generated/IStorageOperations.cs b/src/Azure/Azure.Quantum.Client/generated/IStorageOperations.cs new file mode 100644 index 00000000000..4010389be24 --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/generated/IStorageOperations.cs @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// + +namespace Microsoft.Azure.Quantum.Client +{ + using Microsoft.Rest; + using Microsoft.Rest.Azure; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// StorageOperations operations. + /// + public partial interface IStorageOperations + { + /// + /// Gets a URL with SAS token for a container/blob in the storage + /// account associated with the workspace. The SAS URL can be used to + /// upload job input and/or download job output. + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when unable to deserialize the response + /// + /// + /// Thrown when a required parameter is null + /// + Task> SasUriWithHttpMessagesAsync(BlobDetails blobDetails, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/src/Azure/Azure.Quantum.Client/generated/JobsOperations.cs b/src/Azure/Azure.Quantum.Client/generated/JobsOperations.cs index 81697920294..cf7e04ca42a 100644 --- a/src/Azure/Azure.Quantum.Client/generated/JobsOperations.cs +++ b/src/Azure/Azure.Quantum.Client/generated/JobsOperations.cs @@ -169,7 +169,7 @@ internal JobsOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - CloudError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + CloudError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex = new CloudException(_errorBody.Message); @@ -211,7 +211,7 @@ internal JobsOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { @@ -358,7 +358,7 @@ internal JobsOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - RestError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + RestError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex.Body = _errorBody; @@ -395,7 +395,7 @@ internal JobsOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { @@ -529,7 +529,7 @@ internal JobsOperations(QuantumClient client) string _requestContent = null; if(jobDefinition != null) { - _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(jobDefinition, Client.SerializationSettings); + _requestContent = Rest.Serialization.SafeJsonConvert.SerializeObject(jobDefinition, Client.SerializationSettings); _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); } @@ -559,7 +559,7 @@ internal JobsOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - RestError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + RestError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex.Body = _errorBody; @@ -596,7 +596,7 @@ internal JobsOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { @@ -614,7 +614,7 @@ internal JobsOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { @@ -761,7 +761,7 @@ internal JobsOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - RestError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + RestError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex.Body = _errorBody; @@ -798,7 +798,7 @@ internal JobsOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { @@ -929,7 +929,7 @@ internal JobsOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - CloudError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + CloudError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex = new CloudException(_errorBody.Message); @@ -971,7 +971,7 @@ internal JobsOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { diff --git a/src/Azure/Azure.Quantum.Client/generated/Models/BlobDetails.cs b/src/Azure/Azure.Quantum.Client/generated/Models/BlobDetails.cs new file mode 100644 index 00000000000..6698af8a001 --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/generated/Models/BlobDetails.cs @@ -0,0 +1,73 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// + +namespace Microsoft.Azure.Quantum.Client.Models +{ + using Microsoft.Rest; + using Newtonsoft.Json; + using System.Linq; + + /// + /// Blob details. + /// + public partial class BlobDetails + { + /// + /// Initializes a new instance of the BlobDetails class. + /// + public BlobDetails() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the BlobDetails class. + /// + /// The container name. + /// The blob name. + public BlobDetails(string containerName, string blobName = default(string)) + { + ContainerName = containerName; + BlobName = blobName; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// Gets or sets the container name. + /// + [JsonProperty(PropertyName = "containerName")] + public string ContainerName { get; set; } + + /// + /// Gets or sets the blob name. + /// + [JsonProperty(PropertyName = "blobName")] + public string BlobName { get; set; } + + /// + /// Validate the object. + /// + /// + /// Thrown if validation fails + /// + public virtual void Validate() + { + if (ContainerName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "ContainerName"); + } + } + } +} diff --git a/src/Azure/Azure.Quantum.Client/generated/Models/RestError.cs b/src/Azure/Azure.Quantum.Client/generated/Models/RestError.cs index 4917d841e8e..466b3737fa8 100644 --- a/src/Azure/Azure.Quantum.Client/generated/Models/RestError.cs +++ b/src/Azure/Azure.Quantum.Client/generated/Models/RestError.cs @@ -18,7 +18,7 @@ namespace Microsoft.Azure.Quantum.Client.Models /// /// An Error response. /// - [JsonTransformation] + [Rest.Serialization.JsonTransformation] public partial class RestError { /// diff --git a/src/Azure/Azure.Quantum.Client/generated/Models/SasUriResponse.cs b/src/Azure/Azure.Quantum.Client/generated/Models/SasUriResponse.cs new file mode 100644 index 00000000000..b811d2e06a6 --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/generated/Models/SasUriResponse.cs @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// + +namespace Microsoft.Azure.Quantum.Client.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// Get SAS URL operation response. + /// + public partial class SasUriResponse + { + /// + /// Initializes a new instance of the SasUriResponse class. + /// + public SasUriResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the SasUriResponse class. + /// + /// A URL with a SAS token to upload a blob for + /// execution in the given workspace. + public SasUriResponse(string sasUri = default(string)) + { + SasUri = sasUri; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// Gets or sets a URL with a SAS token to upload a blob for execution + /// in the given workspace. + /// + [JsonProperty(PropertyName = "sasUri")] + public string SasUri { get; set; } + + } +} diff --git a/src/Azure/Azure.Quantum.Client/generated/ProvidersOperations.cs b/src/Azure/Azure.Quantum.Client/generated/ProvidersOperations.cs index 625e3d0457b..9cf8af20c06 100644 --- a/src/Azure/Azure.Quantum.Client/generated/ProvidersOperations.cs +++ b/src/Azure/Azure.Quantum.Client/generated/ProvidersOperations.cs @@ -169,7 +169,7 @@ internal ProvidersOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - RestError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + RestError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex.Body = _errorBody; @@ -206,7 +206,7 @@ internal ProvidersOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { @@ -337,7 +337,7 @@ internal ProvidersOperations(QuantumClient client) try { _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - RestError _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + RestError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); if (_errorBody != null) { ex.Body = _errorBody; @@ -374,7 +374,7 @@ internal ProvidersOperations(QuantumClient client) _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); try { - _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); } catch (JsonException ex) { diff --git a/src/Azure/Azure.Quantum.Client/generated/QuantumClient.cs b/src/Azure/Azure.Quantum.Client/generated/QuantumClient.cs index 3d193cee37a..2fdcd086b3c 100644 --- a/src/Azure/Azure.Quantum.Client/generated/QuantumClient.cs +++ b/src/Azure/Azure.Quantum.Client/generated/QuantumClient.cs @@ -90,6 +90,11 @@ public partial class QuantumClient : ServiceClient, IQuantumClien /// public virtual IProvidersOperations Providers { get; private set; } + /// + /// Gets the IStorageOperations. + /// + public virtual IStorageOperations Storage { get; private set; } + /// /// Initializes a new instance of the QuantumClient class. /// @@ -333,6 +338,7 @@ private void Initialize() { Jobs = new JobsOperations(this); Providers = new ProvidersOperations(this); + Storage = new StorageOperations(this); BaseUri = new System.Uri("https://app-jobscheduler-prod.azurewebsites.net"); AcceptLanguage = "en-US"; LongRunningOperationRetryTimeout = 30; diff --git a/src/Azure/Azure.Quantum.Client/generated/StorageOperations.cs b/src/Azure/Azure.Quantum.Client/generated/StorageOperations.cs new file mode 100644 index 00000000000..38ac48aa70f --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/generated/StorageOperations.cs @@ -0,0 +1,248 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// + +namespace Microsoft.Azure.Quantum.Client +{ + using Microsoft.Rest; + using Microsoft.Rest.Azure; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// StorageOperations operations. + /// + internal partial class StorageOperations : IServiceOperations, IStorageOperations + { + /// + /// Initializes a new instance of the StorageOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + internal StorageOperations(QuantumClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the QuantumClient + /// + public QuantumClient Client { get; private set; } + + /// + /// Gets a URL with SAS token for a container/blob in the storage account + /// associated with the workspace. The SAS URL can be used to upload job input + /// and/or download job output. + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when unable to deserialize the response + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> SasUriWithHttpMessagesAsync(BlobDetails blobDetails, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (Client.SubscriptionId == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "this.Client.SubscriptionId"); + } + if (Client.ResourceGroupName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "this.Client.ResourceGroupName"); + } + if (Client.WorkspaceName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "this.Client.WorkspaceName"); + } + if (blobDetails == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "blobDetails"); + } + if (blobDetails != null) + { + blobDetails.Validate(); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("blobDetails", blobDetails); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "SasUri", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "v1.0/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Quantum/workspaces/{workspaceName}/storage/sasUri").ToString(); + _url = _url.Replace("{subscriptionId}", System.Uri.EscapeDataString(Client.SubscriptionId)); + _url = _url.Replace("{resourceGroupName}", System.Uri.EscapeDataString(Client.ResourceGroupName)); + _url = _url.Replace("{workspaceName}", System.Uri.EscapeDataString(Client.WorkspaceName)); + List _queryParameters = new List(); + if (_queryParameters.Count > 0) + { + _url += (_url.Contains("?") ? "&" : "?") + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.GenerateClientRequestId != null && Client.GenerateClientRequestId.Value) + { + _httpRequest.Headers.TryAddWithoutValidation("x-ms-client-request-id", System.Guid.NewGuid().ToString()); + } + if (Client.AcceptLanguage != null) + { + if (_httpRequest.Headers.Contains("accept-language")) + { + _httpRequest.Headers.Remove("accept-language"); + } + _httpRequest.Headers.TryAddWithoutValidation("accept-language", Client.AcceptLanguage); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(blobDetails != null) + { + _requestContent = Rest.Serialization.SafeJsonConvert.SerializeObject(blobDetails, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Set Credentials + if (Client.Credentials != null) + { + cancellationToken.ThrowIfCancellationRequested(); + await Client.Credentials.ProcessHttpRequestAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if ((int)_statusCode != 200) + { + var ex = new RestErrorException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + RestError _errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new AzureOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + if (_httpResponse.Headers.Contains("x-ms-request-id")) + { + _result.RequestId = _httpResponse.Headers.GetValues("x-ms-request-id").FirstOrDefault(); + } + // Deserialize Response + if ((int)_statusCode == 200) + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _responseContent, ex); + } + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/src/Azure/Azure.Quantum.Client/generated/StorageOperationsExtensions.cs b/src/Azure/Azure.Quantum.Client/generated/StorageOperationsExtensions.cs new file mode 100644 index 00000000000..ec883e16100 --- /dev/null +++ b/src/Azure/Azure.Quantum.Client/generated/StorageOperationsExtensions.cs @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// + +namespace Microsoft.Azure.Quantum.Client +{ + using Microsoft.Rest; + using Microsoft.Rest.Azure; + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for StorageOperations. + /// + public static partial class StorageOperationsExtensions + { + /// + /// Gets a URL with SAS token for a container/blob in the storage account + /// associated with the workspace. The SAS URL can be used to upload job input + /// and/or download job output. + /// + /// + /// The operations group for this extension method. + /// + /// + /// + public static SasUriResponse SasUri(this IStorageOperations operations, BlobDetails blobDetails) + { + return operations.SasUriAsync(blobDetails).GetAwaiter().GetResult(); + } + + /// + /// Gets a URL with SAS token for a container/blob in the storage account + /// associated with the workspace. The SAS URL can be used to upload job input + /// and/or download job output. + /// + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task SasUriAsync(this IStorageOperations operations, BlobDetails blobDetails, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.SasUriWithHttpMessagesAsync(blobDetails, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/src/Quantum.Development.Kit/Props/QSharp.targets b/src/Quantum.Development.Kit/Props/QSharp.targets index f3a638fc586..8168e7919a1 100644 --- a/src/Quantum.Development.Kit/Props/QSharp.targets +++ b/src/Quantum.Development.Kit/Props/QSharp.targets @@ -7,25 +7,25 @@ --> - $(QscExe) $(QsharpDocsGen) --qst $(QsharpTree) --input "@(QsharpFiles,'" "')" --references "@(QsReferences,'" "')" --output $(QsharpOutDir) + $(QscExe) $(QsharpDocsGen) --qst "$(QsharpTree)" --input "@(QsharpFiles,'" "')" --references "@(QsReferences,'" "')" --output "$(QsharpOutDir)" - + - - + + @@ -36,7 +36,7 @@ DependsOnTargets="QsharpPrepare" BeforeTargets="Clean"> - + @@ -52,21 +52,23 @@ false - + false $(BaseIntermediateOutputPath)qsharp - $(QsharpOutDir)\ - $(QsharpOutDir)src\ + $([MSBuild]::Unescape('$(QsharpOutDir)').Replace('\', '/')) + $(QsharpOutDir)/ + $(QsharpOutDir)src/ $(QsharpOutDir).backup.$([System.DateTime]::Now.ToString(`yyyyMMddhhmmss`)) - $(QsharpOutDir)docs\ - --doc $(QsharpDocsOutDir) + $(QsharpOutDir)docs/ + $([MSBuild]::Unescape('$(QsharpDocsOutDir)').Replace('\', '/')) + --doc "$(QsharpDocsOutDir)" $([System.String]::Copy('$(AssemblyName)').Replace(' ','')) - \ No newline at end of file + diff --git a/src/Simulation/Core/Qubit.cs b/src/Simulation/Core/Qubit.cs index 61f912fd5b6..ec1e0d40125 100644 --- a/src/Simulation/Core/Qubit.cs +++ b/src/Simulation/Core/Qubit.cs @@ -32,6 +32,8 @@ public Qubit(int id) this.Id = id; } + public bool IsMeasured { get; set; } = false; + public int Id { get; private set; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] diff --git a/src/Simulation/CsharpGeneration.Tests/Circuits/CodegenTests.qs b/src/Simulation/CsharpGeneration.Tests/Circuits/CodegenTests.qs index 4761f2b4aaf..131e7899e01 100644 --- a/src/Simulation/CsharpGeneration.Tests/Circuits/CodegenTests.qs +++ b/src/Simulation/CsharpGeneration.Tests/Circuits/CodegenTests.qs @@ -2,58 +2,58 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Overrides { - + newtype udt0 = (Result, Result); - - + + function emptyFunction () : Unit { body intrinsic; } - + } namespace Microsoft.Quantum.Testing { - + open Microsoft.Quantum.Intrinsic; - - + + // Nothing in it function emptyFunction () : Unit { body intrinsic; } - - + + operation emptyOperation () : Unit { body intrinsic; } - - + + //Function tests function intFunction () : Int { - + return 1; } - - + + // A duplicated H, just in case... operation H (q1 : Qubit) : Unit { - + } - - + + function powFunction (x : Int, y : Int) : Int { - + return x ^ y; } - - + + function bigPowFunction (x : BigInt, y : Int) : BigInt { - + return x ^ y; } - - + + operation zeroQubitOperation () : Unit { body { } @@ -61,339 +61,339 @@ namespace Microsoft.Quantum.Testing { controlled auto; adjoint controlled auto; } - + operation oneQubitAbstractOperation (q1 : Qubit) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation oneQubitSelfAdjointAbstractOperation (q1 : Qubit) : Unit { body intrinsic; adjoint self; controlled intrinsic; controlled adjoint self; } - + newtype Basis = Pauli; - + newtype udt_Real = Double; - + newtype udt_Complex = (udt_Real, udt_Real); - + newtype udt_TwoDimArray = Result[][]; - + operation randomAbstractOperation (q1 : Qubit, b : Basis, t : (Pauli, Double[][], Bool), i : Int) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation oneQubitSelfAdjointOperation (q1 : Qubit) : Unit { - + body (...) { Z(q1); } - + adjoint self; } - - + + operation oneQubitOperation (q1 : Qubit) : Unit { - + body (...) { // some comment in body. X(q1); } - + adjoint (...) { // some comment in adjoint. // second comment in adjoint. Adjoint X(q1); } - + controlled (c, ...) { Controlled X(c, q1); // some comment in controlled at the bottom. // Notice an empty statement (;) will be added to // make it easy to add this comment... } - + controlled adjoint (c, ...) { Adjoint Controlled X(c, q1); } } - - + + operation twoQubitOperation (q1 : Qubit, t1 : (Qubit, Double)) : Unit { - + body (...) { let (q2, r) = t1; CNOT(q1, q2); R(r, q1); } - + adjoint (...) { let (q2, r) = t1; - + // One Comment. Adjoint R(r, q1); - + // First comment. // Second comment. Adjoint CNOT(q1, q2); } } - - + + operation three_op1 (q1 : Qubit, q2 : Qubit) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation threeQubitOperation (q1 : Qubit, q2 : Qubit, arr1 : Qubits) : Unit { - + body (...) { three_op1(q1, q2); three_op1(q2, q1); three_op1(q1, q2); } - + adjoint (...) { Adjoint three_op1(q1, q2); Adjoint three_op1(q2, q1); Adjoint three_op1(q1, q2); } - + controlled (c, ...) { Controlled three_op1(c, (q1, q2)); Controlled three_op1(c, (q2, q1)); Controlled three_op1(c, (q1, q2)); } - + controlled adjoint (c, ...) { Adjoint Controlled three_op1(c, (q1, q2)); Adjoint Controlled three_op1(c, (q2, q1)); Adjoint Controlled three_op1(c, (q1, q2)); } } - - + + operation nestedArgTuple1 ((a : Int, b : Int), (c : Double, d : Double)) : Unit { body intrinsic; } - - + + operation nestedArgTuple2 (a : (Int, Int), (c : Double, (b : Int, d : (Qubit, Qubit)), e : Double)) : Unit { body intrinsic; } - - + + operation nestedArgTupleGeneric<'A> (a : ('A, Int), (c : 'A, (b : Int, d : (Qubit, 'A)), e : Double)) : Unit { body intrinsic; } - - + + // calling function with the same name in different namespaces operation duplicatedDefinitionsCaller () : Unit { - + emptyFunction(); Microsoft.Quantum.Overrides.emptyFunction(); - + using (qubits = Qubit[1]) { H(qubits[0]); Microsoft.Quantum.Intrinsic.H(qubits[0]); } } - - + + operation da_op0 () : Unit { body intrinsic; } - - + + operation da_op1 (q1 : Qubit) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation da_op2 (i : Int, q : Qubit) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation da_op3 (d : Double, r : Result, i : Int) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation differentArgsOperation (q1 : Qubit, q2 : Qubit, arr1 : Qubit[]) : Unit { - + da_op0(); Adjoint da_op1(q1); Controlled da_op2([q1], (1, q2)); Adjoint Controlled da_op3([q1, q2], (1.1, One, Length(arr1))); } - - + + function random_f0 () : Int { - + return 1; } - - + + function random_f1 (n1 : Int, n2 : Int) : Int { - + return n1 * n2 - random_f0(); } - - + + operation random_op0 (q1 : Qubit, i1 : Int) : Unit { - + } - - + + operation random_op1 (q1 : Qubit) : Result { body intrinsic; } - - + + operation random_op2 (q1 : Qubit) : Result { body intrinsic; } - - + + operation random_op3 (q1 : Qubit, r1 : Result, p1 : Pauli) : Unit { body intrinsic; } - - + + operation random_op4 (q1 : Qubit, p1 : Pauli) : Unit { body intrinsic; } - - + + operation random_op5 (q1 : Qubit, p1 : Pauli) : Unit { body intrinsic; adjoint intrinsic; } - - + + operation random_op6 (q1 : Qubit, p1 : Pauli) : Unit { body intrinsic; } - - + + operation random_op7 (q1 : Qubit, p1 : Pauli) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation random_op8 (q1 : Qubit, p1 : Pauli) : Unit { body intrinsic; } - - + + operation random_op9 (q1 : Qubit, p1 : Pauli) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation random_op10 (q1 : Qubit, i1 : Int) : Unit { body intrinsic; } - - + + operation randomOperation (q1 : Qubit, i1 : Int, r1 : Result, p1 : Pauli) : Unit { - + body (...) { let arr1 = [q1, q1]; - + using (qubits = Qubit[Length(arr1)]) { random_op0(q1, i1); let r = random_op1(q1); - + if (r == One) { - + borrowing (b = Qubit[Length(arr1) + i1]) { - + for (i in 0 .. 1 .. 5) { let m = random_op2(arr1[random_f1(1, 2)]); - + if (m == Zero) { random_op0(q1, i); } } - + random_op3(q1, r1, p1); } } } } - + adjoint (...) { random_op0(q1, i1); random_op6(q1, p1); Adjoint random_op5(q1, p1); } - + controlled (c, ...) { random_op0(q1, i1); random_op4(q1, p1); Controlled random_op7(c, (q1, p1)); } - + controlled adjoint (c, ...) { random_op10(q1, i1); random_op8(q1, p1); Adjoint Controlled random_op9(c, (q1, p1)); } } - - + + function if_f0 () : Int { - + return 0; } - - + + operation ifOperation (i : Int, r : Result, p : Pauli) : Int { - + mutable n = 0; - + if (r == One) { set n = if_f0() * i; } - + if (p == PauliX) { return n; } else { return 0; } - + if (p == PauliX) { return n; } @@ -404,32 +404,32 @@ namespace Microsoft.Quantum.Testing { return p == PauliI ? 3 | if_f0(); } } - - + + function foreach_f2 (n1 : Int, n2 : Int) : Int { - + return n1 * n2; } - - + + operation foreachOperation (i : Int, r1 : Result) : Result { - + mutable result = 0; - + for (n in 0 .. i) { set result = result + i; } - + for (n in i .. -1 .. 0) { set result = (result - i) * 2; } - + let range = 0 .. 10; - + for (n in range) { set result = RangeEnd(range) + result + n * -foreach_f2(n, 4); } - + if (result > 10) { return One; } @@ -437,35 +437,35 @@ namespace Microsoft.Quantum.Testing { return Zero; } } - + newtype udt_args0 = Qubit[]; - + newtype udt_args1 = (Int, Qubit[]); - + newtype udt_args2 = (udt_args0 => udt_args1); - + newtype udt_args3 = (udt_args0 => udt_args1 is Ctl); - + newtype udt_args4 = (udt_args0 => udt_args1 is Adj); - + newtype udt_args5 = (udt_args0 => udt_args1 is Adj + Ctl); - + newtype udt_args1_0 = (Int, udt_args0); - + newtype udt_args1_1 = (Int, udt_args1); - + newtype udt_args1_2 = (Int, udt_args2); - + newtype udt_args2_0 = (Int, Result, udt_args0[]); - + newtype udt_args2_1 = (Int, Result, udt_args1[]); - + newtype udt_args2_2 = (Int, Result, udt_args2[]); - - - operation udtsTest + + + operation udtsTest ( - qubits : Qubit[], + qubits : Qubit[], u0 : Microsoft.Quantum.Overrides.udt0, u1 : udt_args1, u2 : udt_args2, @@ -481,7 +481,7 @@ namespace Microsoft.Quantum.Testing { op2_1 : (udt_args2_1 => Unit), op2_2 : (udt_args2_2 => Unit is Adj + Ctl), op_o : (Microsoft.Quantum.Overrides.udt0 => Unit) ) : udt_args1 { - + let args0 = udt_args0(qubits); let args1 = udt_args1(1, args0!); let args1a = op2(args0); @@ -497,96 +497,96 @@ namespace Microsoft.Quantum.Testing { op1(udt_args1(4, (udt_args0(qubits))!)); return udt_args1(22, qubits); } - - - + + + newtype returnUdt0 = (Int, Int); - + newtype returnUdt1 = (Int, Int)[]; - + newtype returnUdt3 = returnUdt0[]; - + function returnTest1 () : Unit { - + return (); } - - + + function returnTest2 () : Int { - + return 5; } - - + + function returnTest3 () : (Int, Int) { - + return (5, 6); } - - + + function returnTest4 () : returnUdt0 { - + return returnUdt0(7, 8); } - - + + function returnTest5 () : Int[] { - + return [9, 10]; } - - + + function returnTest6 () : returnUdt1 { - + return returnUdt1([(1, 2), (3, 4)]); } - - + + function returnTest7 () : returnUdt0[] { - + return [returnUdt0(1, 2), returnUdt0(3, 4)]; } - - + + function returnTest8 () : returnUdt3 { - + return returnUdt3([returnUdt0(1, 2), returnUdt0(3, 4)]); } - - + + function returnTest9 () : (returnUdt0, returnUdt1) { - + return (returnUdt0(7, 8), returnUdt1([(1, 2), (3, 4)])); } - - + + function returnTest10 () : Microsoft.Quantum.Overrides.udt0 { - + return Microsoft.Quantum.Overrides.udt0(Zero, One); } - + newtype repeat_udt0 = (Int, Qubit[]); - - + + operation repeat_op0 (info : repeat_udt0) : Result { body intrinsic; } - - + + operation repeat_op1 (index : Int, qubits : Qubit[]) : Result { body intrinsic; } - - + + operation repeat_op2 (angle : Double, info : repeat_udt0) : Result { body intrinsic; } - - + + operation repeatOperation (i : Int) : Unit { - + using (qubits = Qubit[i]) { - + repeat { mutable res = repeat_op0(repeat_udt0(0, qubits)); } @@ -596,32 +596,32 @@ namespace Microsoft.Quantum.Testing { } } } - - + + newtype udtTuple_1 = (Int, Qubit); - + newtype udtTuple_2 = (Int, (Qubit, Qubit)); - + operation udtTuple (i : Int, t1 : udtTuple_1, t2 : udtTuple_2, q : Qubit) : Unit { body intrinsic; } - - + + operation selfInvokingOperation (q1 : Qubit) : Unit { - + body (...) { Z(q1); } - + adjoint (...) { Adjoint Z(q1); selfInvokingOperation(q1); } } - - + + function factorial (x : Int) : Int { - + if (x == 1) { return 1; } @@ -629,60 +629,60 @@ namespace Microsoft.Quantum.Testing { return x * factorial(x - 1); } } - - + + function let_f0 (n : Int) : Range { body intrinsic; } - + newtype let_udt_1 = (Int, Qubit[]); - + newtype let_udt_2 = (let_udt_1 => Range is Adj + Ctl); - + newtype let_udt_3 = (let_udt_1 => let_udt_2); - - + + operation letsOperations (q1 : Qubit, n : Int, udts : (Microsoft.Quantum.Overrides.udt0, let_udt_1, let_udt_2, let_udt_3, (Qubit => Unit))) : Range { - + // Assigning from identifier: let q2 = q1; - + // Assigning from op result: let r = M(q1); - + // Assigning from literal: let i = 1.1; let iZero = 0; let dZero = 0.0; - + // Assigning from ranges: let a = 0 .. 10; let b = 8 .. -1 .. 5; - + // Assigning from expressions // Simple and complex: let j = n + 1; let k = ((n - 1) * (n ^ 2) / 3) % 4; - + // Deconstructing tuples: let t = (2.2, (3, One)); let (l, (m, o)) = t; let (p, q) = t; let (u0, u1, u2, u3, call1) = udts; let u = u3!(u1); - + // Deconstructing inside inner blocks: if (true) { let (l2, (m2, o2)) = t; return (u3!(u1))!(u1); } - + // Interpolated string literal let s = $"n is {n} and u is {u3!(u1)}, {r}, {n}, {j}"; let str = $"Hello{true ? "quantum" | ""} world!"; - + //let str2 = "more complicated stuff { true ? $"{n}" | "" }"; // to be fixed in the compilation builder... - + // Discarding variables: let (l3, _) = t; let (_, (_, o3)) = t; @@ -691,10 +691,10 @@ namespace Microsoft.Quantum.Testing { let _ = t; return let_f0(n); } - - + + function bitOperations (a : Int, b : Int) : Bool { - + let andEx = a &&& b; let orEx = a ||| b; let xorEx = a ^^^ b; @@ -702,7 +702,7 @@ namespace Microsoft.Quantum.Testing { let right = a >>> b; let negation = ~~~a; let total = ((((andEx + orEx) + xorEx) + left) + right) + negation; - + if (total > 0) { return true; } @@ -710,15 +710,15 @@ namespace Microsoft.Quantum.Testing { return false; } } - + newtype arrays_T1 = Pauli[]; - + newtype arrays_T2 = (Pauli[], Int[]); - + newtype arrays_T3 = Result[][]; - + operation arraysOperations (qubits : Qubit[], register : Qubits, indices : Range[][], t : arrays_T3) : Result[][] { - + // Creating/Assigning arrays let q = qubits; let r1 = [Zero]; @@ -739,7 +739,7 @@ namespace Microsoft.Quantum.Testing { let r16 = qubits[1 .. -1]; let r18 = new Qubits[2]; let r19 = new Microsoft.Quantum.Overrides.udt0[7]; - + // Accessing array items: let i0 = ((r13!)[0])[1]; let i1 = r2[0 + Length(r1)]; @@ -749,7 +749,7 @@ namespace Microsoft.Quantum.Testing { let i5 = (indices[0])[1]; let i6 = (t!)[0]; let i7 = (register!)[3]; - + // Lengths: let l0 = Length(qubits); let l1 = Length(indices); @@ -761,16 +761,16 @@ namespace Microsoft.Quantum.Testing { return [[i0, One], [Zero]]; } - - + + function GetMeARange () : Range { - + return 0 .. 1; } - - + + operation sliceOperations (qubits : Qubit[], option : Int) : Qubit[] { - + let r2 = 10 .. -2 .. 0; let ranges = new Range[1]; let s1 = qubits[0 .. 10]; @@ -781,7 +781,7 @@ namespace Microsoft.Quantum.Testing { return qubits[10 .. -3 .. 0]; } - + operation rangeOperations (r: Range) : Int { return RangeStart(r) + RangeEnd(r) + RangeStep(r); @@ -789,32 +789,32 @@ namespace Microsoft.Quantum.Testing { function call_target1 ( - i : Int, - plain : (Qubit => Unit), - adj : (Qubit => Unit is Adj), - ctr : (Qubit => Unit is Ctl), + i : Int, + plain : (Qubit => Unit), + adj : (Qubit => Unit is Adj), + ctr : (Qubit => Unit is Ctl), uni : (Qubit => Unit is Adj + Ctl) ) : Unit { } - - - function call_target2 + + + function call_target2 ( - i : Int, plain : (Result, (Qubit => Unit)), - adj : (Result, (Qubit => Unit is Adj)), - ctr : (Result, (Qubit => Unit is Ctl)), + i : Int, plain : (Result, (Qubit => Unit)), + adj : (Result, (Qubit => Unit is Adj)), + ctr : (Result, (Qubit => Unit is Ctl)), uni : (Result, (Qubit => Unit is Adj + Ctl)) ) : Unit { } - + newtype call_plain = (Qubit => Unit); - + newtype call_adj = (Qubit => Unit is Adj); - + newtype call_ctr = (Qubit => Unit is Ctl); - + newtype call_uni = (Qubit => Unit is Adj + Ctl); - + operation callTests (qubits : Qubits) : Unit { - + let plain = call_plain(X); let adj = call_adj(X); let ctr = call_ctr(X); @@ -827,120 +827,120 @@ namespace Microsoft.Quantum.Testing { call_target2(1, (Zero, X), (Zero, X), (Zero, X), (Zero, X)); call_target2(2, (One, plain!), (One, adj!), (One, ctr!), (One, uni!)); } - - + + operation helloWorld (n : Int) : Int { - + let r = n + 1; return r; } - - + + operation alloc_op0 (q1 : Qubit) : Unit { body intrinsic; } - - + + operation allocOperation (n : Int) : Unit { - + body (...) { using (q = Qubit()) { let flag = true; (flag ? X | Z)(q); alloc_op0(q); } - + using (qs = Qubit[n]) { alloc_op0(qs[n - 1]); } - + using ((q1, (q2, (_, q3, _, q4))) = (Qubit(), ((Qubit(), Qubit[2]), (Qubit(), Qubit[n], Qubit[n - 1], Qubit[4])))) { alloc_op0(q1); alloc_op0(q3[1]); } } - + adjoint (...) { borrowing (b = Qubit[n]) { alloc_op0(b[n - 1]); } - + borrowing ((q1, (q2, (_, q3))) = (Qubit(), (Qubit[2], (Qubit(), (Qubit[n], Qubit[4]))))) { - + using (qt = (Qubit(), (Qubit[1], Qubit[2]))) { let (qt1, qt2) = qt; alloc_op0(qt1); } - + alloc_op0(q1); alloc_op0(q2[1]); } } } - - + + operation failedOperation (n : Int) : Int { - + fail "This operation should never be called."; return 1; } - - + + operation compareOps (n : Int) : Bool { - + let lt = n < 1; let lte = n <= 2; let gt = n > 3; let gte = n >= 4; return (lt == (lte and gt)) != gte or not lt; } - - + + operation partialGeneric1<'A, 'B> (a : 'A, b : 'B, c : ('A, 'B)) : Unit { body intrinsic; } - - + + operation partialGeneric2<'A, 'B, 'C, 'D> (a : 'A, b : 'B, c : ('C, 'D)) : Unit { body intrinsic; } - - + + operation partial1Args (a : Int) : Unit { body intrinsic; } - - + + operation partialInnerTuple (a : Int, b : (Double, Result)) : Unit { body intrinsic; } - - + + operation partial3Args (a : Int, b : Double, c : Result) : Unit { body intrinsic; } - - + + operation partialNestedArgsOp (a : (Int, Int, Int), b : ((Double, Double), (Result, Result, Result))) : Unit { body intrinsic; } - - + + function partialFunction (a : Int, b : Double, c : Pauli) : Result { return Zero; } - - + + // TODO: (partial1Args (_))(1); - operation partialApplicationTest + operation partialApplicationTest ( - i : Int, res : Result, - partialInput : ((Int, (Double, Double), (Result, Result, Result)) => Unit), + i : Int, res : Result, + partialInput : ((Int, (Double, Double), (Result, Result, Result)) => Unit), partialUnitary : ((Double, ((Int, Double) -> Result), Qubit[]) => Unit is Adj + Ctl) ) : (Qubit[] => Unit is Adj + Ctl) { - + (partial3Args(_, _, _))(1, 3.5, One); (partial3Args(1, _, Zero))(3.5); (partial3Args(_, 3.5, _))(1, Zero); @@ -964,37 +964,37 @@ namespace Microsoft.Quantum.Testing { (partialInput(1, (_, 1.1), (Zero, _, _)))(2.2, (One, One)); return partialUnitary(1.1, partialFunction(_, _, PauliX), _); } - + newtype Q = Qubit; - + newtype U = (Qubit => Unit is Adj + Ctl); - + newtype A = (Int -> Int[]); - + newtype B = (Int[] -> U); - + newtype C = (Int, A); - + newtype D = (Int[] -> U); - + newtype E = (Double -> C); - + newtype F = (D, E); - + newtype G = ((Double, F, Qubit[]) => Unit is Adj + Ctl); - + newtype AA = A; - + newtype QQ = Q; - - function partialFunctionTest + + function partialFunctionTest ( start : Double, t1 : (A, D), t2 : (B, E), op : G ) : (Qubit[] => Unit is Adj + Ctl) { - + let r1 = (partialFunction(_, _, _))(2, 2.2, PauliY); let r2 = ((partialFunction(1, _, _))(3.3, _))(PauliZ); let (a, d) = t1; @@ -1002,13 +1002,13 @@ namespace Microsoft.Quantum.Testing { let f = F(d, e); return op!(start, f, _); } - - + + operation OP_1 (q : Qubit) : Result { body intrinsic; } - - + + operation opParametersTest ( q1 : Qubit, @@ -1018,7 +1018,7 @@ namespace Microsoft.Quantum.Testing { t1 : (((Qubit[], (Qubit, Qubit)) => Unit is Ctl), ((Qubit[], (Qubit, Qubit)) => Unit is Adj + Ctl)), f1 : (Double -> Double) ) : (Qubit => Unit) { - + op1(OP_1); let v0 = op0; let r0 = v0(q1); @@ -1026,35 +1026,35 @@ namespace Microsoft.Quantum.Testing { op3([q1], (q1, q1)); return op2(q1, _); } - - + + operation With1C (outerOperation : (Qubit => Unit is Adj), innerOperation : (Qubit => Unit is Ctl), target : Qubit) : Unit { - + body (...) { outerOperation(target); innerOperation(target); Adjoint outerOperation(target); } - + controlled (controlRegister, ...) { outerOperation(target); Controlled innerOperation(controlRegister, target); Adjoint outerOperation(target); } } - - + + operation measureWithScratch (pauli : Pauli[], target : Qubit[]) : Result { - + mutable result = Zero; - + using (scratchRegister = Qubit[1]) { let scratch = scratchRegister[0]; - + for (idxPauli in 0 .. Length(pauli) - 1) { let P = pauli[idxPauli]; let src = [target[idxPauli]]; - + if (P == PauliX) { Controlled X(src, scratch); } @@ -1065,30 +1065,30 @@ namespace Microsoft.Quantum.Testing { Controlled (With1C(Microsoft.Quantum.Intrinsic.H, X, _))(src, scratch); } } - + set result = M(scratch); } - + return result; } - - + + operation noOpResult (r : Result) : Unit { - + body (...) { } - + adjoint invert; controlled distribute; controlled adjoint distribute; } - - + + operation noOpGeneric<'T> (r : 'T) : Unit { - + body (...) { } - + adjoint invert; controlled distribute; controlled adjoint distribute; @@ -1098,7 +1098,7 @@ namespace Microsoft.Quantum.Testing { { op(arg); } - + function iter<'T, 'U> (mapper : ('T -> 'U), source : 'T[]) : Unit { for (i in source) { let v = mapper(i); @@ -1122,16 +1122,16 @@ namespace Microsoft.Quantum.Intrinsic { namespace Microsoft.Quantum.Core { - function Length<'T> (a : 'T[]) : Int { - body intrinsic; + function Length<'T> (a : 'T[]) : Int { + body intrinsic; } - - function RangeStart (range : Range) : Int { + + function RangeStart (range : Range) : Int { body intrinsic; } - - + + function RangeEnd (range : Range) : Int { body intrinsic; } @@ -1145,92 +1145,92 @@ namespace Microsoft.Quantum.Core namespace Microsoft.Quantum.Compiler.Generics { - + open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Testing; - - + + function genF1<'A> (arg : 'A) : Unit { body intrinsic; } - - + + operation genMapper<'T, 'U> (mapper : ('T => 'U), source : 'T[]) : 'U[] { - + mutable result = new 'U[Length(source)]; - + for (i in 0 .. Length(source) - 1) { let m = mapper(source[i]); - set result = result w/ i <- m; + set result = result w/ i <- m; } - + return result; } - - + + operation genIter<'T> (callback : ('T => Unit is Adj + Ctl), source : 'T[]) : Unit { - + body (...) { for (i in 0 .. Length(source) - 1) { callback(source[i]); } } - + adjoint invert; controlled distribute; controlled adjoint distribute; } - - + + operation genC1<'T> (a1 : 'T) : Unit { body intrinsic; } - - + + operation genC1a<'T> (a1 : 'T) : 'T { body intrinsic; } - - + + operation genC2<'T, 'U> (a1 : 'T) : 'T { body intrinsic; } - - + + operation genAdj1<'T> (a1 : 'T) : Unit { body intrinsic; adjoint self; } - - + + operation genU1<'T> (a1 : 'T) : Unit { - + body (...) { let x = genC2<'T, Unit>(a1); } - + adjoint (...) { } controlled (c, ...) { } controlled adjoint (c, ...) { } } - - + + operation genCtrl3<'X, 'Y, 'Z> (arg1 : 'X, arg2 : (Int, ('Y, 'Z), Result)) : Unit { body intrinsic; controlled intrinsic; } - - + + operation genU2<'A, 'B> (a1 : 'A, t1 : ('A, 'B), i : Int) : Unit { body intrinsic; adjoint intrinsic; controlled intrinsic; controlled adjoint intrinsic; } - - + + operation ResultToString (v : Result) : String { - + if (v == One) { return "uno"; } @@ -1238,14 +1238,14 @@ namespace Microsoft.Quantum.Compiler.Generics { return "zero"; } } - - + + operation usesGenerics () : Unit { - + let a = [One, Zero, Zero]; let s = [ResultToString(a[0]), ResultToString(a[1])]; noOpResult(a[0]); - + using (qubits = Qubit[3]) { let op = Hold(CNOT, (qubits[0], qubits[1]),_); @@ -1255,28 +1255,28 @@ namespace Microsoft.Quantum.Compiler.Generics { noOpGeneric(a[0]); genIter(X, qubits); } - + genIter(noOpResult, a); genIter(genU1, genMapper(ResultToString, a)); genIter(genU1, s); genIter(genU1, a); } - - + + operation composeImpl<'A, 'B> (second : ('A => Unit), first : ('B => 'A), arg : 'B) : Unit { - + second(first(arg)); } - - + + operation compose<'A, 'B> (second : ('A => Unit), first : ('B => 'A)) : ('B => Unit) { - + return composeImpl(second, first, _); } - - + + function genRecursion<'T> (x : 'T, cnt : Int) : 'T { - + if (cnt == 0) { return x; } @@ -1284,12 +1284,12 @@ namespace Microsoft.Quantum.Compiler.Generics { return genRecursion(x, cnt - 1); } } - - + + function MapDefaults<'C, 'B> (map : ('C -> 'C), l : Int) : Unit { - + mutable arr = new 'C[l]; - + for (i in 0 .. l - 1) { set arr = arr w/ i <- map(arr[i]); } @@ -1299,14 +1299,16 @@ namespace Microsoft.Quantum.Compiler.Generics { newtype MyType2 = (i1 : Int, i2 : MyType1, (i3 : Int[], i4 : String)); function UpdateUdtItems (udt : MyType2) : MyType2 { - + mutable arr = new Int[10]; return udt w/ i1 <- -5 - w/ i3 <- arr - w/ i1 <- 1; + w/ i3 <- arr + w/ i1 <- 1; } + newtype NamedTuple = (FirstItem: (Int, Double), SecondItem: Int); + // Access Modifiers internal function EmptyInternalFunction () : Unit { } diff --git a/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs b/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs index 6605b571cd2..31fb2e62e04 100644 --- a/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs +++ b/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs @@ -35,9 +35,9 @@ module SimulationCode = let ``Pure roslyn``() = let code = " namespace N1 - { + { enum E { A, b, C } - + public class C1 { public object P1 {get;set;} @@ -63,8 +63,8 @@ namespace N1 Assert.Equal(expected |> clearFormatting, actual |> clearFormatting) [] - let ``doubles in different locales`` () = - let cases = + let ``doubles in different locales`` () = + let cases = [ 1.1, "1.1D" 1000.001, "1000.001D" @@ -93,42 +93,42 @@ namespace N1 | DiagnosticSeverity.Error -> errors <- diag :: errors | _ -> () let addSourceFile (mgr:CompilationUnitManager) fileName = - let fileId = new Uri(Path.GetFullPath fileName) + let fileId = new Uri(Path.GetFullPath fileName) let file = CompilationUnitManager.InitializeFileManager(fileId, File.ReadAllText fileName) mgr.AddOrUpdateSourceFileAsync file |> ignore // TODO: catch compilation errors and fail let mgr = new CompilationUnitManager(null, fun ps -> ps.Diagnostics |> Array.iter addError) files |> List.iter (addSourceFile mgr) try let mutable compilation = mgr.Build().BuiltCompilation - if not errors.IsEmpty then - errors + if not errors.IsEmpty then + errors |> List.map (fun e -> sprintf "%s at %s, line %d" e.Message e.Source (e.Range.Start.Line + 1)) |> String.concat "\n" - |> failwith + |> failwith let functorGenSuccessful = CodeGeneration.GenerateFunctorSpecializations(compilation, &compilation) // todo: we might want to raise an error here if the functor generation fails (which will be the case for incorrect code) compilation.Namespaces with | e -> sprintf "compilation threw exception: \n%s" e.Message |> failwith // should never happen (all exceptions are caught by the compiler) - + let syntaxTree = parse [ (Path.Combine("Circuits", "Intrinsic.qs")); (Path.Combine("Circuits", "CodegenTests.qs")) ] let globalContext = CodegenContext.Create syntaxTree - let findCallable name = + let findCallable name = let key = NonNullable.New name - match globalContext.byName.TryGetValue key with + match globalContext.byName.TryGetValue key with | true, v -> v |> List.sort |> List.head - | false, _ -> sprintf "no callable with name %s has been successfully compiled" name |> failwith + | false, _ -> sprintf "no callable with name %s has been successfully compiled" name |> failwith let findUdt name = let key = globalContext.allUdts.Keys |> Seq.sort |> Seq.find (fun n -> n.Name.Value = name) - match globalContext.allUdts.TryGetValue key with - | true, v -> key.Namespace, v - | false, _ -> sprintf "no type with name %s has been successfully compiled" name |> failwith + match globalContext.allUdts.TryGetValue key with + | true, v -> key.Namespace, v + | false, _ -> sprintf "no type with name %s has been successfully compiled" name |> failwith //// // Create some operations for our tests... - //// + //// let emptyOperation = findCallable @"emptyOperation" let zeroQubitOperation = findCallable @"zeroQubitOperation" let oneQubitAbstractOperation = findCallable @"oneQubitAbstractOperation" @@ -153,7 +153,7 @@ namespace N1 let failedOperation = findCallable @"failedOperation" let compareOps = findCallable @"compareOps" let partialApplicationTest = findCallable @"partialApplicationTest" - let opParametersTest = findCallable @"opParametersTest" + let opParametersTest = findCallable @"opParametersTest" let measureWithScratch = findCallable @"measureWithScratch" let with1C = findCallable @"With1C" let genC1 = findCallable @"genC1" @@ -170,11 +170,11 @@ namespace N1 let nestedArgTuple1 = findCallable @"nestedArgTuple1" let nestedArgTuple2 = findCallable @"nestedArgTuple2" let nestedArgTupleGeneric = findCallable @"nestedArgTupleGeneric" - let udtsTest = findCallable @"udtsTest" - let compose = findCallable @"compose" - let composeImpl = findCallable @"composeImpl" - let callTests = findCallable @"callTests" - let udtTuple = findCallable @"udtTuple" + let udtsTest = findCallable @"udtsTest" + let compose = findCallable @"compose" + let composeImpl = findCallable @"composeImpl" + let callTests = findCallable @"callTests" + let udtTuple = findCallable @"udtTuple" let emptyFunction = findCallable @"emptyFunction" let intFunction = findCallable @"intFunction" let powFunction = findCallable @"powFunction" @@ -212,6 +212,7 @@ namespace N1 let udt_Complex = findUdt @"udt_Complex" let udt_TwoDimArray = findUdt @"udt_TwoDimArray" let udt_InternalType = findUdt @"InternalType" + let udt_NamedTuple = findUdt @"NamedTuple" let createTestContext op = globalContext.setCallable op @@ -220,59 +221,59 @@ namespace N1 let expected = expected.Replace("%%%", (Uri(Path.GetFullPath fileName)).AbsolutePath) let expected = expected.Replace("%%", (Path.GetFullPath fileName).Replace("\\", "\\\\")) let tree = parse [(Path.Combine("Circuits","Intrinsic.qs")); fileName] - let actual = + let actual = CodegenContext.Create (tree, ImmutableDictionary.Empty) |> generate (Path.GetFullPath fileName |> NonNullable.New) Assert.Equal(expected |> clearFormatting, actual |> clearFormatting) let testOneBody (builder:SyntaxBuilder) (expected: string list) = - let actual = + let actual = builder.BuiltStatements |> List.map (fun s -> s.ToFullString()) Assert.Equal(expected.Length, actual.Length) List.zip (expected |> List.map clearFormatting) (actual |> List.map clearFormatting) |> List.iter Assert.Equal - + let testOneList op (build: CodegenContext -> 'X -> 'Y List) (arg: 'X) (clean: 'Y -> 'Z) (expected: 'Z list) = let context = createTestContext op - let actual = + let actual = arg |> build context |> List.map clean - List.zip expected actual + List.zip expected actual |> List.iter Assert.Equal<'Z> [] let ``tupleBaseClassName test`` () = let testOne (_, udt) expected = let context = (CodegenContext.Create syntaxTree).setUdt udt - let actual = tupleBaseClassName context udt.Type + let actual = tupleBaseClassName context udt.Type Assert.Equal (expected |> clearFormatting, actual |> clearFormatting) - + "QTuple>" |> testOne udt_args0 - + "QTuple<(Int64, IQArray)>" - |> testOne udt_args1 - + |> testOne udt_args1 + "QTuple" |> testOne udt_A - + "QTuple" |> testOne udt_AA "QTuple" |> testOne udt_U - + "QTuple" |> testOne udt_Q - + "QTuple" |> testOne udt_Real - + "QTuple<(udt_Real,udt_Real)>" |> testOne udt_Complex - + "QTuple>>" |> testOne udt_TwoDimArray @@ -287,14 +288,14 @@ namespace N1 let testOne (_,op) expected = let context = createTestContext op let sortByNames l = l |> List.sortBy (fun ((n,_),_) -> n) |> List.sortBy (fun ((_,ns),_) -> ns) - let actual = + let actual = op |> operationDependencies |> List.map (fun n -> ((n.Namespace.Value, n.Name.Value), (n |> roslynCallableTypeName context))) - + List.zip (expected |> sortByNames) (actual |> sortByNames) |> List.iter Assert.Equal - + [] |> testOne emptyOperation @@ -306,21 +307,21 @@ namespace N1 ((NS2, "R" ), "IAdjointable<(Double,Qubit)>") ] |> testOne twoQubitOperation - + [ ((NS1,"three_op1"), "IUnitary<(Qubit,Qubit)>") ] |> testOne threeQubitOperation - + [] |> testOne randomAbstractOperation - + [ ((NS2, "Z"), "IUnitary") ((NS1, "selfInvokingOperation"), "IAdjointable") ] |> testOne selfInvokingOperation - + [ ((NSG, "genRecursion"), "ICallable") ] @@ -331,7 +332,7 @@ namespace N1 ((NS1, "let_f0" ), "ICallable") ] |> testOne letsOperations - + [] |> testOne helloWorld @@ -348,7 +349,7 @@ namespace N1 [] |> testOne failedOperation - + [] |> testOne compareOps @@ -369,9 +370,9 @@ namespace N1 ((NS1, "repeat_op0"), "ICallable") ((NS1, "repeat_op1"), "ICallable<(Int64,IQArray), Result>") ((NS1, "repeat_op2"), "ICallable<(Double,repeat_udt0), Result>") - ((NS1, "repeat_udt0"), "ICallable<(Int64,IQArray), repeat_udt0>") + ((NS1, "repeat_udt0"), "ICallable<(Int64,IQArray), repeat_udt0>") ] - |> testOne repeatOperation + |> testOne repeatOperation [ ((NS1, "partial3Args"), "ICallable<(Int64,Double,Result), QVoid>") @@ -382,12 +383,12 @@ namespace N1 ((NS1, "partialNestedArgsOp"), "ICallable<((Int64,Int64,Int64),((Double,Double),(Result,Result,Result))), QVoid>") ] |> testOne partialApplicationTest - + [ ((NS1, "OP_1"), "ICallable") ] |> testOne opParametersTest - + [ ((NS2, "Allocate" ), "Allocate") ((NS2, "Borrow" ), "Borrow") @@ -407,9 +408,9 @@ namespace N1 ((NS1, "random_op8" ), "ICallable<(Qubit,Pauli), QVoid>") ((NS1, "random_op9" ), "IUnitary<(Qubit,Pauli)>") ] - |> testOne randomOperation - - [ + |> testOne randomOperation + + [ ((NS2, "Allocate" ), "Allocate") ((NS2, "H" ), "IUnitary") ((NSC, "Length" ), "ICallable") @@ -420,18 +421,18 @@ namespace N1 ((NS2, "X" ), "IUnitary") ] |> testOne measureWithScratch - + [] |> testOne genC1 - + [ ((NSG, "genC2" ), "ICallable") ] |> testOne genU1 - + [] |> testOne genCtrl3 - + [ ((NS2, "Allocate" ), "Allocate") ((NS2, "CNOT" ), "IAdjointable<(Qubit,Qubit)>") @@ -445,7 +446,7 @@ namespace N1 ((NS1, "noOpGeneric" ), "IUnitary") ((NS1, "noOpResult" ), "IUnitary") ] - |> testOne usesGenerics + |> testOne usesGenerics [ ((NS2, "Allocate" ), "Allocate") @@ -455,23 +456,23 @@ namespace N1 ((NS1, "emptyFunction" ), "ICallable") ((NSO, "emptyFunction" ), "ICallable") ] - |> testOne duplicatedDefinitionsCaller - + |> testOne duplicatedDefinitionsCaller + [ ((NS1, "iter"), "ICallable") ((NSC, "Length"), "ICallable") ] |> testOne testLengthDependency - + [] let ``flatArgumentsList test`` () = - let testOne (_, op: QsCallable) (expectedArgs: (string * string) list) = + let testOne (_, op: QsCallable) (expectedArgs: (string * string) list) = testOneList op flatArgumentsList op.ArgumentTuple id expectedArgs [] |> testOne emptyOperation - + [ ("n", "Int64") ] @@ -481,14 +482,14 @@ namespace N1 ("q1", "Qubit") ] |> testOne oneQubitAbstractOperation - + [ "q1", "Qubit" "t1", "(Qubit,Double)" ] |> testOne twoQubitOperation - - + + [ "q1", "Qubit" "q2", "Qubit" @@ -499,11 +500,11 @@ namespace N1 [ "q1", "Qubit" "b", "Basis" - "t", "(Pauli,IQArray>,Boolean)" + "t", "(Pauli,IQArray>,Boolean)" "i", "Int64" ] |> testOne randomAbstractOperation - + [ "a", "Int64" "b", "Int64" @@ -511,7 +512,7 @@ namespace N1 "d", "Double" ] |> testOne nestedArgTuple1 - + [ "a", "(Int64,Int64)" "c", "Double" @@ -520,7 +521,7 @@ namespace N1 "e", "Double" ] |> testOne nestedArgTuple2 - + [ "outerOperation", "IAdjointable" "innerOperation", "IControllable" @@ -532,33 +533,33 @@ namespace N1 "a1", "__T__" ] |> testOne genC1 - + [ "arg1", "__X__" "arg2", "(Int64,(__Y__,__Z__),Result)" ] |> testOne genCtrl3 - + [ "second", "ICallable" "first", "ICallable" "arg", "__B__" ] |> testOne composeImpl - + [ "mapper", "ICallable" "source", "IQArray<__T__>" ] |> testOne genMapper - + [] let ``findQubitFields test`` () = let testOne (_,op) = testOneList op findQubitFields op.Signature.ArgumentType (snd >> formatSyntaxTree) [] |> testOne emptyOperation - + [] |> testOne helloWorld @@ -566,28 +567,28 @@ namespace N1 "Data" ] |> testOne oneQubitAbstractOperation - + [ "Data.Item1" "Data.Item2.Item1" ] |> testOne twoQubitOperation - - + + [ "Data.Item1" "Data.Item2" "Data.Item3?.Data" ] |> testOne threeQubitOperation - + [ "Data.Item1" "Data.Item2" "Data.Item3" ] |> testOne differentArgsOperation - + [ "Data.Item1" ] @@ -597,7 +598,7 @@ namespace N1 "Data.Item1" ] |> testOne randomAbstractOperation - + [ ] |> testOne nestedArgTuple1 @@ -607,19 +608,19 @@ namespace N1 "Data.Item2.Item2.Item2.Item2" ] |> testOne nestedArgTuple2 - + [ "Data" ] |> testOne genU1 - + [ "Data.Item1" "Data.Item2.Item2.Item1" "Data.Item2.Item2.Item2" ] |> testOne genCtrl3 - + [ "Data.Item2?.Data.Item2" "Data.Item3?.Data.Item2.Item1" @@ -630,7 +631,7 @@ namespace N1 [] |> testOne emptyFunction - + [ "Data.Item2.Item1?.Data" "Data.Item2.Item2?.Data" @@ -639,7 +640,7 @@ namespace N1 "Data.Item4?.Data" ] |> testOne partialFunctionTest - + [] let ``buildQubitsField test`` () = let testOne (_,op) expected = testOneList op buildQubitsField op.Signature.ArgumentType (formatSyntaxTree >> clearFormatting) (expected |> List.map clearFormatting) @@ -648,7 +649,7 @@ namespace N1 "System.Collections.Generic.IEnumerable IApplyData.Qubits => null;" ] |> testOne emptyOperation - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits => null;" ] @@ -664,7 +665,7 @@ namespace N1 }" ] |> testOne oneQubitAbstractOperation - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits { @@ -676,38 +677,38 @@ namespace N1 }" ] |> testOne twoQubitOperation - - + + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits { get { return Qubit.Concat( - ((IApplyData)Data.Item1)?.Qubits, - ((IApplyData)Data.Item2)?.Qubits, + ((IApplyData)Data.Item1)?.Qubits, + ((IApplyData)Data.Item2)?.Qubits, ((IApplyData)Data.Item3?.Data)?.Qubits ); } }" ] |> testOne threeQubitOperation - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits { get { return Qubit.Concat( - ((IApplyData)Data.Item1)?.Qubits, - ((IApplyData)Data.Item2)?.Qubits, + ((IApplyData)Data.Item1)?.Qubits, + ((IApplyData)Data.Item2)?.Qubits, ((IApplyData)Data.Item3)?.Qubits ); } }" ] |> testOne differentArgsOperation - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits { @@ -718,7 +719,7 @@ namespace N1 }" ] |> testOne randomOperation - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits => null;" ] @@ -735,7 +736,7 @@ namespace N1 }" ] |> testOne nestedArgTuple2 - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits @@ -750,14 +751,14 @@ namespace N1 }" ] |> testOne udtTuple - + [ - "System.Collections.Generic.IEnumerable IApplyData.Qubits + "System.Collections.Generic.IEnumerable IApplyData.Qubits { get { return Qubit.Concat( - ((IApplyData)Data.Item1)?.Qubits, + ((IApplyData)Data.Item1)?.Qubits, ((IApplyData)Data.Item3.Item2?.Data.Item2)?.Qubits, ((IApplyData)Data.Item3.Item3?.Data)?.Qubits, ((IApplyData)Data.Item3.Item4?.Data)?.Qubits, @@ -767,7 +768,7 @@ namespace N1 }" ] |> testOne letsOperations - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits { @@ -780,7 +781,7 @@ namespace N1 ] |> testOne genU1 - + [ "System.Collections.Generic.IEnumerable IApplyData.Qubits { @@ -790,8 +791,8 @@ namespace N1 var __temp2__ = Data.Item2.Item2.Item1; var __temp3__ = Data.Item2.Item2.Item2; return Qubit.Concat( - __temp1__?.GetQubits(), - __temp2__?.GetQubits(), + __temp1__?.GetQubits(), + __temp2__?.GetQubits(), __temp3__?.GetQubits() ); } @@ -803,43 +804,43 @@ namespace N1 let ``areAllQubitArgs test`` () = let testOne (_,op) expected = let context = createTestContext op - let actual = + let actual = op.Signature.ArgumentType |> findQubitFields context |> List.map fst |> areAllQubitArgs - Assert.Equal (expected, actual) + Assert.Equal (expected, actual) true |> testOne emptyOperation - + true |> testOne helloWorld true |> testOne oneQubitAbstractOperation - + true |> testOne twoQubitOperation - + false |> testOne threeQubitOperation - + false |> testOne differentArgsOperation - + true |> testOne randomOperation true |> testOne randomAbstractOperation - + true |> testOne nestedArgTuple1 true |> testOne nestedArgTuple2 - + let depsByName (l : QsQualifiedName list) = l |> List.sortBy (fun n -> n.Namespace.Value) |> List.sortBy (fun n -> n.Name.Value) @@ -856,11 +857,11 @@ namespace N1 [ ] |> testOne emptyOperation - + [ ] |> testOne oneQubitAbstractOperation - + [ ] |> testOne genU2 @@ -874,7 +875,7 @@ namespace N1 template "emptyFunction" "ICallable" "emptyFunction" ] |> testOne duplicatedDefinitionsCaller - + [ template "Allocate" "Allocate" "Microsoft.Quantum.Intrinsic.Allocate" template "CNOT" "IAdjointable<(Qubit, Qubit)>" "Microsoft.Quantum.Intrinsic.CNOT" @@ -889,28 +890,28 @@ namespace N1 template "MicrosoftQuantumTestingnoOpResult" "IUnitary" "Microsoft.Quantum.Testing.noOpResult" ] |> testOne usesGenerics - + [ template "Z" "IUnitary" "Microsoft.Quantum.Intrinsic.Z" "this.self = this;" ] |> testOne selfInvokingOperation - + [ template "self" "ICallable" "genRecursion<>" ] |> testOne genRecursion - + [] let ``getTypeOfOp test`` () = let testOne (_,op) = let dependendies context d = operationDependencies d |> List.map (getTypeOfOp context) - |> List.map formatSyntaxTree + |> List.map formatSyntaxTree |> List.sort testOneList op dependendies op id - + let template = sprintf "typeof(%s)" [ template "Microsoft.Quantum.Intrinsic.Allocate" @@ -927,12 +928,12 @@ namespace N1 ] |> List.sort |> testOne usesGenerics - + [ template "composeImpl<,>" ] |> testOne compose - + [ template "genRecursion<>" ] @@ -948,7 +949,7 @@ namespace N1 let ``buildOpsProperties test`` () = let testOne (_,op) expected = let context = createTestContext op - let actual = + let actual = op |> operationDependencies |> depsByName @@ -972,13 +973,13 @@ namespace N1 template "IUnitary" "MicrosoftQuantumTestingnoOpResult" ] |> testOne usesGenerics - + [ template "IUnitary" "Z" template "IAdjointable" "self" ] |> testOne selfInvokingOperation - + [ template "ICallable" "self" ] @@ -1026,19 +1027,19 @@ namespace N1 template "QVoid" "QVoid" "emptyFunction" |> testOne emptyFunction - let findBody op = + let findBody op = let isBody (sp:QsSpecialization) = match sp.Kind with | QsBody -> true | _ -> false (op.Specializations |> Seq.find isBody) - let findAdjoint op = + let findAdjoint op = let isAdjoint (sp:QsSpecialization) = match sp.Kind with | QsAdjoint -> true | _ -> false (op.Specializations |> Seq.find isAdjoint) - let findControlled op = + let findControlled op = let isControlled (sp:QsSpecialization) = match sp.Kind with | QsControlled -> true | _ -> false (op.Specializations |> Seq.find isControlled) - let findControlledAdjoint op = + let findControlledAdjoint op = let isControlledAdjoint (sp:QsSpecialization) = match sp.Kind with | QsControlledAdjoint -> true | _ -> false (op.Specializations |> Seq.find isControlledAdjoint) @@ -1046,7 +1047,7 @@ namespace N1 let context = createTestContext op let builder = new SyntaxBuilder(context) builder.Namespaces.OnSpecializationDeclaration sp |> ignore - builder + builder let applyVisitor (ns,op) = createVisitor (ns,op) (findBody op) @@ -1057,7 +1058,7 @@ namespace N1 let controlledVisitor (ns,op) = createVisitor (ns,op) (findControlled op) - + [] let ``basic body builder`` () = let testOne = testOneBody @@ -1070,7 +1071,7 @@ namespace N1 "X.Apply(q1);" ] |> testOne (applyVisitor oneQubitOperation) - + [ "X.Adjoint.Apply(q1);" ] @@ -1101,16 +1102,16 @@ namespace N1 "self.Apply(q1);" ] |> testOne (adjointVisitor selfInvokingOperation) - + [] let ``recursive functions body`` () = let testOne = testOneBody - + [ """ if ((cnt == 0L)) { - return x; + return x; } else { @@ -1124,7 +1125,7 @@ namespace N1 """ if ((x == 1L)) { - return 1L; + return 1L; } else { @@ -1133,30 +1134,30 @@ namespace N1 """ ] |> testOne (applyVisitor factorial) - + [] let ``generic functions body`` () = let testOne = testOneBody - + [ "X.Apply(q1);" ] |> testOne (applyVisitor oneQubitOperation) - + [] let ``composed generic body`` () = let testOne = testOneBody - + [ "second.Apply(first.Apply<__A__>(arg));" ] |> testOne (applyVisitor composeImpl) - + [ "return composeImpl.Partial((second, first, _));" ] |> testOne (applyVisitor compose) - + [] let ``usesGenerics body`` () = @@ -1164,7 +1165,7 @@ namespace N1 "var a = (IQArray)new QArray(Result.One, Result.Zero, Result.Zero);" "var s = (IQArray)new QArray(ResultToString.Apply(a[0L]), ResultToString.Apply(a[1L]));" "MicrosoftQuantumTestingnoOpResult.Apply(a[0L]);" - + """ { var qubits = Allocate.Apply(3L); @@ -1181,7 +1182,7 @@ namespace N1 } #line hidden catch - { + { __arg1__ = false; throw; } @@ -1219,7 +1220,7 @@ namespace N1 "call_target1.Apply((1L, X, X, X, X));" "call_target1.Apply((1L, plain.Data, adj.Data, ctr.Data, uni.Data));" - + "call_target2.Apply((1L, (Result.Zero, X), (Result.Zero, X), (Result.Zero, X), (Result.Zero, X)));" "call_target2.Apply((2L, (Result.One, plain.Data), (Result.One, adj.Data), (Result.One, ctr.Data), (Result.One, uni.Data)));" ] @@ -1267,7 +1268,7 @@ namespace N1 "return let_f0.Apply(n);" ] |> testOneBody (applyVisitor letsOperations) - + [] let ``bit operations`` () = [ @@ -1279,7 +1280,7 @@ namespace N1 "var negation = ~(a); " "var total = (((((andEx + orEx) + xorEx) + left) + right) + negation);" - """ + """ if ((total > 0L)) { return true; @@ -1291,7 +1292,7 @@ namespace N1 """ ] |> testOneBody (applyVisitor bitOperations) - + [] let ``helloWorld body`` () = [ @@ -1299,14 +1300,14 @@ namespace N1 "return r;" ] |> testOneBody (applyVisitor helloWorld) - + [] let ``if operations`` () = [ "var n = 0L;" """ - if ((r == Result.One)) - { + if ((r == Result.One)) + { n = (if_f0.Apply(QVoid.Instance) * i); } """ @@ -1328,7 +1329,7 @@ namespace N1 else if ((p == Pauli.PauliY)) { return 1L; - } + } else { return ((p==Pauli.PauliI)?3L:if_f0.Apply(QVoid.Instance)); @@ -1336,39 +1337,39 @@ namespace N1 """ ] |> testOneBody (applyVisitor ifOperation) - + [] let ``foreach operations`` () = [ "var result = 0L;" - @"foreach (var n in new QRange(0L, i)) + @"foreach (var n in new QRange(0L, i)) #line hidden - { - result = (result + i); + { + result = (result + i); }" - @"foreach (var n in new QRange(i, -(1L), 0L)) + @"foreach (var n in new QRange(i, -(1L), 0L)) #line hidden - { - result = ((result - i) * 2L); + { + result = ((result - i) * 2L); }" "var range = new QRange(0L, 10L);" - @"foreach (var n in range) + @"foreach (var n in range) #line hidden - { - result = ((range.End + result) + (n * -(foreach_f2.Apply((n, 4L))))); + { + result = ((range.End + result) + (n * -(foreach_f2.Apply((n, 4L))))); }" """ - if ((result > 10L)) - { + if ((result > 10L)) + { return Result.One; - } + } else { return Result.Zero; }""" ] |> testOneBody (applyVisitor foreachOperation) - + [] let ``udt operations`` () = [ @@ -1389,21 +1390,21 @@ namespace N1 "return new udt_args1((22L, qubits));" ] |> testOneBody (applyVisitor udtsTest) - + [] let ``test Length dependency`` () = [ "iter.Apply((Length, new QArray>(new QArray(Result.One), new QArray(Result.Zero, Result.One))));" ] |> testOneBody (applyVisitor testLengthDependency) - + [] let ``udt return values`` () = [ "return QVoid.Instance;" ] |> testOneBody (applyVisitor returnTest1) - + [ "return 5L;" ] @@ -1413,7 +1414,7 @@ namespace N1 "return (5L, 6L);" ] |> testOneBody (applyVisitor returnTest3) - + [ "return new returnUdt0((7L, 8L));" ] @@ -1423,32 +1424,32 @@ namespace N1 "return new QArray(9L, 10L);" ] |> testOneBody (applyVisitor returnTest5) - + [ "return new returnUdt1( new QArray<(Int64,Int64)>((1L, 2L), (3L, 4L)));" ] |> testOneBody (applyVisitor returnTest6) - + [ "return new QArray( new returnUdt0((1L, 2L)), new returnUdt0((3L, 4L)));" ] |> testOneBody (applyVisitor returnTest7) - + [ "return new returnUdt3(new QArray(new returnUdt0((1L, 2L)), new returnUdt0((3L, 4L))));" ] |> testOneBody (applyVisitor returnTest8) - + [ "return (new returnUdt0((7L, 8L)), new returnUdt1(new QArray<(Int64,Int64)>((1L, 2L), (3L, 4L))));" ] |> testOneBody (applyVisitor returnTest9) - + [ "return new Microsoft.Quantum.Overrides.udt0((Result.Zero, Result.One));" ] |> testOneBody (applyVisitor returnTest10) - + [] let ``repeat operation`` () = [ @@ -1456,7 +1457,7 @@ namespace N1 { var qubits = Allocate.Apply(i); #line hidden - bool __arg1__ = true; + bool __arg1__ = true; try { while (true) @@ -1475,15 +1476,15 @@ namespace N1 } #line hidden catch - { - __arg1__ = false; + { + __arg1__ = false; throw; } #line hidden finally { - if (__arg1__) - { + if (__arg1__) + { Release.Apply(qubits); } } @@ -1491,7 +1492,7 @@ namespace N1 """ ] |> testOneBody (applyVisitor repeatOperation) - + [] let ``allocate operations`` () = [ @@ -1499,7 +1500,7 @@ namespace N1 { var q = Allocate.Apply(); #line hidden - bool __arg1__ = true; + bool __arg1__ = true; try { var flag = true; @@ -1508,15 +1509,15 @@ namespace N1 } #line hidden catch - { - __arg1__ = false; + { + __arg1__ = false; throw; } #line hidden - finally + finally { if (__arg1__) - { + { Release.Apply(q); } } @@ -1525,22 +1526,22 @@ namespace N1 { var qs = Allocate.Apply(n); #line hidden - bool __arg2__ = true; + bool __arg2__ = true; try { alloc_op0.Apply(qs[(n-1L)]); } #line hidden catch - { - __arg2__ = false; + { + __arg2__ = false; throw; } #line hidden finally { if (__arg2__) - { + { Release.Apply(qs); } } @@ -1549,7 +1550,7 @@ namespace N1 { var (q1, (q2, (__arg3__, q3, __arg4__, q4))) = (Allocate.Apply(), ((Allocate.Apply(), Allocate.Apply(2L)), (Allocate.Apply(), Allocate.Apply(n), Allocate.Apply((n-1L)), Allocate.Apply(4L)))); #line hidden - bool __arg5__ = true; + bool __arg5__ = true; try { alloc_op0.Apply(q1); @@ -1557,15 +1558,15 @@ namespace N1 } #line hidden catch - { - __arg5__ = false; + { + __arg5__ = false; throw; } #line hidden finally { if (__arg5__) - { + { Release.Apply(q1); Release.Apply(q2.Item1); Release.Apply(q2.Item2); @@ -1584,22 +1585,22 @@ namespace N1 { var b = Borrow.Apply(n); #line hidden - bool __arg1__ = true; + bool __arg1__ = true; try { alloc_op0.Apply(b[(n-1L)]); } #line hidden catch - { - __arg1__ = false; + { + __arg1__ = false; throw; } #line hidden finally { - if (__arg1__) - { + if (__arg1__) + { Return.Apply(b); } } @@ -1608,29 +1609,29 @@ namespace N1 { var (q1, (q2, (__arg2__, q3))) = (Borrow.Apply(), (Borrow.Apply(2L), (Borrow.Apply(), (Borrow.Apply(n), Borrow.Apply(4L))))); #line hidden - bool __arg3__ = true; + bool __arg3__ = true; try { { var qt = (Allocate.Apply(), (Allocate.Apply(1L), Allocate.Apply(2L))); #line hidden - bool __arg4__ = true; + bool __arg4__ = true; try { var (qt1, qt2) = ((Qubit, (IQArray, IQArray)))qt; alloc_op0.Apply(qt1); - } + } #line hidden catch - { - __arg4__ = false; + { + __arg4__ = false; throw; - } + } #line hidden finally { if (__arg4__) - { + { Release.Apply(qt.Item1); Release.Apply(qt.Item2.Item1); Release.Apply(qt.Item2.Item2); @@ -1643,15 +1644,15 @@ namespace N1 } #line hidden catch - { - __arg3__ = false; + { + __arg3__ = false; throw; } #line hidden finally { if (__arg3__) - { + { Return.Apply(q1); Return.Apply(q2); Return.Apply(__arg2__); @@ -1662,7 +1663,7 @@ namespace N1 }""" ] |> testOneBody (adjointVisitor allocOperation) - + [] let ``failed operation`` () = [ @@ -1670,8 +1671,8 @@ namespace N1 @"return 1L;" ] |> testOneBody (applyVisitor failedOperation) - - + + [] let ``compare operations`` () = [ @@ -1682,7 +1683,7 @@ namespace N1 "return (((lt == (lte && gt)) != gte) || !(lt));" ] |> testOneBody (applyVisitor compareOps) - + let testOneSpecialization pick (_,op) expected = let context = createTestContext op let actual = op |> pick |> buildSpecialization context |> Option.map (fst >> formatSyntaxTree) @@ -1690,26 +1691,26 @@ namespace N1 [] let ``buildSpecialization - apply`` () = - let testOne = testOneSpecialization findBody + let testOne = testOneSpecialization findBody None |> testOne emptyOperation None |> testOne oneQubitAbstractOperation - + None |> testOne oneQubitSelfAdjointAbstractOperation - + None |> testOne randomAbstractOperation - + Some """ public override Func Body => (__in__) => { #line hidden return QVoid.Instance; - };""" + };""" |> testOne zeroQubitOperation Some """ @@ -1739,8 +1740,8 @@ namespace N1 }; """ |> testOne twoQubitOperation - - + + Some """ public override Func<(Qubit,Qubit,IQArray), QVoid> Body => (__in__) => { @@ -1756,11 +1757,11 @@ namespace N1 }; """ |> testOne differentArgsOperation - + [] let ``operation/function types`` () = let testOne = testOneSpecialization findBody - + let ret = "ICallable"; let op0 = "ICallable"; let op1 = "ICallable"; @@ -1777,7 +1778,7 @@ namespace N1 var r0 = v0.Apply(q1); var (op3, op4) = t1; op3.Apply((new QArray(q1), (q1, q1))); - + return op2.Partial(new Func((__arg1__) => (q1, __arg1__))); };""" op0 op1 op2 op3 op4 f1 ret) |> testOne opParametersTest @@ -1785,7 +1786,7 @@ namespace N1 [] let ``array operations`` () = [ - "var q = (IQArray)qubits;" + "var q = (IQArray)qubits;" "var r1 = (IQArray)new QArray(Result.Zero);" "var r2 = (IQArray)new QArray(0L, 1L);" "var r3 = (IQArray)new QArray(0D, 1.1D, 2.2D);" @@ -1794,7 +1795,7 @@ namespace N1 "var r6 = QArray.Create(r5.Length);" "var r7 = (IQArray)QArray.Add(r2, r4);" "var r8 = (IQArray)r7?.Slice(new QRange(1L, 5L, 10L));" - + "var r9 = new arrays_T1(new QArray(Pauli.PauliX, Pauli.PauliY));" "var r10 = (IQArray)QArray.Create(4L);" "var r11 = new arrays_T2((new QArray(Pauli.PauliZ), new QArray(4L)));" @@ -1804,7 +1805,7 @@ namespace N1 "var r15 = (IQArray)register.Data?.Slice(new QRange(0L, 2L));" "var r16 = (IQArray)qubits?.Slice(new QRange(1L, -(1L)));" "var r18 = (IQArray)QArray.Create(2L);" - "var r19 = (IQArray)QArray.Create(7L);" + "var r19 = (IQArray)QArray.Create(7L);" "var i0 = r13.Data[0L][1L];" "var i1 = r2[(0L + r1.Length)];" "var i2 = r3[(i1 * ((2L + 3L) - (8L % 1L)))];" @@ -1813,7 +1814,7 @@ namespace N1 "var i5 = indices[0L][1L];" "var i6 = (IQArray)t.Data[0L];" "var i7 = register.Data[3L];" - + "var l0 = qubits.Length;" "var l1 = indices.Length;" "var l2 = indices[0L].Length;" @@ -1821,12 +1822,12 @@ namespace N1 "var l4 = r8.Length;" "var l5 = r9.Data.Length;" "var l6 = register.Data.Length;" - + "return new QArray>(new QArray(i0, Result.One), new QArray(Result.Zero));" ] |> testOneBody (applyVisitor arraysOperations) - - + + [] let ``array slice`` () = [ @@ -1841,7 +1842,7 @@ namespace N1 "return qubits?.Slice(new QRange(10L,-(3L),0L));" ] |> testOneBody (applyVisitor sliceOperations) - + [] let ``range operations`` () = [ @@ -1852,10 +1853,10 @@ namespace N1 [] let ``generic parameter types`` () = let testOne (ns,op : QsCallable) (expected: string list) = - let actual = + let actual = op.Signature |> typeParametersNames - List.zip (expected |> List.map clearFormatting) (actual |> List.map clearFormatting) + List.zip (expected |> List.map clearFormatting) (actual |> List.map clearFormatting) |> List.iter Assert.Equal [] @@ -1863,28 +1864,28 @@ namespace N1 [] |> testOne oneQubitAbstractOperation - + [] |> testOne randomAbstractOperation - + [ "__T__" ] |> testOne genC1 - + [ "__T__" "__U__" ] |> testOne genC2 - + [ "__X__" "__Y__" "__Z__" ] |> testOne genCtrl3 - + [ "__T__" "__U__" @@ -1892,35 +1893,35 @@ namespace N1 |> testOne genMapper [] - let ``buildSpecialization - adjoint`` () = + let ``buildSpecialization - adjoint`` () = let testOne = testOneSpecialization findAdjoint None |> testOne oneQubitAbstractOperation - - Some "public override Func AdjointBody => Body;" + + Some "public override Func AdjointBody => Body;" |> testOne oneQubitSelfAdjointAbstractOperation None |> testOne randomAbstractOperation - - Some "public override Func AdjointBody => Body;" - |> testOne oneQubitSelfAdjointOperation - + + Some "public override Func AdjointBody => Body;" + |> testOne oneQubitSelfAdjointOperation + Some """ public override Func AdjointBody => (__in__) => { #line hidden return QVoid.Instance; - };""" + };""" |> testOne zeroQubitOperation - + Some """ public override Func AdjointBody => (__in__) => { var q1 = __in__; X.Adjoint.Apply(q1); - + #line hidden return QVoid.Instance; };""" @@ -1935,12 +1936,12 @@ namespace N1 R.Adjoint.Apply((r, q1)); CNOT.Adjoint.Apply((q1, q2)); - + #line hidden return QVoid.Instance; };""" - |> testOne twoQubitOperation - + |> testOne twoQubitOperation + Some """ public override Func<(Qubit,Qubit,Qubits), QVoid> AdjointBody => (__in__) => { @@ -1951,25 +1952,25 @@ namespace N1 #line hidden return QVoid.Instance; };""" - |> testOne threeQubitOperation - - + |> testOne threeQubitOperation + + Some "public override Func<__T__, QVoid> AdjointBody => Body;" |> testOne genAdj1 - + [] - let ``buildSpecialization - controlled`` () = + let ``buildSpecialization - controlled`` () = let testOne = testOneSpecialization findControlled - + None |> testOne oneQubitAbstractOperation - + None |> testOne oneQubitSelfAdjointAbstractOperation - + None |> testOne randomAbstractOperation - + Some """ public override Func<(IQArray,QVoid), QVoid> ControlledBody => (__in__) => { @@ -1977,7 +1978,7 @@ namespace N1 #line hidden return QVoid.Instance; - };""" + };""" |> testOne zeroQubitOperation Some """ @@ -1990,8 +1991,8 @@ namespace N1 #line hidden return QVoid.Instance; };""" - |> testOne oneQubitOperation - + |> testOne oneQubitOperation + Some """ public override Func<(IQArray,(Qubit,Qubit,Qubits)), QVoid> ControlledBody => (__in__) => { @@ -2000,25 +2001,25 @@ namespace N1 three_op1.Controlled.Apply((c, (q1, q2))); three_op1.Controlled.Apply((c, (q2, q1))); three_op1.Controlled.Apply((c, (q1, q2))); - + #line hidden return QVoid.Instance; };""" |> testOne threeQubitOperation - + [] - let ``buildSpecialization - controlled-adjoint`` () = + let ``buildSpecialization - controlled-adjoint`` () = let testOne = testOneSpecialization findControlledAdjoint None |> testOne oneQubitAbstractOperation - + Some "public override Func<(IQArray,Qubit), QVoid> ControlledAdjointBody => ControlledBody;" |> testOne oneQubitSelfAdjointAbstractOperation - + None |> testOne randomAbstractOperation - + Some """ public override Func<(IQArray,QVoid), QVoid> ControlledAdjointBody => (__in__) => { @@ -2026,11 +2027,11 @@ namespace N1 #line hidden return QVoid.Instance; - };""" + };""" |> testOne zeroQubitOperation Some """ - public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => (__in__) => + public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => (__in__) => { var (c,q1) = __in__; X.Controlled.Adjoint.Apply((c, q1)); @@ -2039,12 +2040,12 @@ namespace N1 };""" |> testOne oneQubitOperation - + Some """ public override Func<(IQArray,(Qubit,Qubit,Qubits)), QVoid> ControlledAdjointBody => (__in__) => { var (c,(q1,q2,arr1)) = __in__; - + three_op1.Controlled.Adjoint.Apply((c, (q1, q2))); three_op1.Controlled.Adjoint.Apply((c, (q2, q1))); three_op1.Controlled.Adjoint.Apply((c, (q1, q2))); @@ -2053,7 +2054,7 @@ namespace N1 return QVoid.Instance; };""" |> testOne threeQubitOperation - + [] let ``partial application`` () = [ @@ -2092,57 +2093,57 @@ namespace N1 .Partial(new Func((__arg11__) => (1L, (3.5D, __arg11__)))) .Apply(Result.One);" "partialNestedArgsOp - .Partial(new Func<((Int64,Int64,Int64),((Double,Double),(Result,Result,Result))), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg12__) => + .Partial(new Func<((Int64,Int64,Int64),((Double,Double),(Result,Result,Result))), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg12__) => ( - (__arg12__.Item1.Item1, __arg12__.Item1.Item2, __arg12__.Item1.Item3), + (__arg12__.Item1.Item1, __arg12__.Item1.Item2, __arg12__.Item1.Item3), ( - (__arg12__.Item2.Item1.Item1, __arg12__.Item2.Item1.Item2), + (__arg12__.Item2.Item1.Item1, __arg12__.Item2.Item1.Item2), (__arg12__.Item2.Item2.Item1, __arg12__.Item2.Item2.Item2, __arg12__.Item2.Item2.Item3) ) ) )) - .Partial(new Func<(Int64,((Double,Double),Result)), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg13__) => + .Partial(new Func<(Int64,((Double,Double),Result)), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg13__) => ( - (1L, i, __arg13__.Item1), + (1L, i, __arg13__.Item1), ( - (__arg13__.Item2.Item1.Item1, __arg13__.Item2.Item1.Item2), + (__arg13__.Item2.Item1.Item1, __arg13__.Item2.Item1.Item2), (res, __arg13__.Item2.Item2, res) ) ) )) .Apply((1L, ((3.3D, 2D), Result.Zero)));" "partialNestedArgsOp - .Partial(new Func<(Int64,((Double,Double),Result)), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg14__) => + .Partial(new Func<(Int64,((Double,Double),Result)), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg14__) => ( - (1L, i, __arg14__.Item1), + (1L, i, __arg14__.Item1), ( - (__arg14__.Item2.Item1.Item1, __arg14__.Item2.Item1.Item2), + (__arg14__.Item2.Item1.Item1, __arg14__.Item2.Item1.Item2), (res, __arg14__.Item2.Item2, res) ) ) )) - .Partial(new Func<(Double,Result), (Int64,((Double,Double),Result))>((__arg15__) => + .Partial(new Func<(Double,Result), (Int64,((Double,Double),Result))>((__arg15__) => ( - 2L, + 2L, ( - (2.2D, __arg15__.Item1), + (2.2D, __arg15__.Item1), __arg15__.Item2 ) ) )) .Apply((3.3D, Result.Zero));" "partialNestedArgsOp - .Partial(new Func<(Int64,(Double,Result)), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg16__) => + .Partial(new Func<(Int64,(Double,Result)), ((Int64,Int64,Int64),((Double,Double),(Result,Result,Result)))>((__arg16__) => ( - (i, __arg16__.Item1, 1L), + (i, __arg16__.Item1, 1L), ( (__arg16__.Item2.Item1, 1D), (res, __arg16__.Item2.Item2, Result.Zero) ) ) )) - .Partial(new Func((__arg17__) => + .Partial(new Func((__arg17__) => ( - i, + i, (__arg17__, res) ) )) @@ -2162,26 +2163,26 @@ namespace N1 "partialGeneric2.Partial((_, _, (1L, Result.One))).Apply((0L, Result.Zero));" "partialGeneric2.Partial((0L, _, (1L, _))).Apply((Result.Zero, Result.One));" "partialInput - .Partial(new Func<(Double,(Result,Result)), (Int64,(Double,Double),(Result,Result,Result))>((__arg20__) => + .Partial(new Func<(Double,(Result,Result)), (Int64,(Double,Double),(Result,Result,Result))>((__arg20__) => ( - 1L, - (__arg20__.Item1, 1.1D), + 1L, + (__arg20__.Item1, 1.1D), (Result.Zero, __arg20__.Item2.Item1, __arg20__.Item2.Item2) ) )) .Apply((2.2D, (Result.One, Result.One)));" """ return partialUnitary - .Partial(new Func, (Double,ICallable,IQArray)>((__arg21__) => + .Partial(new Func, (Double,ICallable,IQArray)>((__arg21__) => ( - 1.1D, - partialFunction.Partial(new Func<(Int64,Double), (Int64,Double,Pauli)>((__arg22__) => + 1.1D, + partialFunction.Partial(new Func<(Int64,Double), (Int64,Double,Pauli)>((__arg22__) => ( - __arg22__.Item1, - __arg22__.Item2, + __arg22__.Item1, + __arg22__.Item2, Pauli.PauliX ) - )), + )), __arg21__) )); """ @@ -2202,10 +2203,10 @@ namespace N1 "return op.Data.Partial(new Func, (Double,F,IQArray)>((__arg4__) => (start, f, __arg4__)));" ] |> testOneBody (applyVisitor partialFunctionTest) - + [] let ``buildRun test`` () = - let testOne (_,op) expected = + let testOne (_,op) expected = let context = createTestContext op let (name, nonGenericName) = findClassName context op let actual = buildRun context nonGenericName op.ArgumentTuple op.Signature.ArgumentType op.Signature.ReturnType |> formatSyntaxTree @@ -2222,57 +2223,57 @@ namespace N1 return __m__.Run(q1); }" |> testOne oneQubitAbstractOperation - + "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, Qubit q1) { return __m__.Run(q1); }" |> testOne oneQubitSelfAdjointAbstractOperation - - + + "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, Qubit q1, Basis b, (Pauli, IQArray>, Boolean) t, Int64 i) { return __m__.Run>, Boolean), Int64), QVoid>((q1,b,t,i)); }" |> testOne randomAbstractOperation - - + + "public static System.Threading.Tasks.Task>> Run(IOperationFactory __m__, IQArray qubits, Qubits register, IQArray> indices, arrays_T3 t) { return __m__.Run, Qubits, IQArray>, arrays_T3), IQArray>>((qubits, register, indices, t)); - }" + }" |> testOne arraysOperations - - + + "public static System.Threading.Tasks.Task<__T__> Run(IOperationFactory __m__, __T__ a1) { return __m__.Run, __T__, __T__>(a1); - }" + }" |> testOne genC1a - - + + "public static System.Threading.Tasks.Task> Run(IOperationFactory __m__, ICallable mapper, IQArray<__T__> source) { return __m__.Run, (ICallable, IQArray<__T__>), IQArray<__U__>>((mapper, source)); - }" + }" |> testOne genMapper - + "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, Int64 a, Int64 b, Double c, Double d) { return __m__.Run(((a,b),(c,d))); - }" + }" |> testOne nestedArgTuple1 "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, (Int64, Int64) a, Double c, Int64 b, (Qubit, Qubit) d, Double e) { return __m__.Run((a,(c,(b,d),e))); - }" + }" |> testOne nestedArgTuple2 "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, (__A__, Int64) a, __A__ c, Int64 b, (Qubit, __A__) d, Double e) { return __m__.Run, ((__A__,Int64),(__A__,(Int64,(Qubit,__A__)),Double)), QVoid>((a,(c,(b,d),e))); - }" + }" |> testOne nestedArgTupleGeneric "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, ICallable second, ICallable first, __B__ arg) @@ -2280,35 +2281,35 @@ namespace N1 return __m__.Run, (ICallable, ICallable, __B__), QVoid>((second, first, arg)); }" |> testOne composeImpl - + "public static System.Threading.Tasks.Task Run(IOperationFactory __m__, ICallable second, ICallable first) { return __m__.Run, (ICallable, ICallable), ICallable>((second, first)); }" |> testOne compose - + [] let ``is abstract`` () = let testOne (_,op) expected = let actual = op |> isAbstract Assert.Equal(expected, actual) - true |> testOne emptyOperation + true |> testOne emptyOperation true |> testOne oneQubitAbstractOperation true |> testOne oneQubitSelfAdjointAbstractOperation true |> testOne randomAbstractOperation false |> testOne zeroQubitOperation - false |> testOne oneQubitSelfAdjointOperation + false |> testOne oneQubitSelfAdjointOperation false |> testOne oneQubitOperation false |> testOne twoQubitOperation - false |> testOne threeQubitOperation + false |> testOne threeQubitOperation false |> testOne differentArgsOperation false |> testOne randomOperation let testOneClass (_,op : QsCallable) executionTarget (expected : string) = let expected = expected.Replace("%%%", op.SourceFile.Value) - let assemblyConstants = - new System.Collections.Generic.KeyValuePair<_,_> (AssemblyConstants.ExecutionTarget, executionTarget) + let assemblyConstants = + new System.Collections.Generic.KeyValuePair<_,_> (AssemblyConstants.ExecutionTarget, executionTarget) |> Seq.singleton |> ImmutableDictionary.CreateRange let compilation = {Namespaces = syntaxTree; EntryPoints = ImmutableArray.Create op.FullName} @@ -2317,7 +2318,7 @@ namespace N1 Assert.Equal(expected |> clearFormatting, actual |> clearFormatting) [] - let ``buildOperationClass - concrete`` () = + let ``buildOperationClass - concrete`` () = """ public abstract partial class emptyOperation : Operation, ICallable { @@ -2331,7 +2332,7 @@ namespace N1 public static HoneywellEntryPointInfo Info => new HoneywellEntryPointInfo(typeof(emptyOperation)); public override void Init() { } - + public override IApplyData __dataIn(QVoid data) => data; public override IApplyData __dataOut(QVoid data) => data; public static System.Threading.Tasks.Task Run(IOperationFactory __m__) @@ -2435,12 +2436,12 @@ namespace N1 } ; - - public override void Init() - { + + public override void Init() + { this.X = this.Factory.Get>(typeof(Microsoft.Quantum.Intrinsic.X)); } - + public override IApplyData __dataIn(Qubit data) => data; public override IApplyData __dataOut(QVoid data) => data; public static System.Threading.Tasks.Task Run(IOperationFactory __m__, Qubit q1) @@ -2450,9 +2451,9 @@ namespace N1 } """ |> testOneClass oneQubitOperation AssemblyConstants.QCIProcessor - + [] - let ``buildOperationClass - generics`` () = + let ``buildOperationClass - generics`` () = """ public abstract partial class genCtrl3<__X__, __Y__, __Z__> : Controllable<(__X__,(Int64,(__Y__,__Z__),Result))>, ICallable { @@ -2466,7 +2467,7 @@ namespace N1 { } - System.Collections.Generic.IEnumerable IApplyData.Qubits + System.Collections.Generic.IEnumerable IApplyData.Qubits { get { @@ -2492,9 +2493,9 @@ namespace N1 return __m__.Run, (__X__,(Int64,(__Y__,__Z__),Result)), QVoid>((arg1, arg2)); } } -""" +""" |> testOneClass genCtrl3 AssemblyConstants.HoneywellProcessor - + """ [SourceLocation("%%%", OperationFunctor.Body, 1266, 1272)] public partial class composeImpl<__A__, __B__> : Operation<(ICallable,ICallable,__B__), QVoid>, ICallable @@ -2509,7 +2510,7 @@ namespace N1 { } - System.Collections.Generic.IEnumerable IApplyData.Qubits + System.Collections.Generic.IEnumerable IApplyData.Qubits { get { @@ -2541,11 +2542,11 @@ namespace N1 return __m__.Run, (ICallable,ICallable,__B__), QVoid>((second, first, arg)); } } -""" +""" |> testOneClass composeImpl AssemblyConstants.IonQProcessor - + [] - let ``buildOperationClass - abstract function`` () = + let ``buildOperationClass - abstract function`` () = """ public abstract partial class genF1<__A__> : Function<__A__, QVoid>, ICallable { @@ -2569,11 +2570,11 @@ namespace N1 } """ |> testOneClass genF1 AssemblyConstants.QCIProcessor - + [] let ``buildOperationClass - access modifiers`` () = """ -[SourceLocation("%%%", OperationFunctor.Body, 1312, 1314)] +[SourceLocation("%%%", OperationFunctor.Body, 1314, 1316)] internal partial class EmptyInternalFunction : Function, ICallable { public EmptyInternalFunction(IOperationFactory m) : base(m) @@ -2607,7 +2608,7 @@ internal partial class EmptyInternalFunction : Function, ICallable |> testOneClass emptyInternalFunction null """ -[SourceLocation("%%%", OperationFunctor.Body, 1314, 1316)] +[SourceLocation("%%%", OperationFunctor.Body, 1316, 1318)] internal partial class EmptyInternalOperation : Operation, ICallable { public EmptyInternalOperation(IOperationFactory m) : base(m) @@ -2651,22 +2652,22 @@ internal partial class EmptyInternalOperation : Operation, ICallab var qubits = Allocate.Apply(1L); #line hidden bool __arg1__ = true; - try + try { H.Apply(qubits[0L]); - MicrosoftQuantumIntrinsicH.Apply(qubits[0L]); + MicrosoftQuantumIntrinsicH.Apply(qubits[0L]); } #line hidden catch - { + { __arg1__ = false; throw; } #line hidden - finally + finally { if (__arg1__) - { + { Release.Apply(qubits); } } @@ -2674,7 +2675,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab ] |> testOneBody (applyVisitor duplicatedDefinitionsCaller) - + [] let ``buildOpsProperties with duplicatedDefinitionsCaller`` () = let t = sprintf @"protected %s %s { get; set; }" @@ -2682,23 +2683,23 @@ internal partial class EmptyInternalOperation : Operation, ICallab let expected = [ - template "Allocate" "Allocate" - template "IUnitary" "MicrosoftQuantumIntrinsicH" - template "ICallable" "H" - template "Release" "Release" - template "ICallable" "MicrosoftQuantumOverridesemptyFunction" - template "ICallable" "emptyFunction" + template "Allocate" "Allocate" + template "IUnitary" "MicrosoftQuantumIntrinsicH" + template "ICallable" "H" + template "Release" "Release" + template "ICallable" "MicrosoftQuantumOverridesemptyFunction" + template "ICallable" "emptyFunction" ] let (_,op) = duplicatedDefinitionsCaller let context = createTestContext op - let actual = + let actual = op |> operationDependencies |> depsByName |> buildOpsProperties context |> List.map formatSyntaxTree - + List.zip (expected |> List.map clearFormatting) (actual |> List.map clearFormatting) |> List.iter Assert.Equal [] @@ -2722,28 +2723,28 @@ internal partial class EmptyInternalOperation : Operation, ICallab |> List.iter Assert.Equal [] - let ``buildOperationClass - concrete functions`` () = + let ``buildOperationClass - concrete functions`` () = """ - [SourceLocation("%%%", OperationFunctor.Body, 1301,1312)] + [SourceLocation("%%%", OperationFunctor.Body, 1301,1310)] public partial class UpdateUdtItems : Function, ICallable { public UpdateUdtItems(IOperationFactorym) : base(m) { } - + String ICallable.Name => "UpdateUdtItems"; String ICallable.FullName => "Microsoft.Quantum.Compiler.Generics.UpdateUdtItems"; public static EntryPointInfo Info => new EntryPointInfo(typeof(UpdateUdtItems)); - public override Func Body => (__in__) => + public override Func Body => (__in__) => { var udt = __in__; vararr=QArray.Create(10L); return new MyType2((1L,udt.Data.Item2,(arr?.Copy(),udt.Data.Item3.Item2))); }; - + public override void Init() { } - + public override IApplyData __dataIn(MyType2data) => data; public override IApplyData __dataOut(MyType2data) => data; public static System.Threading.Tasks.Task Run(IOperationFactory __m__, MyType2 udt) @@ -2904,8 +2905,8 @@ internal partial class EmptyInternalOperation : Operation, ICallab public U(IUnitary data) : base(data) { } - - System.Collections.Generic.IEnumerable IApplyData.Qubits + + System.Collections.Generic.IEnumerable IApplyData.Qubits { get { @@ -2919,7 +2920,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_U - + """ public class AA : UDTBase, IApplyData { @@ -2930,8 +2931,8 @@ internal partial class EmptyInternalOperation : Operation, ICallab public AA(A data) : base(data) { } - - System.Collections.Generic.IEnumerable IApplyData.Qubits + + System.Collections.Generic.IEnumerable IApplyData.Qubits { get { @@ -2945,7 +2946,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_AA - + """ public class Q : UDTBase, IApplyData { @@ -2956,7 +2957,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab public Q(Qubit data) : base(data) { } - + System.Collections.Generic.IEnumerable IApplyData.Qubits { get @@ -2971,7 +2972,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_Q - + """ public class QQ : UDTBase, IApplyData { @@ -2982,7 +2983,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab public QQ(Q data) : base(data) { } - + System.Collections.Generic.IEnumerable IApplyData.Qubits { get @@ -3023,7 +3024,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_Qubits - + """ public class udt_args1 : UDTBase<(Int64,IQArray)>, IApplyData { @@ -3053,7 +3054,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_args1 - + """ public class udt_Real : UDTBase, IApplyData { @@ -3073,7 +3074,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_Real - + """ public class udt_Complex : UDTBase<(udt_Real,udt_Real)>, IApplyData { @@ -3096,7 +3097,7 @@ internal partial class EmptyInternalOperation : Operation, ICallab } """ |> testOneUdt udt_Complex - + """ public class udt_TwoDimArray : UDTBase>>, IApplyData { @@ -3139,9 +3140,36 @@ internal class InternalType : UDTBase, IApplyData """ |> testOneUdt udt_InternalType + [] + let ``buildUdtClass - named tuple`` () = + """ +public class NamedTuple : UDTBase<((Int64,Double),Int64)>, IApplyData +{ + public NamedTuple() : base(default(((Int64,Double),Int64))) + { + } + + public NamedTuple(((Int64,Double),Int64) data) : base(data) + { + } + + public (Int64,Double) FirstItem => Data.Item1; + public Int64 SecondItem => Data.Item2; + public (Int64,Double) Item1 => Data.Item1; + public Int64 Item2 => Data.Item2; + System.Collections.Generic.IEnumerable IApplyData.Qubits => null; + public void Deconstruct(out (Int64,Double) item1, out Int64 item2) + { + item1 = Data.Item1; + item2 = Data.Item2; + } +} +""" + |> testOneUdt udt_NamedTuple + [] - let ``one file - EmptyElements`` () = + let ``one file - EmptyElements`` () = """ //------------------------------------------------------------------------------ // @@ -3252,7 +3280,7 @@ namespace Microsoft.Quantum |> testOneFile (Path.Combine("Circuits","EmptyElements.qs")) [] - let ``one file - UserDefinedTypes`` () = + let ``one file - UserDefinedTypes`` () = """ //------------------------------------------------------------------------------ // @@ -3328,7 +3356,7 @@ namespace Microsoft.Quantum item2 = Data.Item2; } } -} +} """ |> testOneFile (Path.Combine("Circuits","Types.qs")) @@ -3340,7 +3368,7 @@ namespace Microsoft.Quantum Assert.Equal(1, local.Length) Assert.Equal("Microsoft.Quantum.Intrinsic", (fst local.[0]).Value) let actual = (snd local.[0]) |> List.map oneName |> List.sort - List.zip expected actual |> List.iter Assert.Equal + List.zip expected actual |> List.iter Assert.Equal [] let ``one file - HelloWorld`` () = @@ -3386,9 +3414,9 @@ namespace Microsoft.Quantum.Tests.Inline #line 11 "%%" return r; }; - + public override void Init() { } - + public override IApplyData __dataIn(Int64 data) => new QTuple(data); public override IApplyData __dataOut(Int64 data) => new QTuple(data); public static System.Threading.Tasks.Task Run(IOperationFactory __m__, Int64 n) @@ -3397,10 +3425,10 @@ namespace Microsoft.Quantum.Tests.Inline } } }""" - |> + |> testOneFile (Path.Combine("Circuits","HelloWorld.qs")) - + [] let ``one file - LineNumbers`` () = """ @@ -3464,7 +3492,7 @@ namespace Microsoft.Quantum.Tests.LineNumbers var (ctrls,q) = (Allocate.Apply(r), Allocate.Apply()); #line hidden bool __arg1__ = true; - try + try { #line 15 "%%" if ((n == 0L)) @@ -3485,7 +3513,7 @@ namespace Microsoft.Quantum.Tests.LineNumbers } #line hidden catch - { + { __arg1__ = false; throw; } @@ -3522,10 +3550,10 @@ namespace Microsoft.Quantum.Tests.LineNumbers } } }""" - |> + |> testOneFile (Path.Combine("Circuits","LineNumbers.qs")) - + [] let ``one file - UnitTests`` () = """ @@ -3552,9 +3580,9 @@ using Microsoft.Quantum.Simulation.Core; [assembly: CallableDeclaration("{\"Kind\":{\"Case\":\"TypeConstructor\"},\"QualifiedName\":{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\"},\"Attributes\":[],\"Modifiers\":{\"Access\":{\"Case\":\"DefaultAccess\"}},\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":12,\"Item2\":4},\"SymbolRange\":{\"Item1\":{\"Line\":1,\"Column\":9},\"Item2\":{\"Line\":1,\"Column\":13}},\"ArgumentTuple\":{\"Case\":\"QsTuple\",\"Fields\":[[{\"Case\":\"QsTupleItem\",\"Fields\":[{\"VariableName\":{\"Case\":\"ValidName\",\"Fields\":[\"__Item1__\"]},\"Type\":{\"Case\":\"String\"},\"InferredInformation\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Position\":{\"Case\":\"Null\"},\"Range\":{\"Item1\":{\"Line\":1,\"Column\":1},\"Item2\":{\"Line\":1,\"Column\":1}}}]}]]},\"Signature\":{\"TypeParameters\":[],\"ArgumentType\":{\"Case\":\"String\"},\"ReturnType\":{\"Case\":\"UserDefinedType\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Null\"}}]},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":true}}},\"Documentation\":[]}")] [assembly: SpecializationDeclaration("{\"Kind\":{\"Case\":\"QsBody\"},\"TypeArguments\":{\"Case\":\"Null\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":true}},\"Parent\":{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\"},\"Attributes\":[],\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":12,\"Item2\":4},\"HeaderRange\":{\"Item1\":{\"Line\":1,\"Column\":9},\"Item2\":{\"Line\":1,\"Column\":13}},\"Documentation\":[]}")] [assembly: TypeDeclaration("{\"QualifiedName\":{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\"},\"Attributes\":[{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Core\",\"Name\":\"Attribute\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":11}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"UnitValue\"},\"Item2\":[],\"Item3\":{\"Case\":\"UnitType\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":13}}]}},\"Offset\":{\"Item1\":11,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}}],\"Modifiers\":{\"Access\":{\"Case\":\"DefaultAccess\"}},\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":12,\"Item2\":4},\"SymbolRange\":{\"Item1\":{\"Line\":1,\"Column\":9},\"Item2\":{\"Line\":1,\"Column\":13}},\"Type\":{\"Case\":\"String\"},\"TypeItems\":{\"Case\":\"QsTuple\",\"Fields\":[[{\"Case\":\"QsTupleItem\",\"Fields\":[{\"Case\":\"Anonymous\",\"Fields\":[{\"Case\":\"String\"}]}]}]]},\"Documentation\":[]}")] -[assembly: CallableDeclaration("{\"Kind\":{\"Case\":\"Operation\"},\"QualifiedName\":{\"Namespace\":\"Microsoft.Quantum.Tests.UnitTests\",\"Name\":\"UnitTest1\"},\"Attributes\":[{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":6}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"ValueTuple\",\"Fields\":[[{\"Item1\":{\"Case\":\"StringLiteral\",\"Fields\":[\"ToffoliSimulator\",[]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":7},\"Item2\":{\"Line\":1,\"Column\":25}}]}}]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":6},\"Item2\":{\"Line\":1,\"Column\":26}}]}},\"Offset\":{\"Item1\":20,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}},{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":6}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"ValueTuple\",\"Fields\":[[{\"Item1\":{\"Case\":\"StringLiteral\",\"Fields\":[\"QuantumSimulator\",[]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":7},\"Item2\":{\"Line\":1,\"Column\":25}}]}}]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":6},\"Item2\":{\"Line\":1,\"Column\":26}}]}},\"Offset\":{\"Item1\":19,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}}],\"Modifiers\":{\"Access\":{\"Case\":\"DefaultAccess\"}},\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":21,\"Item2\":4},\"SymbolRange\":{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":20}},\"ArgumentTuple\":{\"Case\":\"QsTuple\",\"Fields\":[[]]},\"Signature\":{\"TypeParameters\":[],\"ArgumentType\":{\"Case\":\"UnitType\"},\"ReturnType\":{\"Case\":\"UnitType\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":false}}},\"Documentation\":[]}")] +[assembly: CallableDeclaration("{\"Kind\":{\"Case\":\"Operation\"},\"QualifiedName\":{\"Namespace\":\"Microsoft.Quantum.Tests.UnitTests\",\"Name\":\"UnitTest1\"},\"Attributes\":[{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":6}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"StringLiteral\",\"Fields\":[\"ToffoliSimulator\",[]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":7},\"Item2\":{\"Line\":1,\"Column\":25}}]}},\"Offset\":{\"Item1\":20,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}},{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":6}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"StringLiteral\",\"Fields\":[\"QuantumSimulator\",[]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":7},\"Item2\":{\"Line\":1,\"Column\":25}}]}},\"Offset\":{\"Item1\":19,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}}],\"Modifiers\":{\"Access\":{\"Case\":\"DefaultAccess\"}},\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":21,\"Item2\":4},\"SymbolRange\":{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":20}},\"ArgumentTuple\":{\"Case\":\"QsTuple\",\"Fields\":[[]]},\"Signature\":{\"TypeParameters\":[],\"ArgumentType\":{\"Case\":\"UnitType\"},\"ReturnType\":{\"Case\":\"UnitType\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":false}}},\"Documentation\":[]}")] [assembly: SpecializationDeclaration("{\"Kind\":{\"Case\":\"QsBody\"},\"TypeArguments\":{\"Case\":\"Null\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":false}},\"Parent\":{\"Namespace\":\"Microsoft.Quantum.Tests.UnitTests\",\"Name\":\"UnitTest1\"},\"Attributes\":[],\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":21,\"Item2\":4},\"HeaderRange\":{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":20}},\"Documentation\":[]}")] -[assembly: CallableDeclaration("{\"Kind\":{\"Case\":\"Operation\"},\"QualifiedName\":{\"Namespace\":\"Microsoft.Quantum.Tests.UnitTests\",\"Name\":\"UnitTest2\"},\"Attributes\":[{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":6}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"ValueTuple\",\"Fields\":[[{\"Item1\":{\"Case\":\"StringLiteral\",\"Fields\":[\"SomeNamespace.CustomSimulator\",[]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":7},\"Item2\":{\"Line\":1,\"Column\":38}}]}}]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":6},\"Item2\":{\"Line\":1,\"Column\":39}}]}},\"Offset\":{\"Item1\":24,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}}],\"Modifiers\":{\"Access\":{\"Case\":\"DefaultAccess\"}},\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":25,\"Item2\":4},\"SymbolRange\":{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":20}},\"ArgumentTuple\":{\"Case\":\"QsTuple\",\"Fields\":[[]]},\"Signature\":{\"TypeParameters\":[],\"ArgumentType\":{\"Case\":\"UnitType\"},\"ReturnType\":{\"Case\":\"UnitType\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":false}}},\"Documentation\":[]}")] +[assembly: CallableDeclaration("{\"Kind\":{\"Case\":\"Operation\"},\"QualifiedName\":{\"Namespace\":\"Microsoft.Quantum.Tests.UnitTests\",\"Name\":\"UnitTest2\"},\"Attributes\":[{\"TypeId\":{\"Case\":\"Value\",\"Fields\":[{\"Namespace\":\"Microsoft.Quantum.Diagnostics\",\"Name\":\"Test\",\"Range\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":2},\"Item2\":{\"Line\":1,\"Column\":6}}]}}]},\"Argument\":{\"Item1\":{\"Case\":\"StringLiteral\",\"Fields\":[\"SomeNamespace.CustomSimulator\",[]]},\"Item2\":[],\"Item3\":{\"Case\":\"String\"},\"Item4\":{\"IsMutable\":false,\"HasLocalQuantumDependency\":false},\"Item5\":{\"Case\":\"Value\",\"Fields\":[{\"Item1\":{\"Line\":1,\"Column\":7},\"Item2\":{\"Line\":1,\"Column\":38}}]}},\"Offset\":{\"Item1\":24,\"Item2\":4},\"Comments\":{\"OpeningComments\":[],\"ClosingComments\":[]}}],\"Modifiers\":{\"Access\":{\"Case\":\"DefaultAccess\"}},\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":25,\"Item2\":4},\"SymbolRange\":{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":20}},\"ArgumentTuple\":{\"Case\":\"QsTuple\",\"Fields\":[[]]},\"Signature\":{\"TypeParameters\":[],\"ArgumentType\":{\"Case\":\"UnitType\"},\"ReturnType\":{\"Case\":\"UnitType\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":false}}},\"Documentation\":[]}")] [assembly: SpecializationDeclaration("{\"Kind\":{\"Case\":\"QsBody\"},\"TypeArguments\":{\"Case\":\"Null\"},\"Information\":{\"Characteristics\":{\"Case\":\"EmptySet\"},\"InferredInformation\":{\"IsSelfAdjoint\":false,\"IsIntrinsic\":false}},\"Parent\":{\"Namespace\":\"Microsoft.Quantum.Tests.UnitTests\",\"Name\":\"UnitTest2\"},\"Attributes\":[],\"SourceFile\":\"%%%\",\"Position\":{\"Item1\":25,\"Item2\":4},\"HeaderRange\":{\"Item1\":{\"Line\":1,\"Column\":11},\"Item2\":{\"Line\":1,\"Column\":20}},\"Documentation\":[]}")] #line hidden @@ -3756,7 +3784,7 @@ namespace Microsoft.Quantum.Tests.UnitTests } """ - |> + |> testOneFile (Path.Combine("Circuits","UnitTests.qs")) diff --git a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj index 0da8bb707e6..1bc1a267e83 100644 --- a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj +++ b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj @@ -21,7 +21,7 @@ - + diff --git a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.nuspec.template b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.nuspec.template index 997341009c3..f964fcb499e 100644 --- a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.nuspec.template +++ b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.nuspec.template @@ -21,6 +21,7 @@ + diff --git a/src/Simulation/CsharpGeneration/RewriteStep.props b/src/Simulation/CsharpGeneration/RewriteStep.props new file mode 100644 index 00000000000..996b5865b98 --- /dev/null +++ b/src/Simulation/CsharpGeneration/RewriteStep.props @@ -0,0 +1,8 @@ + + + + + $(MSBuildThisFileDirectory)/../lib/netstandard2.1/Microsoft.Quantum.CsharpGeneration.dll + + + diff --git a/src/Simulation/CsharpGeneration/SimulationCode.fs b/src/Simulation/CsharpGeneration/SimulationCode.fs index 32cc584932b..e0c6b0c0810 100644 --- a/src/Simulation/CsharpGeneration/SimulationCode.fs +++ b/src/Simulation/CsharpGeneration/SimulationCode.fs @@ -17,7 +17,7 @@ open Microsoft.Quantum.RoslynWrapper open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler.ReservedKeywords -open Microsoft.Quantum.QsCompiler.SyntaxTokens +open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.SyntaxExtensions open Microsoft.Quantum.QsCompiler.Transformations.Core @@ -31,17 +31,17 @@ open Microsoft.Quantum.QsCompiler.Transformations.BasicTransformations /// --------------------------------------------------------------------------- module SimulationCode = open System.Globalization - + type CodegenContext with member this.setCallable (op: QsCallable) = { this with current = (Some op.FullName); signature = (Some op.Signature) } member this.setUdt (udt: QsCustomType) = { this with current = (Some udt.FullName) } - let autoNamespaces = + let autoNamespaces = [ "System" "Microsoft.Quantum.Core" "Microsoft.Quantum.Intrinsic" - "Microsoft.Quantum.Simulation.Core" + "Microsoft.Quantum.Simulation.Core" ] let funcsAsProps = [ @@ -50,43 +50,43 @@ module SimulationCode = ("End", { Namespace = "Microsoft.Quantum.Core" |> NonNullable.New; Name = "RangeEnd" |> NonNullable.New } ) ("Step", { Namespace = "Microsoft.Quantum.Core" |> NonNullable.New; Name = "RangeStep" |> NonNullable.New } ) ] - + let isCurrentOp context n = match context.current with | None -> false | Some name -> name = n - let prependNamespaceString (name : QsQualifiedName) = + let prependNamespaceString (name : QsQualifiedName) = let pieces = name.Namespace.Value.Split([|'.'|]) |> String.Concat pieces + name.Name.Value - let needsFullPath context (op:QsQualifiedName) = + let needsFullPath context (op:QsQualifiedName) = let hasMultipleDefinitions() = if context.byName.ContainsKey op.Name then context.byName.[op.Name].Length > 1 else false let sameNamespace = match context.current with | None -> false | Some n -> n.Namespace = op.Namespace - if sameNamespace then + if sameNamespace then false elif hasMultipleDefinitions() then true else not (autoNamespaces |> List.contains op.Namespace.Value) - - let getTypeParameters types = - let findAll (t: ResolvedType) = t.ExtractAll (fun item -> item.Resolution |> function + + let getTypeParameters types = + let findAll (t: ResolvedType) = t.ExtractAll (fun item -> item.Resolution |> function | QsTypeKind.TypeParameter tp -> seq{ yield tp } | _ -> Enumerable.Empty()) - types - |> Seq.collect findAll + types + |> Seq.collect findAll |> Seq.distinctBy (fun tp -> tp.Origin, tp.TypeName) |> Seq.toList - let getAllItems itemBase t = - let rec getItems (acc : Queue) current = function + let getAllItems itemBase t = + let rec getItems (acc : Queue) current = function | Tuple ts -> ts |> Seq.iteri (fun i x -> getItems acc (current <|.|> ``ident`` ("Item" + (i+1).ToString())) x) | _ -> acc.Enqueue current - let items = Queue() + let items = Queue() getItems items itemBase t items let hasTypeParameters types = not (getTypeParameters types).IsEmpty - + let justTheName context (n: QsQualifiedName) = if needsFullPath context n then n.Namespace.Value + "." + n.Name.Value else n.Name.Value @@ -108,14 +108,14 @@ module SimulationCode = | QsTypeKind.Operation ((tIn, tOut), _) -> (tIn, tOut) | QsTypeKind.Function (tIn, tOut) -> (tIn, tOut) // TODO: Diagnostics - | _ -> failwith "Invalid ResolvedType for callable definition" + | _ -> failwith "Invalid ResolvedType for callable definition" - let hasAdjointControlled functors = - let oneFunctor (adj,ctrl) f = - match f with - | QsFunctor.Adjoint -> (true, ctrl) + let hasAdjointControlled functors = + let oneFunctor (adj,ctrl) f = + match f with + | QsFunctor.Adjoint -> (true, ctrl) | QsFunctor.Controlled -> (adj, true) - match functors with + match functors with | Value fs -> fs |> Seq.fold oneFunctor (false,false) // TODO: Diagnostics | Null -> (true, true) @@ -139,11 +139,11 @@ module SimulationCode = | QsTypeKind.Operation (_,functors) -> roslynCallableInterfaceName functors.Characteristics | QsTypeKind.Function _ -> roslynCallableInterfaceName ResolvedCharacteristics.Empty | QsTypeKind.TypeParameter t -> t |> roslynTypeParameterName - | QsTypeKind.MissingType -> "object" + | QsTypeKind.MissingType -> "object" // TODO: diagnostics | QsTypeKind.InvalidType -> "" - - and roslynTupleTypeName context tupleTypes = + + and roslynTupleTypeName context tupleTypes = tupleTypes |> Seq.map (roslynTypeName context) |> String.concat "," @@ -152,13 +152,13 @@ module SimulationCode = and roslynTypeParameterName (t:QsTypeParameter) = sprintf "__%s__" t.TypeName.Value - and roslynCallableInterfaceName characteristics = - let (adj, ctrl) = characteristics.SupportedFunctors |> hasAdjointControlled - match (adj,ctrl) with - | (true, true) -> "IUnitary" - | (true, false) -> "IAdjointable" + and roslynCallableInterfaceName characteristics = + let (adj, ctrl) = characteristics.SupportedFunctors |> hasAdjointControlled + match (adj,ctrl) with + | (true, true) -> "IUnitary" + | (true, false) -> "IAdjointable" | (false, true) -> "IControllable" - | _ -> "ICallable" + | _ -> "ICallable" and roslynCallableTypeName context (name:QsQualifiedName) = if not (context.allCallables.ContainsKey name) then @@ -171,7 +171,7 @@ module SimulationCode = if isGeneric context name then baseInterface else - match baseInterface with + match baseInterface with | "ICallable" -> sprintf "%s<%s, %s>" baseInterface (roslynTypeName context tIn) (roslynTypeName context tOut) | _ -> @@ -186,11 +186,11 @@ module SimulationCode = | QsTypeKind.Operation _ | QsTypeKind.Function _ -> true | _ -> false - + let tupleBaseClassName context qsharpType = let baseType = (roslynTypeName context qsharpType) sprintf "QTuple<%s>" baseType - + let udtBaseClassName context qsharpType = let baseType = (roslynTypeName context qsharpType) sprintf "UDTBase<%s>" baseType @@ -204,20 +204,20 @@ module SimulationCode = count <- count + 1 sprintf "__arg%d__" count - type ExpressionSeeker(parent : SyntaxTreeTransformation>) = + type ExpressionSeeker(parent : SyntaxTreeTransformation>) = inherit ExpressionTransformation>(parent, TransformationOptions.NoRebuild) override this.OnTypedExpression ex = match ex.Expression with - | Identifier (id, _) -> + | Identifier (id, _) -> match id with | GlobalCallable name -> this.SharedState.Add name |> ignore | _ -> () | _ -> () - base.OnTypedExpression ex + base.OnTypedExpression ex /// Used to discover which operations are used by a certain code block. - type StatementKindSeeker(parent : SyntaxTreeTransformation>) = + type StatementKindSeeker(parent : SyntaxTreeTransformation>) = inherit StatementKindTransformation>(parent, TransformationOptions.NoRebuild) let ALLOCATE = { Name = "Allocate" |> NonNullable.New; Namespace = "Microsoft.Quantum.Intrinsic" |> NonNullable.New } @@ -225,22 +225,22 @@ module SimulationCode = let BORROW = { Name = "Borrow" |> NonNullable.New; Namespace = "Microsoft.Quantum.Intrinsic" |> NonNullable.New } let RETURN = { Name = "Return" |> NonNullable.New; Namespace = "Microsoft.Quantum.Intrinsic" |> NonNullable.New } - override this.OnAllocateQubits node = + override this.OnAllocateQubits node = this.SharedState.Add ALLOCATE |> ignore this.SharedState.Add RELEASE |> ignore - base.OnAllocateQubits node + base.OnAllocateQubits node - override this.OnBorrowQubits node = + override this.OnBorrowQubits node = this.SharedState.Add BORROW |> ignore this.SharedState.Add RETURN |> ignore - base.OnBorrowQubits node + base.OnBorrowQubits node /// Used to discover which operations are used by a certain code block. type OperationsSeeker private (_private_) = inherit SyntaxTreeTransformation>(new HashSet<_>(), TransformationOptions.NoRebuild) - new () as this = - new OperationsSeeker("_private_") then + new () as this = + new OperationsSeeker("_private_") then this.StatementKinds <- new StatementKindSeeker(this) this.Expressions <- new ExpressionSeeker(this) this.Types <- new TypeTransformation>(this, TransformationOptions.Disabled) @@ -257,8 +257,8 @@ module SimulationCode = member val StartLine = None with get, set member val LineNumber = None with get, set - new (context : CodegenContext) as this = - new SyntaxBuilder("_private_") then + new (context : CodegenContext) as this = + new SyntaxBuilder("_private_") then this.Namespaces <- new NamespaceBuilder(this) this.Statements <- new StatementBlockBuilder(this) this.StatementKinds <- new StatementBuilder(this, context) @@ -266,19 +266,19 @@ module SimulationCode = this.Types <- new TypeTransformation(this, TransformationOptions.Disabled) /// Used to generate the list of statements that implement a Q# operation specialization. - and StatementBlockBuilder(parent : SyntaxBuilder) = + and StatementBlockBuilder(parent : SyntaxBuilder) = inherit StatementTransformation(parent, TransformationOptions.NoRebuild) - override this.OnScope (scope : QsScope) = + override this.OnScope (scope : QsScope) = parent.DeclarationsInScope <- scope.KnownSymbols base.OnScope scope override this.OnStatement (node:QsStatement) = - match node.Location with - | Value loc -> + match node.Location with + | Value loc -> let (current, _) = loc.Offset parent.LineNumber <- parent.StartLine |> Option.map (fun start -> start + current + 1) // The Q# compiler reports 0-based line numbers. - | Null -> + | Null -> parent.LineNumber <- None // auto-generated statement; the line number will be set to the specialization declaration parent.DeclarationsInStatement <- node.SymbolDeclarations parent.DeclarationsInScope <- LocalDeclarations.Concat parent.DeclarationsInScope parent.DeclarationsInStatement // only fine because/if a new statement transformation is created for every block! @@ -287,20 +287,20 @@ module SimulationCode = /// Used to generate the statements that implement a Q# operation specialization. and StatementBuilder(parent : SyntaxBuilder, context) = inherit StatementKindTransformation(parent, TransformationOptions.NoRebuild) - + let withLineNumber s = // add a line directive if the operation specifies the source file and a line number match context.fileName, parent.LineNumber with | Some _, Some ln when ln = 0 -> ``#line hidden`` <| s - | Some n, Some ln -> + | Some n, Some ln -> ``#line`` ln n s - | Some n, None -> parent.StartLine |> function - | Some ln -> + | Some n, None -> parent.StartLine |> function + | Some ln -> ``#line`` (ln + 1) n s // we need 1-based line numbers here, and startLine is zero-based | None -> s | _ -> s - + let QArrayType = function | ArrayType b -> generic "QArray" ``<<`` [ roslynTypeName context b ] ``>>`` |> Some | _ -> None @@ -308,17 +308,17 @@ module SimulationCode = let (|Property|_|) = function | CallLikeExpression (op : TypedExpression, args) -> match op.Expression with - | Identifier (id, _) -> + | Identifier (id, _) -> match id with | GlobalCallable n -> funcsAsProps |> List.tryPick (fun (prop, f) -> if (n = f) then Some (args, prop) else None) | _ -> None | _ -> None | _ -> None - + let (|NewUdt|_|) = function | CallLikeExpression (op : TypedExpression, args) -> match op.Expression with - | Identifier (id, _) -> + | Identifier (id, _) -> match id with | GlobalCallable n when isUdt context n |> fst -> Some (n,args) | _ -> None @@ -327,7 +327,7 @@ module SimulationCode = let (|PartialApplication|_|) expression = match expression with - | CallLikeExpression (op,args) when TypedExpression.IsPartialApplication expression -> Some (op,args) + | CallLikeExpression (op,args) when TypedExpression.IsPartialApplication expression -> Some (op,args) | _ -> None // Builds Roslyn code for a Q# expression @@ -348,7 +348,7 @@ module SimulationCode = | RangeLiteral (r,e) -> buildRange r e | NEG n -> ``-`` (buildExpression n) | NOT r -> ! (buildExpression r) - | BNOT i -> ``~~~`` (buildExpression i) + | BNOT i -> ``~~~`` (buildExpression i) | ADD (l, r) -> buildAddExpr ex.ResolvedType l r // We use the Pow extension method from Microsoft.Quantum.Simulation.Core for all valid combinations of types. | POW (l, r) -> ``invoke`` ((buildExpression l) <|.|> (``ident`` "Pow")) ``(`` [ (buildExpression r) ] ``)`` @@ -369,7 +369,7 @@ module SimulationCode = | LTE (l, r) -> ``((`` ((buildExpression l) .<=. (buildExpression r)) ``))`` | GT (l, r) -> ``((`` ((buildExpression l) .>. (buildExpression r)) ``))`` | GTE (l, r) -> ``((`` ((buildExpression l) .>=. (buildExpression r)) ``))`` - | CONDITIONAL (c, t, f) -> ``((`` (buildConditional c t f) ``))`` + | CONDITIONAL (c, t, f) -> ``((`` (buildConditional c t f) ``))`` | CopyAndUpdate (l, i, r) -> buildCopyAndUpdateExpression (l, i, r) | UnwrapApplication e -> (buildExpression e) <|.|> (``ident`` "Data") | ValueTuple vs -> buildTuple vs @@ -383,7 +383,7 @@ module SimulationCode = | PartialApplication (op,args) -> buildPartial ex.ResolvedType ex.TypeParameterResolutions op args // needs to be before NewUdt! | NewUdt (udt,args) -> buildNewUdt udt args // needs to be before CallLikeExpression! | CallLikeExpression (op,args) -> buildApply ex.ResolvedType op args - | MissingExpr -> ``ident`` "_" :> ExpressionSyntax + | MissingExpr -> ``ident`` "_" :> ExpressionSyntax and captureExpression (ex : TypedExpression) = match ex.Expression with @@ -393,44 +393,44 @@ module SimulationCode = | _ -> buildExpression ex | _ -> buildExpression ex - and buildNamedItem ex acc = - match acc with + and buildNamedItem ex acc = + match acc with | LocalVariable name -> (buildExpression ex) <|.|> (``ident`` name.Value) // TODO: Diagnostics | _ -> failwith "Invalid identifier for named item" - and buildAddExpr (exType : ResolvedType) lhs rhs = - match exType.Resolution |> QArrayType with - | Some arrType -> arrType <.> (``ident`` "Add", [buildExpression lhs; buildExpression rhs]) + and buildAddExpr (exType : ResolvedType) lhs rhs = + match exType.Resolution |> QArrayType with + | Some arrType -> arrType <.> (``ident`` "Add", [buildExpression lhs; buildExpression rhs]) | _ -> ``((`` ((buildExpression lhs) <+> (buildExpression rhs)) ``))`` and buildInterpolatedString (s : string) (exs: ImmutableArray) = - if exs.Length <> 0 then + if exs.Length <> 0 then let exprs = exs |> Seq.map buildExpression |> Seq.toList ``invoke`` (``ident`` "String.Format" ) ``(`` (literal s :: exprs) ``)`` else literal s - - and buildId id : ExpressionSyntax = + + and buildId id : ExpressionSyntax = match id with | LocalVariable n-> n.Value |> ``ident`` :> ExpressionSyntax | GlobalCallable n -> - if isCurrentOp context n then + if isCurrentOp context n then Directives.Self |> ``ident`` :> ExpressionSyntax - elif needsFullPath context n then + elif needsFullPath context n then prependNamespaceString n |> ``ident`` :> ExpressionSyntax - else + else n.Name.Value |> ``ident`` :> ExpressionSyntax // TODO: Diagnostics - | InvalidIdentifier -> + | InvalidIdentifier -> failwith "Received InvalidIdentifier" - and buildCopyAndUpdateExpression (lhsEx : TypedExpression, accEx : TypedExpression, rhsEx) = + and buildCopyAndUpdateExpression (lhsEx : TypedExpression, accEx : TypedExpression, rhsEx) = match lhsEx.ResolvedType.Resolution |> QArrayType with - | Some arrayType -> - let lhsAsQArray = ``new`` arrayType ``(`` [buildExpression lhsEx] ``)`` + | Some arrayType -> + let lhsAsQArray = ``new`` arrayType ``(`` [buildExpression lhsEx] ``)`` lhsAsQArray <.> (``ident`` "Modify", [ buildExpression accEx; captureExpression rhsEx ]) // in-place modification | _ -> lhsEx.ResolvedType.Resolution |> function - | UserDefinedType udt -> + | UserDefinedType udt -> let name = QsQualifiedName.New (udt.Namespace, udt.Name) let decl = findUdt context name @@ -440,48 +440,48 @@ module SimulationCode = // TODO: Diagnostics | _ -> failwith "item access expression in copy-and-update expression for user defined type is not a suitable identifier" let updatedItems = new Dictionary() - let rec aggregate (lhs : TypedExpression) = - match lhs.Expression with - | CopyAndUpdate (l, i, r) when l.ResolvedType.Resolution |> isUserDefinedType -> + let rec aggregate (lhs : TypedExpression) = + match lhs.Expression with + | CopyAndUpdate (l, i, r) when l.ResolvedType.Resolution |> isUserDefinedType -> let lhs = aggregate l // need to recur first, or make sure key is not already in dictionary updatedItems.[getItemName i.Expression] <- captureExpression r lhs | _ -> lhs - let lhs = aggregate lhsEx |> buildExpression + let lhs = aggregate lhsEx |> buildExpression updatedItems.[getItemName accEx.Expression] <- captureExpression rhsEx // needs to be after aggregate let root = lhs <|.|> (``ident`` "Data") let items = getAllItems root decl.Type - let rec buildArg = function + let rec buildArg = function | QsTuple args -> args |> Seq.map buildArg |> Seq.toList |> ``tuple`` | QsTupleItem (Named item) -> updatedItems.TryGetValue item.VariableName.Value |> function - | true, rhs -> + | true, rhs -> items.Dequeue() |> ignore rhs | _ -> items.Dequeue() | QsTupleItem _ -> items.Dequeue() - ``new`` (``type`` [ justTheName context name ]) ``(`` [buildArg decl.TypeItems] ``)`` + ``new`` (``type`` [ justTheName context name ]) ``(`` [buildArg decl.TypeItems] ``)`` | _ -> failwith "copy-and-update expressions are currently only supported for arrays and user defined types" - and buildTuple many : ExpressionSyntax = - many |> Seq.map captureExpression |> Seq.toList |> ``tuple`` // captured since we rely on the native C# tuples + and buildTuple many : ExpressionSyntax = + many |> Seq.map captureExpression |> Seq.toList |> ``tuple`` // captured since we rely on the native C# tuples and buildPartial (partialType : ResolvedType) typeParamResolutions opEx args = let (pIn, pOut) = inAndOutputType partialType // The type of the operation constructed by partial application let (oIn, _) = inAndOutputType opEx.ResolvedType // The type of the operation accepting the partial tuples. - let buildPartialMapper () = // may only be executed if there are no more type parameters to be resolved + let buildPartialMapper () = // may only be executed if there are no more type parameters to be resolved let argName = nextArgName() let items = getAllItems (``ident`` argName) pIn let rec argMapping (expr : TypedExpression) = let rec buildMissing = function | Tuple ts -> ts |> Seq.toList |> List.map buildMissing |> ``tuple`` - | _ -> items.Dequeue() - - match expr with + | _ -> items.Dequeue() + + match expr with | Missing -> buildMissing expr.ResolvedType - | Tuple vt -> + | Tuple vt -> match expr.ResolvedType with | Tuple ts when ts.Length = vt.Length -> vt |> Seq.zip ts |> Seq.toList @@ -492,10 +492,10 @@ module SimulationCode = | Item ex -> captureExpression ex // TODO: Diagnostics. | _ -> failwith "partial application contains an error expression" - + let resolvedOrigInputT = ResolvedType.ResolveTypeParameters typeParamResolutions oIn let mapper = [ ``() =>`` [argName] (argMapping {args with ResolvedType = resolvedOrigInputT}) ] - ``new`` (generic "Func" ``<<`` [ (roslynTypeName context pIn); (roslynTypeName context resolvedOrigInputT) ] ``>>``) ``(`` mapper ``)`` + ``new`` (generic "Func" ``<<`` [ (roslynTypeName context pIn); (roslynTypeName context resolvedOrigInputT) ] ``>>``) ``(`` mapper ``)`` // Checks if the expression still has type parameters. // If it does, we can't create the PartialMapper at compile time @@ -507,32 +507,32 @@ module SimulationCode = op <.> (``ident`` "Partial", [ values ]) and buildNewUdt n args = - ``new`` (``type`` [ justTheName context n ]) ``(`` [args |> captureExpression] ``)`` + ``new`` (``type`` [ justTheName context n ]) ``(`` [args |> captureExpression] ``)`` - and buildApply returnType op args = + and buildApply returnType op args = // Checks if the expression points to a non-generic user-defined callable. // Because these have fully-resolved types in the runtime, // they don't need to have the return type explicitly in the apply. - let isNonGenericCallable() = + let isNonGenericCallable() = match op.Expression with | Identifier (_, Value tArgs) when tArgs.Length > 0 -> false - | Identifier (id, _) -> + | Identifier (id, _) -> match id with | GlobalCallable n -> let sameName = match context.current with | None -> false | Some name -> n = name if sameName then // when called recursively, we always need to specify the return type. false else - not (hasTypeParameters [op.ResolvedType]) - | _ -> + not (hasTypeParameters [op.ResolvedType]) + | _ -> false | _ -> false - let useReturnType = + let useReturnType = match returnType.Resolution with | QsTypeKind.UnitType -> false - | _ -> + | _ -> not (isNonGenericCallable()) let apply = if useReturnType then (``ident`` (sprintf "Apply<%s>" (roslynTypeName context returnType))) else (``ident`` "Apply") buildExpression op <.> (apply, [args |> captureExpression]) // we need to capture to guarantee that the result accurately reflects any indirect binding of arguments @@ -556,50 +556,50 @@ module SimulationCode = | Some arrayType -> ``new`` arrayType ``(`` (elems |> Seq.map captureExpression |> Seq.toList) ``)`` // TODO: diagnostics. | _ -> failwith "" - - and buildNewArray b count = - let arrayType = (ArrayType b |> QArrayType).Value + + and buildNewArray b count = + let arrayType = (ArrayType b |> QArrayType).Value arrayType <.> (``ident`` "Create", [count |> buildExpression]) - and buildArrayItem a i = + and buildArrayItem a i = match i.ResolvedType.Resolution with - | Range -> ``invoke`` ((buildExpression a) <|?.|> (``ident`` "Slice")) ``(`` [ (buildExpression i) ] ``)`` - | _ -> ``item`` (buildExpression a) [ (buildExpression i) ] - - let buildBlock (block : QsScope) = + | Range -> ``invoke`` ((buildExpression a) <|?.|> (``ident`` "Slice")) ``(`` [ (buildExpression i) ] ``)`` + | _ -> ``item`` (buildExpression a) [ (buildExpression i) ] + + let buildBlock (block : QsScope) = let builder = new SyntaxBuilder(context) builder.StartLine <- parent.StartLine builder.Statements.OnScope block |> ignore builder.BuiltStatements - let buildSymbolTuple buildTuple buildSymbol symbol = + let buildSymbolTuple buildTuple buildSymbol symbol = let rec buildOne = function // TODO: Diagnostics | InvalidItem -> failwith ("InvalidItem received") | VariableName one -> one.Value |> buildSymbol | VariableNameTuple many -> many |> Seq.map buildOne |> Seq.toList |> buildTuple | DiscardedItem -> "_" |> buildSymbol - // While _ inside C# tuple destructs will properly discard the assignment, + // While _ inside C# tuple destructs will properly discard the assignment, // _ can also be used as variable name in C# where a repeated usage will lead to a compilation error. // We hence auto-generate a name for discarded Q# bindings. match symbol with | DiscardedItem -> nextArgName() |> buildSymbol | _ -> buildOne symbol - let buildSymbolNames buildName = - buildSymbolTuple (String.concat "," >> sprintf "(%s)") buildName + let buildSymbolNames buildName = + buildSymbolTuple (String.concat "," >> sprintf "(%s)") buildName /// returns true if a value of this type contains any arrays /// -> in particular, this does not include the in- and output type of callables - let rec containsArrays (t : ResolvedType) = - match t.Resolution with + let rec containsArrays (t : ResolvedType) = + match t.Resolution with | TupleType ts -> ts |> Seq.exists containsArrays | ArrayType _ -> true | _ -> false // no need to check types within callables - + /// returns true if the given expression initializes a new QArray instance - let rec isArrayInit ex = - match ex.Expression with + let rec isArrayInit ex = + match ex.Expression with | CopyAndUpdate _ | NewArray _ | ADD _ | ValueArray _ -> true | CONDITIONAL (_, l, r) -> isArrayInit l && isArrayInit r | _ -> false @@ -619,23 +619,23 @@ module SimulationCode = |> this.AddStatement QsReturnStatement node - override this.OnVariableDeclaration (node:QsBinding) = + override this.OnVariableDeclaration (node:QsBinding) = let bindsArrays = node.Rhs.ResolvedType |> containsArrays - let rhs = node.Rhs |> captureExpression - let buildBinding buildName = + let rhs = node.Rhs |> captureExpression + let buildBinding buildName = let lhs = node.Lhs |> buildSymbolNames buildName if bindsArrays then // we need to cast to the correct type here (in particular to IQArray for arrays) let t = roslynTypeName context node.Rhs.ResolvedType - ``var`` lhs (``:=`` <| ``cast`` t rhs ) |> this.AddStatement + ``var`` lhs (``:=`` <| ``cast`` t rhs ) |> this.AddStatement else ``var`` lhs (``:=`` <| rhs ) |> this.AddStatement - match node.Kind with + match node.Kind with | MutableBinding -> - match node.Lhs with + match node.Lhs with // no need to insert a destructing statement first - | VariableName varName -> - match node.Rhs.ResolvedType.Resolution |> QArrayType with + | VariableName varName -> + match node.Rhs.ResolvedType.Resolution |> QArrayType with | Some _ when isArrayInit node.Rhs -> // avoid unnecessary copies on construction ``var`` varName.Value (``:=`` <| rhs ) |> this.AddStatement | Some arrType -> // we need to make sure to bind to a new QArray instance here @@ -644,27 +644,27 @@ module SimulationCode = | _ -> buildBinding id // we first need to destruct here, and then make sure all QArrays are built - | VariableNameTuple _ when bindsArrays -> + | VariableNameTuple _ when bindsArrays -> // insert a destructing statement let prefix = nextArgName() let imName = sprintf "%s%s__" prefix - buildBinding imName + buildBinding imName // build the actual binding, making sure all necessary QArrays instances are created - for localVar in parent.DeclarationsInStatement.Variables do + for localVar in parent.DeclarationsInStatement.Variables do let varName = localVar.VariableName.Value - match localVar.Type.Resolution |> QArrayType with - | Some arrType -> + match localVar.Type.Resolution |> QArrayType with + | Some arrType -> let qArray = ``new`` arrType ``(`` [``ident`` (imName varName)] ``)`` ``var`` varName (``:=`` <| qArray) |> this.AddStatement - | _ -> ``var`` varName (``:=`` <| ``ident`` (imName varName)) |> this.AddStatement - | _ -> buildBinding id + | _ -> ``var`` varName (``:=`` <| ``ident`` (imName varName)) |> this.AddStatement + | _ -> buildBinding id | _ -> buildBinding id QsVariableDeclaration node override this.OnValueUpdate (node:QsValueUpdate) = - let rec varNames onTuple onItem (ex : TypedExpression) = - match ex.Expression with + let rec varNames onTuple onItem (ex : TypedExpression) = + match ex.Expression with | MissingExpr -> onItem "_" | Identifier (LocalVariable id, Null) -> onItem id.Value | ValueTuple vs -> vs |> Seq.map (varNames onTuple onItem) |> onTuple @@ -672,67 +672,67 @@ module SimulationCode = | _ -> failwith "unexpected expression in lhs of value update" let lhs, rhs = buildExpression node.Lhs, captureExpression node.Rhs - match node.Lhs.Expression with - | MissingExpr -> ``var`` (nextArgName()) (``:=`` <| buildExpression node.Rhs) |> this.AddStatement + match node.Lhs.Expression with + | MissingExpr -> ``var`` (nextArgName()) (``:=`` <| buildExpression node.Rhs) |> this.AddStatement // no need to insert a destructing statement first - | Identifier (LocalVariable id, Null) -> - let matchesIdentifier (ex : TypedExpression) = - match ex.Expression with + | Identifier (LocalVariable id, Null) -> + let matchesIdentifier (ex : TypedExpression) = + match ex.Expression with | Identifier (LocalVariable rhsId, Null) when rhsId.Value = id.Value -> true | _ -> false let isArray = function | ArrayType _ -> true | _ -> false - match node.Rhs.Expression with + match node.Rhs.Expression with | CopyAndUpdate (l, a, r) when l |> matchesIdentifier && l.ResolvedType.Resolution |> isArray -> // we do an in-place modification in this case let access, rhs = buildExpression a, captureExpression r (buildExpression l) <.> (``ident`` "Modify", [ access; rhs ]) |> statement |> this.AddStatement - | _ when node.Rhs |> matchesIdentifier -> () // unnecessary statement + | _ when node.Rhs |> matchesIdentifier -> () // unnecessary statement | _ -> node.Rhs.ResolvedType.Resolution |> QArrayType |> function - | Some _ when isArrayInit node.Rhs -> // avoid unnecessary copies here - lhs <-- rhs |> statement |> this.AddStatement + | Some _ when isArrayInit node.Rhs -> // avoid unnecessary copies here + lhs <-- rhs |> statement |> this.AddStatement | Some arrType -> // we need to make sure to bind to a new QArray instance here let qArray = ``new`` arrType ``(`` [rhs] ``)`` lhs <-- qArray |> statement |> this.AddStatement | _ -> lhs <-- rhs |> statement |> this.AddStatement // we first need to destruct here, and then make sure all QArrays are built - | _ when containsArrays node.Rhs.ResolvedType -> + | _ when containsArrays node.Rhs.ResolvedType -> // insert a destructing statement let prefix = nextArgName() let imName name = if name = "_" then name else sprintf "%s%s__" prefix name let tempBinding = varNames (fun ids -> String.Join (",", ids) |> sprintf "(%s)") imName node.Lhs - ``var`` tempBinding (``:=`` <| rhs ) |> this.AddStatement + ``var`` tempBinding (``:=`` <| rhs ) |> this.AddStatement // build the actual binding, making sure all necessary QArrays instances are created let ids = varNames (Seq.collect id) (fun id -> seq{ if id <> "_" then yield id}) node.Lhs - for id in ids do + for id in ids do let decl = parent.DeclarationsInScope.Variables |> Seq.tryFind (fun d -> d.VariableName.Value = id) - match decl |> Option.map (fun d -> d.Type.Resolution |> QArrayType) |> Option.flatten with + match decl |> Option.map (fun d -> d.Type.Resolution |> QArrayType) |> Option.flatten with | Some arrType -> // we need to make sure to create a new QArray instance here let qArray = ``new`` arrType ``(`` [imName id |> ``ident``] ``)`` (``ident`` id) <-- qArray |> statement |> this.AddStatement - | _ -> (``ident`` id) <-- (imName id |> ``ident``) |> statement |> this.AddStatement + | _ -> (``ident`` id) <-- (imName id |> ``ident``) |> statement |> this.AddStatement | _ -> lhs <-- rhs |> statement |> this.AddStatement QsValueUpdate node - override this.OnConditionalStatement (node:QsConditionalStatement) = + override this.OnConditionalStatement (node:QsConditionalStatement) = let all = node.ConditionalBlocks let (cond, thenBlock) = all.[0] let cond = cond |> buildExpression let thenBlock = thenBlock.Body |> buildBlock - let others = [ - for i in 1 .. all.Length - 1 -> + let others = [ + for i in 1 .. all.Length - 1 -> let (cond, block) = all.[i] cond |> buildExpression, block.Body |> buildBlock ] - let elseBlock = - match node.Default with + let elseBlock = + match node.Default with | Null -> None | Value block -> ``else`` (buildBlock block.Body) |> Some ``if`` ``(`` cond ``)`` thenBlock (``elif`` others elseBlock) |> this.AddStatement QsConditionalStatement node - + override this.OnForStatement (node:QsForStatement) = let sym = node.LoopItem |> fst |> buildSymbolNames id let range = node.IterationValues |> captureExpression @@ -747,34 +747,34 @@ module SimulationCode = ``while`` ``(`` cond ``)`` body |> this.AddStatement QsWhileStatement node - - override this.OnRepeatStatement rs = + + override this.OnRepeatStatement rs = let buildTest test fixup = let condition = buildExpression test let thens = [``break``] let elses = buildBlock fixup ``if`` ``(`` condition ``)`` thens (Some (``else`` elses)) - ``while`` ``(`` ``true`` ``)`` + ``while`` ``(`` ``true`` ``)`` ((buildBlock rs.RepeatBlock.Body) @ [buildTest rs.SuccessCondition rs.FixupBlock.Body]) |> this.AddStatement QsRepeatStatement rs - override this.OnQubitScope (using:QsQubitScope) = - let (alloc, release) = - match using.Kind with + override this.OnQubitScope (using:QsQubitScope) = + let (alloc, release) = + match using.Kind with | Allocate -> ("Allocate", "Release") | Borrow -> ("Borrow", "Return") - let rec removeDiscarded sym = + let rec removeDiscarded sym = match sym with | VariableName _ -> sym | DiscardedItem -> nextArgName() |> NonNullable.New |> VariableName | VariableNameTuple many -> many |> Seq.map removeDiscarded |> ImmutableArray.CreateRange |> VariableNameTuple | InvalidItem -> failwith ("InvalidItem received") - let rec buildInitializeExpression (exp:ResolvedInitializer) = + let rec buildInitializeExpression (exp:ResolvedInitializer) = match exp.Resolution with - | SingleQubitAllocation -> ((``ident`` alloc) <.> (``ident`` "Apply", [])) - | QubitRegisterAllocation e -> ((``ident`` alloc) <.> (``ident`` "Apply", [ (buildExpression e) ])) + | SingleQubitAllocation -> ((``ident`` alloc) <.> (``ident`` "Apply", [])) + | QubitRegisterAllocation e -> ((``ident`` alloc) <.> (``ident`` "Apply", [ (buildExpression e) ])) | QubitTupleAllocation many -> many |> Seq.map buildInitializeExpression |> List.ofSeq |> ``tuple`` // todo: diagnostics | InvalidInitializer -> failwith ("InvalidInitializer received") @@ -793,12 +793,12 @@ module SimulationCode = match (symbol, expr.Resolution) with | VariableName one, SingleQubitAllocation -> [ buildOne one.Value ] | VariableName one, QubitRegisterAllocation _ -> [ buildOne one.Value ] - | VariableName one, QubitTupleAllocation _ -> (buildDeconstruct one.Value expr) + | VariableName one, QubitTupleAllocation _ -> (buildDeconstruct one.Value expr) | VariableNameTuple ss, QubitTupleAllocation aa -> Seq.zip ss aa |> Seq.map buildReleaseExpression |> Seq.toList |> List.concat | _ -> failwith ("InvalidItem received") parent.LineNumber <- currentLine - releases - + releases + let symbols = removeDiscarded using.Binding.Lhs let deallocationFlagName = nextArgName() let deallocationFlagIdentifier = ``ident`` deallocationFlagName @@ -810,12 +810,12 @@ module SimulationCode = let deallocation = buildReleaseExpression (symbols, using.Binding.Rhs) // To force that exceptions thrown during the execution of the allocation scope take precedence over the ones thrown upon release - // we catch all exceptions in a variable and throw after releaseing if necessary. + // we catch all exceptions in a variable and throw after releaseing if necessary. // Indicates if deallocation is needed. It is not needed when exception is thrown. let deallocationFlagDeclaration = ``typed var`` "bool" deallocationFlagName (``:=`` ``true`` |> Some) |> ``#line hidden`` :> StatementSyntax - - let catch = + + let catch = let setFlagToFalse = deallocationFlagIdentifier <-- ``false`` |> statement ``catch`` None [setFlagToFalse; ``throw`` None] // use standard mechanism to rethrow the exception by using "throw;" let finallyBlock = [``if`` ``(`` deallocationFlagIdentifier ``)`` deallocation None] @@ -830,27 +830,27 @@ module SimulationCode = parent.LineNumber <- currentLine QsQubitScope using - override this.OnFailStatement fs = + override this.OnFailStatement fs = let failException = ``new`` (``type`` ["ExecutionFailException"]) ``(`` [ (buildExpression fs) ] ``)`` this.AddStatement (``throw`` <| Some failException) QsFailStatement fs - and NamespaceBuilder (parent : SyntaxBuilder) = + and NamespaceBuilder (parent : SyntaxBuilder) = inherit NamespaceTransformation(parent, TransformationOptions.NoRebuild) - override this.OnSpecializationDeclaration (sp : QsSpecialization) = + override this.OnSpecializationDeclaration (sp : QsSpecialization) = count <- 0 - match sp.Location with + match sp.Location with | Value location -> parent.StartLine <- Some (location.Offset |> fst) | Null -> parent.StartLine <- None // TODO: we may need to have the means to know which original declaration the code came from base.OnSpecializationDeclaration sp - + let operationDependencies (od:QsCallable) = let seeker = new OperationsSeeker() seeker.Namespaces.OnCallableDeclaration od |> ignore seeker.SharedState |> Seq.toList - let getOpName context n = + let getOpName context n = if needsFullPath context n then prependNamespaceString n else if isCurrentOp context n then Directives.Self else n.Name.Value @@ -863,9 +863,9 @@ module SimulationCode = let signature = context.allCallables.[n].Signature let tIn = signature.ArgumentType let tOut = signature.ReturnType - let count = (getTypeParameters [tIn;tOut]).Length + let count = (getTypeParameters [tIn;tOut]).Length sprintf "%s<%s>" opName (String.replicate (count - 1) ",") - else + else opName ``invoke`` (``ident`` "typeof") ``(`` [``ident`` name] ``)`` @@ -876,8 +876,8 @@ module SimulationCode = let buildOne n = let name = getOpName context n let lhs = ``ident`` "this" <|.|> ``ident`` name - let rhs = - if (isCurrentOp context n) && not (isGeneric context n) then + let rhs = + if (isCurrentOp context n) && not (isGeneric context n) then "this" |> ``ident`` :> ExpressionSyntax else let signature = roslynCallableTypeName context n @@ -885,20 +885,20 @@ module SimulationCode = (``invoke`` factoryGet ``(`` [ (getTypeOfOp context n) ] ``)``) statement (lhs <-- rhs) operations - |> List.map buildOne - ``method`` "void" "Init" ``<<`` [] ``>>`` - ``(`` parameters ``)`` + |> List.map buildOne + ``method`` "void" "Init" ``<<`` [] ``>>`` + ``(`` parameters ``)`` [ ``public``; ``override`` ] ``{`` body ``}`` :> MemberDeclarationSyntax - + /// Returns the constructor for the given operation. let buildConstructor context name : MemberDeclarationSyntax = - ``constructor`` name ``(`` [ ("m", ``type`` "IOperationFactory") ] ``)`` + ``constructor`` name ``(`` [ ("m", ``type`` "IOperationFactory") ] ``)`` ``:`` [ "m" ] [ ``public`` ] ``{`` [] ``}`` - :> MemberDeclarationSyntax + :> MemberDeclarationSyntax /// For each Operation used in the given OperationDeclartion, returns /// a Property that returns an instance of the operation by calling the @@ -930,7 +930,7 @@ module SimulationCode = /// Returns a static property of type OperationInfo using the operation's input and output types. let buildOperationInfoProperty (globalContext:CodegenContext) operationInput operationOutput operationName = - let propertyType = + let propertyType = match globalContext.ExecutionTarget with | target when target = AssemblyConstants.HoneywellProcessor -> sprintf "HoneywellEntryPointInfo<%s, %s>" operationInput operationOutput | target when target = AssemblyConstants.IonQProcessor -> sprintf "IonQEntryPointInfo<%s, %s>" operationInput operationOutput @@ -946,7 +946,7 @@ module SimulationCode = let buildSpecializationBody context (sp:QsSpecialization) = match sp.Implementation with - | Provided (args, _) -> + | Provided (args, _) -> let returnType = sp.Signature.ReturnType let statements = let builder = new SyntaxBuilder(context) @@ -954,12 +954,12 @@ module SimulationCode = builder.BuiltStatements let inData = ``ident`` "__in__" - let ret = + let ret = match returnType.Resolution with | QsTypeKind.UnitType -> - [ - ``#line hidden`` <| - ``return`` ( Some ((``ident`` "QVoid") <|.|> (``ident`` "Instance")) ) + [ + ``#line hidden`` <| + ``return`` ( Some ((``ident`` "QVoid") <|.|> (``ident`` "Instance")) ) ] | _ -> [] @@ -972,79 +972,79 @@ module SimulationCode = match args with | QsTupleItem one -> (one.VariableName |> name, []) | QsTuple many -> - if many.Length = 0 then + if many.Length = 0 then ("__in__", []) - elif many.Length = 1 then + elif many.Length = 1 then ("__in__", [ ``var`` (buildVariableName many.[0]) (``:=`` <| inData) ]) - else + else ("__in__", [ ``var`` (buildVariableName args) (``:=`` <| inData) ]) Some (``() => {}`` [ argName ] (argsInit @ statements @ ret) :> ExpressionSyntax) - | Generated SelfInverse -> - let adjointedBodyName = - match sp.Kind with + | Generated SelfInverse -> + let adjointedBodyName = + match sp.Kind with | QsAdjoint -> "Body" | QsControlledAdjoint -> "ControlledBody" //TODO: diagnostics. | _ -> "Body" Some (``ident`` adjointedBodyName :> ExpressionSyntax) - | _ -> + | _ -> None - + let buildSpecialization context (sp:QsSpecialization) : (PropertyDeclarationSyntax * _) option = let inType = roslynTypeName context sp.Signature.ArgumentType let outType = roslynTypeName context sp.Signature.ReturnType let propertyType = "Func<" + inType + ", " + outType + ">" - let bodyName = - match sp.Kind with + let bodyName = + match sp.Kind with | QsBody -> "Body" | QsAdjoint -> "Adjoint" | QsControlled -> "Controlled" | QsControlledAdjoint -> "ControlledAdjoint" let body = buildSpecializationBody context sp let attributes = - match sp.Location with + match sp.Location with | Null -> [] | Value location -> [ // since the line numbers throughout the generated code are 1-based, let's also choose them 1-based here let startLine = fst location.Offset + 1 - let endLine = - match context.declarationPositions.TryGetValue sp.SourceFile with - | true, startPositions -> + let endLine = + match context.declarationPositions.TryGetValue sp.SourceFile with + | true, startPositions -> let index = startPositions.IndexOf location.Offset if index + 1 >= startPositions.Count then -1 else fst startPositions.[index + 1] + 1 //TODO: diagnostics. | false, _ -> startLine - ``attribute`` None (``ident`` "SourceLocation") [ - ``literal`` sp.SourceFile.Value - ``ident`` "OperationFunctor" <|.|> ``ident`` bodyName - ``literal`` startLine + ``attribute`` None (``ident`` "SourceLocation") [ + ``literal`` sp.SourceFile.Value + ``ident`` "OperationFunctor" <|.|> ``ident`` bodyName + ``literal`` startLine ``literal`` endLine ] ] - match body with + match body with | Some body -> let bodyName = if bodyName = "Body" then bodyName else bodyName + "Body" - let impl = + let impl = ``property-arrow_get`` propertyType bodyName [``public``; ``override``] ``get`` (``=>`` body) Some (impl, attributes) | None -> - None + None /// Returns a flat list (name, type) with all the named parameters of a DeconstructedTuple - let flatArgumentsList context args = + let flatArgumentsList context args = let rec flatOne found = function | QsTupleItem one -> match one.VariableName with | ValidName n -> found @ [n.Value, one.Type |> roslynTypeName context] | InvalidName -> found - | QsTuple many -> + | QsTuple many -> many |> Seq.fold flatOne found args - |> flatOne [] + |> flatOne [] /// Maps the name and type of each named item in the argument tuple. let internal mapArgumentTuple mapping context arguments (argumentType : ResolvedType) = @@ -1057,54 +1057,54 @@ module SimulationCode = many |> Seq.map buildTuple |> List.ofSeq |> ``tuple`` if isTuple argumentType.Resolution then buildTuple arguments - else match flatArgumentsList context arguments with + else match flatArgumentsList context arguments with | [] -> ``ident`` "QVoid" <|.|> ``ident`` "Instance" | [name, typeName] -> mapping (name, typeName) :> ExpressionSyntax | flatArgs -> flatArgs |> List.map mapping |> ``tuple`` let buildRun context className arguments argumentType returnType : MemberDeclarationSyntax = - let inType = roslynTypeName context argumentType + let inType = roslynTypeName context argumentType let outType = roslynTypeName context returnType let task = sprintf "System.Threading.Tasks.Task<%s>" outType let flatArgs = arguments |> flatArgumentsList context let opFactoryTypes = [ className; inType; outType ] - + let uniqueArgName = "__m__" let runArgs = mapArgumentTuple (fst >> ``ident``) context arguments argumentType - let body = - [ + let body = + [ ``return`` (Some ((``ident`` uniqueArgName) <.> (``generic`` "Run" ``<<`` opFactoryTypes ``>>``, [ runArgs ]))) ] - let args = - (``param`` uniqueArgName ``of`` (``type`` "IOperationFactory") ) - :: (flatArgs |> List.map (fun (name, roslynType) -> (``param`` name ``of`` (``type`` roslynType)) ) ) - ``method`` task "Run" ``<<`` [] ``>>`` - ``(`` args ``)`` + let args = + (``param`` uniqueArgName ``of`` (``type`` "IOperationFactory") ) + :: (flatArgs |> List.map (fun (name, roslynType) -> (``param`` name ``of`` (``type`` roslynType)) ) ) + ``method`` task "Run" ``<<`` [] ``>>`` + ``(`` args ``)`` [``public``; ``static``] ``{`` body ``}`` :> MemberDeclarationSyntax - + let findUdtBase context n = let udt = findUdt context n udt.Type - let rec canHaveQubits context (qsharpType:ResolvedType) = + let rec canHaveQubits context (qsharpType:ResolvedType) = match qsharpType.Resolution with | QsTypeKind.Qubit -> true | QsTypeKind.ArrayType at -> canHaveQubits context at - | QsTypeKind.TupleType tt -> tt |> Seq.fold (fun state m -> state || canHaveQubits context m) false + | QsTypeKind.TupleType tt -> tt |> Seq.fold (fun state m -> state || canHaveQubits context m) false | QsTypeKind.UserDefinedType n -> QsQualifiedName.New (n.Namespace, n.Name) - |> findUdtBase context + |> findUdtBase context |> canHaveQubits context | QsTypeKind.Operation _ | QsTypeKind.Function _ -> true | QsTypeKind.TypeParameter _ -> true | _ -> false - let findQubitFields context (qsharpType:ResolvedType) = + let findQubitFields context (qsharpType:ResolvedType) = let item_n n = ``ident`` (sprintf "Item%d" (n+1)) let rec buildSimpleTerm current nullable (t:ResolvedType) = @@ -1112,7 +1112,7 @@ module SimulationCode = | QsTypeKind.Qubit -> [ t, current ] | QsTypeKind.Operation _ - | QsTypeKind.Function _ + | QsTypeKind.Function _ | QsTypeKind.TypeParameter _ | QsTypeKind.ArrayType _ -> if canHaveQubits context t then @@ -1121,21 +1121,21 @@ module SimulationCode = [] | QsTypeKind.UserDefinedType n -> QsQualifiedName.New (n.Namespace, n.Name) - |> findUdtBase context + |> findUdtBase context |> buildSimpleTerm (current <|?.|> (``ident`` "Data")) false | QsTypeKind.TupleType tt -> let buildOne j t = - if nullable then + if nullable then buildSimpleTerm (current <|?.|> (item_n j)) false t - else + else buildSimpleTerm (current <|.|> (item_n j)) false t tt |> Seq.mapi buildOne |> List.concat | _ -> [] match qsharpType.Resolution with - | QsTypeKind.TupleType many -> + | QsTypeKind.TupleType many -> many |> Seq.mapi ( fun j -> buildSimpleTerm ( ``ident`` "Data" <|.|> item_n j ) false ) |> List.concat - | one -> + | one -> qsharpType |> buildSimpleTerm ( ``ident`` "Data" ) true let areAllQubitArgs (argsTypes:ResolvedType list) = @@ -1144,63 +1144,63 @@ module SimulationCode = | _ -> false argsTypes |> List.fold (fun st t -> st && isOne t.Resolution) true - let buildQubitsField context (qsharpType:ResolvedType) = - let fields = qsharpType |> findQubitFields context + let buildQubitsField context (qsharpType:ResolvedType) = + let fields = qsharpType |> findQubitFields context let (fieldTypes, fieldPaths) = fields |> List.unzip if areAllQubitArgs fieldTypes then let buildOne path = ``yield return`` path - match fieldPaths with - | [] -> - ``property-arrow_get`` "System.Collections.Generic.IEnumerable" "IApplyData.Qubits" [] + match fieldPaths with + | [] -> + ``property-arrow_get`` "System.Collections.Generic.IEnumerable" "IApplyData.Qubits" [] ``get`` (``=>`` ``null``) | _ -> - ``property-get`` "System.Collections.Generic.IEnumerable" "IApplyData.Qubits" [] + ``property-get`` "System.Collections.Generic.IEnumerable" "IApplyData.Qubits" [] ``get`` (fieldPaths |> List.map buildOne) else - // this implementation is a workaround for the .NET Core issue discussed here: + // this implementation is a workaround for the .NET Core issue discussed here: // https://github.com/microsoft/qsharp-runtime/issues/116 let mutable count = 0 let nextName() = count <- count + 1 sprintf "__temp%d__" count let mutable items = [] - for (t, token) in fields do + for (t, token) in fields do match t.Resolution with | QsTypeKind.Function _ | QsTypeKind.Operation _ | QsTypeKind.ArrayType _ | QsTypeKind.UserDefinedType _ - | QsTypeKind.Qubit -> + | QsTypeKind.Qubit -> let qs = ``((`` ( ``cast`` "IApplyData" token) ``))`` <|?.|> ``ident`` "Qubits" items <- (null, qs) :: items - | _ -> + | _ -> let id = nextName() let decl = ``var`` id (``:=`` token) let qs = (``ident`` id) ( ``ident`` "GetQubits", [] ) items <- (decl, qs) :: items items <- items |> List.rev - let statements = + let statements = match fields with | [] -> [``return`` (Some ``null``)] - | [_] -> + | [_] -> [ let (decl, qs) = items.Head; if decl <> null then yield decl yield ``return`` (snd items.Head |> Some) - ] + ] | _ -> [ for (decl, _) in items do if decl <> null then yield decl let qs = ( ``ident`` "Qubit" <.> (``ident`` "Concat", items |> List.map snd) ) yield ``return`` (Some qs) ] - ``property-get`` "System.Collections.Generic.IEnumerable" "IApplyData.Qubits" [] + ``property-get`` "System.Collections.Generic.IEnumerable" "IApplyData.Qubits" [] ``get`` statements :> MemberDeclarationSyntax |> List.singleton - + let buildName name = - ``property-arrow_get`` "String" "ICallable.Name" [ ] + ``property-arrow_get`` "String" "ICallable.Name" [ ] ``get`` (``=>`` (``literal`` name) ) :> MemberDeclarationSyntax @@ -1209,7 +1209,7 @@ module SimulationCode = let ns = name.Namespace.Value let n = name.Name.Value if ns = "" then n else ns + "." + n - ``property-arrow_get`` "String" "ICallable.FullName" [ ] + ``property-arrow_get`` "String" "ICallable.FullName" [ ] ``get`` (``=>`` (``literal`` fqn) ) :> MemberDeclarationSyntax @@ -1217,8 +1217,8 @@ module SimulationCode = let testOutputHandle = "Output" let buildOutput () = [ - ``propg`` outputHelperInterface testOutputHandle [ ``internal`` ] - :> MemberDeclarationSyntax + ``propg`` outputHelperInterface testOutputHandle [ ``internal`` ] + :> MemberDeclarationSyntax ] let buildUnitTest (targetName : QsQualifiedName) opName opStart opSourceFile = @@ -1257,7 +1257,7 @@ module SimulationCode = let buildDataClass = let buildValueTupleConstructor = let args = [ ("data", ``type`` (roslynTypeName context qsharpType)) ] - ``constructor`` name ``(`` args ``)`` + ``constructor`` name ``(`` args ``)`` ``:`` [ "data" ] [ ``public`` ] ``{`` @@ -1274,27 +1274,27 @@ module SimulationCode = (constructors @ qubitsField) ``}`` :> MemberDeclarationSyntax - let buildMethod t body = + let buildMethod t body = let baseType = (roslynTypeName context t) let args = [ (``param`` "data" ``of`` (``type`` (roslynTypeName context t)) ) ] - ``arrow_method`` "IApplyData" (sprintf "__data%s" name) ``<<`` [] ``>>`` - ``(`` args ``)`` + ``arrow_method`` "IApplyData" (sprintf "__data%s" name) ``<<`` [] ``>>`` + ``(`` args ``)`` [``public``; ``override``] ( Some ( ``=>`` body) ) :> MemberDeclarationSyntax match qsharpType.Resolution with - | QsTypeKind.UnitType - | QsTypeKind.Qubit + | QsTypeKind.UnitType + | QsTypeKind.Qubit | QsTypeKind.UserDefinedType _ - | QsTypeKind.ArrayType _ -> + | QsTypeKind.ArrayType _ -> (``ident`` "data") |> buildMethod qsharpType, None - | QsTypeKind.TupleType vt -> + | QsTypeKind.TupleType vt -> ( ``new`` (``type`` name) ``(`` [ ``ident`` "data" ] ``)`` ) |> buildMethod qsharpType , (Some buildDataClass) - | _ -> + | _ -> ( ``new`` (``generic`` "QTuple" ``<<`` [ roslynTypeName context qsharpType ] ``>>``) ``(`` [ ``ident`` "data" ] ``)`` ) |> buildMethod qsharpType, None - let typeParametersNames signature = + let typeParametersNames signature = // TODO Diagnostics let name = function | ValidName n -> sprintf "__%s__" n.Value | InvalidName -> "__" signature.TypeParameters |> Seq.map name |> Seq.sort |> Seq.toList @@ -1302,17 +1302,17 @@ module SimulationCode = let findClassName context (op: QsCallable) = let name = op.FullName.Name.Value let typeParameters = typeParametersNames op.Signature - let nonGeneric = if typeParameters.IsEmpty then name else sprintf "%s<%s>" name (String.Join(",", typeParameters)) + let nonGeneric = if typeParameters.IsEmpty then name else sprintf "%s<%s>" name (String.Join(",", typeParameters)) (name, nonGeneric) - let isAbstract op = + let isAbstract op = let isBody (sp:QsSpecialization) = match sp.Kind with | QsBody when sp.Implementation <> Intrinsic -> true | _ -> false not (op.Specializations |> Seq.exists isBody) let isFunction (op:QsCallable) = match op.Kind with | Function -> true | _ -> false let buildTestClass (testTargets : QsQualifiedName list) (targetName : QsQualifiedName) opName (op : QsCallable) = - let className = + let className = let requiresQualification = (testTargets |> List.filter (fun t -> t.Name.Value = targetName.Name.Value)).Length > 1 if requiresQualification then sprintf "%s_%s" (targetName.Namespace.Value.Replace('.', '_')) targetName.Name.Value else targetName.Name.Value @@ -1321,8 +1321,8 @@ module SimulationCode = ``constructor`` className ``(`` [ (testOutputHandle, ``type`` outputHelperInterface) ] ``)`` ``:`` [] [``public``] - ``{`` - [ + ``{`` + [ ``ident`` "this" <|.|> ``ident`` testOutputHandle <-- ``ident`` testOutputHandle |> statement ] ``}`` @@ -1331,16 +1331,16 @@ module SimulationCode = let properties = buildOutput () let methods = - match op.Location with + match op.Location with | Value location -> [ buildUnitTest targetName opName (fst location.Offset) op.SourceFile.Value ] // TODO: diagnostics | Null -> failwith "missing location for unit test" - + ``class`` className ``<<`` [] ``>>`` ``:`` None ``,`` [] [``public``] ``{`` - (constructors @ properties @ methods) + (constructors @ properties @ methods) ``}`` let private classAccessModifier = function @@ -1356,33 +1356,33 @@ module SimulationCode = let outType = op.Signature.ReturnType |> roslynTypeName context let constructors = [ (buildConstructor context name) ] - let properties = + let properties = let opProperties = buildOpsProperties context opNames - buildName name :: - buildFullName context.current.Value :: - if globalContext.entryPoints |> Seq.contains op.FullName then - buildOperationInfoProperty globalContext inType outType nonGenericName :: + buildName name :: + buildFullName context.current.Value :: + if globalContext.entryPoints |> Seq.contains op.FullName then + buildOperationInfoProperty globalContext inType outType nonGenericName :: opProperties else opProperties - + let baseOp = - if isFunction op then + if isFunction op then "Function" else let (adj, ctrl) = op.Signature.Information.Characteristics.SupportedFunctors |> hasAdjointControlled - match (adj, ctrl) with + match (adj, ctrl) with | (false , false) -> "Operation" | (true , false) -> "Adjointable" | (false , true ) -> "Controllable" | (true , true ) -> "Unitary" - + let typeArgsInterface = if (baseOp = "Operation" || baseOp = "Function") then [inType; outType] else [inType] let typeParameters = typeParametersNames op.Signature let baseClass = genericBase baseOp ``<<`` typeArgsInterface ``>>`` - let bodies, attr = - op.Specializations |> Seq.map (buildSpecialization context) |> Seq.choose id |> Seq.toList + let bodies, attr = + op.Specializations |> Seq.map (buildSpecialization context) |> Seq.choose id |> Seq.toList |> List.map (fun (x, y) -> (x :> MemberDeclarationSyntax, y)) |> List.unzip - let inData = (buildDataWrapper context "In" op.Signature.ArgumentType) + let inData = (buildDataWrapper context "In" op.Signature.ArgumentType) let outData = (buildDataWrapper context "Out" op.Signature.ReturnType) let defaultTargetNs = NonNullable<_>.New("Microsoft.Quantum.Simulation.Simulators") @@ -1407,7 +1407,7 @@ module SimulationCode = let innerClasses = ([ inData |> snd; outData |> snd ] |> List.choose id) @ unitTests let methods = [ opNames |> buildInit context; inData |> fst; outData |> fst; buildRun context nonGenericName op.ArgumentTuple op.Signature.ArgumentType op.Signature.ReturnType ] - + let modifiers = let access = classAccessModifier op.Modifiers.Access if isAbstract op then @@ -1419,7 +1419,7 @@ module SimulationCode = ``class`` name ``<<`` typeParameters ``>>`` ``:`` (Some baseClass) ``,`` [ ``simpleBase`` "ICallable" ] modifiers ``{`` - (constructors @ innerClasses @ properties @ bodies @ methods) + (constructors @ innerClasses @ properties @ bodies @ methods) ``}`` ) @@ -1429,15 +1429,15 @@ module SimulationCode = let buildUdtClass (globalContext:CodegenContext) (udt: QsCustomType) = let context = globalContext.setUdt udt let name = udt.FullName.Name.Value - let qsharpType = udt.Type - let buildEmtpyConstructor = - let baseTupleType = - match qsharpType.Resolution with + 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 ``)`` + ``constructor`` name ``(`` args ``)`` ``:`` defaultValue [ ``public`` ] ``{`` @@ -1447,32 +1447,39 @@ module SimulationCode = let buildBaseTupleConstructor = let baseTupleType = (roslynTypeName context qsharpType) let args = [ ("data", ``type`` baseTupleType) ] - ``constructor`` name ``(`` args ``)`` + ``constructor`` name ``(`` args ``)`` ``:`` [ "data" ] [ ``public`` ] ``{`` [] ``}`` :> MemberDeclarationSyntax - - let buildNamedItemFields = - let items = getAllItems (``ident`` "Data") qsharpType - let rec buildProps = function - | QsTuple items -> items |> Seq.collect (fun i -> buildProps i) - | QsTupleItem (Anonymous _) -> items.Dequeue() |> ignore; Seq.empty - | QsTupleItem (Named decl) -> seq { yield - ``property-arrow_get`` (roslynTypeName context decl.Type) decl.VariableName.Value [ ``public`` ] - ``get`` (``=>`` (items.Dequeue())) - :> MemberDeclarationSyntax} - buildProps udt.TypeItems |> Seq.toList - let buildItemFields = + let buildNamedItemFields = + let produceProperty (decl : LocalVariableDeclaration>) valueExpr = + ``property-arrow_get`` (roslynTypeName context decl.Type) decl.VariableName.Value [ ``public`` ] + ``get`` (``=>`` valueExpr) :> MemberDeclarationSyntax + let rec buildProps current = function + | QsTuple items -> items |> Seq.mapi (fun i x -> buildProps (current <|.|> ``ident`` ("Item" + (i+1).ToString())) x) |> Seq.collect id + | QsTupleItem (Anonymous _) -> Seq.empty + | QsTupleItem (Named decl) -> seq { yield produceProperty decl current } + // UDT types are packaged differently if there is one constituent type, or many. + // This function handles that difference in packaging. + let rec readType typeItem = + match typeItem with + | QsTuple items when items.IsEmpty -> Seq.empty + | QsTuple items when items.Length = 1 -> items |> Seq.head |> readType + | QsTuple _ -> buildProps (``ident`` "Data") typeItem + | QsTupleItem (Anonymous _) -> Seq.empty + | QsTupleItem (Named decl) -> seq { yield produceProperty decl (``ident`` "Data") } + readType udt.TypeItems |> Seq.toList + let buildItemFields = let buildOne i t = - ``property-arrow_get`` (roslynTypeName context t) (sprintf "Item%d" (i+1)) [ ``public`` ] + ``property-arrow_get`` (roslynTypeName context t) (sprintf "Item%d" (i+1)) [ ``public`` ] ``get`` (``=>`` (``ident`` "Data" <|.|> ``ident`` (sprintf "Item%d" (i+1)))) :> MemberDeclarationSyntax match qsharpType.Resolution with | QsTypeKind.TupleType many -> many |> Seq.mapi buildOne |> List.ofSeq - | _ -> [] + | _ -> [] let buildDeconstruct = let body = let buildOne i t = @@ -1482,48 +1489,48 @@ module SimulationCode = match qsharpType.Resolution with | QsTypeKind.TupleType many -> many |> Seq.mapi buildOne |> List.ofSeq | _ -> [] - let parameters = + let parameters = let buildOneParameter i t = - let paramType = t |> roslynTypeName context + let paramType = t |> roslynTypeName context ``out param`` (sprintf "item%d" (i+1)) ``of`` (``type`` paramType) match qsharpType.Resolution with | QsTypeKind.TupleType many -> many |> Seq.mapi buildOneParameter |> List.ofSeq | _ -> [] - ``method`` "void" "Deconstruct" ``<<`` [] ``>>`` - ``(`` parameters ``)`` + ``method`` "void" "Deconstruct" ``<<`` [] ``>>`` + ``(`` parameters ``)`` [ ``public`` ] ``{`` body ``}`` :> MemberDeclarationSyntax - + let baseClassName = udtBaseClassName context qsharpType let baseClass = ``simpleBase`` baseClassName let modifiers = [ classAccessModifier udt.Modifiers.Access ] - let interfaces = [ ``simpleBase`` "IApplyData" ] + let interfaces = [ ``simpleBase`` "IApplyData" ] let constructors = [ buildEmtpyConstructor; buildBaseTupleConstructor ] let qubitsField = buildQubitsField context qsharpType let itemFields = buildNamedItemFields @ buildItemFields let allFields = itemFields @ qubitsField let allMethods = [ buildDeconstruct ] - + ``class`` name ``<<`` [] ``>>`` ``:`` (Some baseClass) ``,`` interfaces modifiers ``{`` (constructors @ allFields @ allMethods) ``}`` :> MemberDeclarationSyntax - + // Generates the code for all the elements of the given namespace. - let buildNamespace globalContext (nsName : NonNullable, localElements : QsNamespaceElement list) = + let buildNamespace globalContext (nsName : NonNullable, localElements : QsNamespaceElement list) = let buildOne = function | QsCallable op when op.Kind = TypeConstructor -> None | QsCustomType udt -> udt |> buildUdtClass globalContext |> Some | QsCallable op -> op |> buildOperationClass globalContext |> Some - let members = + let members = localElements |> List.map buildOne |> List.choose id - ``#line hidden`` <| + ``#line hidden`` <| ``namespace`` nsName.Value ``{`` [] @@ -1531,7 +1538,7 @@ module SimulationCode = ``}`` :> MemberDeclarationSyntax - type AttributeGenerator () = + type AttributeGenerator () = inherit NamespaceTransformation(TransformationOptions.NoRebuild) let mutable attributes = [] @@ -1539,36 +1546,36 @@ module SimulationCode = let attr = ``attribute`` (Some ``assembly``) (``ident`` attrName) [ ``literal`` json ] attributes <- attr :: attributes - member internal this.Apply (elements : IEnumerable) = + member internal this.Apply (elements : IEnumerable) = attributes <- [] - for element in elements do + for element in elements do base.OnNamespaceElement element |> ignore attributes |> List.rev - override this.OnSpecializationDeclaration (spec : QsSpecialization) = + override this.OnSpecializationDeclaration (spec : QsSpecialization) = (SpecializationDeclarationHeader.New spec).ToJson() |> GenerateAndAdd "SpecializationDeclaration" spec - override this.OnCallableDeclaration (callable : QsCallable) = + override this.OnCallableDeclaration (callable : QsCallable) = (CallableDeclarationHeader.New callable).ToJson() |> GenerateAndAdd "CallableDeclaration" base.OnCallableDeclaration callable - override this.OnTypeDeclaration (qsType : QsCustomType) = + override this.OnTypeDeclaration (qsType : QsCustomType) = (TypeDeclarationHeader.New qsType).ToJson() |> GenerateAndAdd "TypeDeclaration" qsType - let buildDeclarationAttributes elements = + let buildDeclarationAttributes elements = let generator = new AttributeGenerator() - generator.Apply elements + generator.Apply elements // Returns only those namespaces and their elements that are defined for the given file. let findLocalElements selector fileName syntaxTree = - let path = - match CompilationBuilder.CompilationUnitManager.TryGetUri fileName with + let path = + match CompilationBuilder.CompilationUnitManager.TryGetUri fileName with | true, uri -> uri.AbsolutePath |> NonNullable.New | false, _ -> NonNullable.New "" syntaxTree @@ -1589,12 +1596,12 @@ module SimulationCode = ] // Builds the C# syntaxTree for the Q# elements defined in the given file. - let buildSyntaxTree localElements (context : CodegenContext) = + let buildSyntaxTree localElements (context : CodegenContext) = let usings = autoNamespaces |> List.map (fun ns -> ``using`` ns) let attributes = localElements |> List.map (snd >> buildDeclarationAttributes) |> List.concat let namespaces = localElements |> List.map (buildNamespace context) - ``compilation unit`` + ``compilation unit`` attributes usings namespaces @@ -1604,55 +1611,55 @@ module SimulationCode = |> ``pragmaDisableWarning`` 0436 // shadowing existing classes from references |> ``with leading comments`` autogenComment - // Helper method that takes a SyntaxTree, adds trivia (formatting) + // Helper method that takes a SyntaxTree, adds trivia (formatting) // and returns it as a string let formatSyntaxTree tree = - try + try let ws = new AdhocWorkspace() let formattedRoot = Formatter.Format(tree, ws) formattedRoot.ToFullString() - with + with | :? ReflectionTypeLoadException as l -> let msg = l.LoaderExceptions |> Array.fold (fun msg e -> msg + ";" + e.Message) "" failwith msg - - /// Builds the SyntaxTree for callables and types loaded via test names, + + /// Builds the SyntaxTree for callables and types loaded via test names, /// formats it and returns it as a string. - /// Returns null if no elements have been loaded via test name. - let loadedViaTestNames (dllName : NonNullable) globalContext = - let isLoadedViaTestName nsElement = + /// Returns null if no elements have been loaded via test name. + let loadedViaTestNames (dllName : NonNullable) globalContext = + let isLoadedViaTestName nsElement = let asOption = function | Value _ -> Some nsElement | _ -> None - match nsElement with - | QsCallable c as e -> SymbolResolution.TryGetTestName c.Attributes - | QsCustomType t as e -> SymbolResolution.TryGetTestName t.Attributes + match nsElement with + | QsCallable c as e -> SymbolResolution.TryGetTestName c.Attributes + | QsCustomType t as e -> SymbolResolution.TryGetTestName t.Attributes |> asOption - let context = {globalContext with fileName = Some dllName.Value} + let context = {globalContext with fileName = Some dllName.Value} let localElements = findLocalElements isLoadedViaTestName dllName context.allQsElements - let getNameCollisions (_, elems : QsNamespaceElement list) = - let tryGetCollision = function - | QsCustomType t -> - match SymbolResolution.TryGetOriginalName t.Attributes with - | Value origName -> - match context.allUdts.TryGetValue origName with - | true, collision -> + let getNameCollisions (_, elems : QsNamespaceElement list) = + let tryGetCollision = function + | QsCustomType t -> + match SymbolResolution.TryGetOriginalName t.Attributes with + | Value origName -> + match context.allUdts.TryGetValue origName with + | true, collision -> if context.GenerateCodeForSource collision.SourceFile then None else Some (origName.Namespace, QsCustomType collision) | _ -> None | Null -> None - | QsCallable c -> - match SymbolResolution.TryGetOriginalName c.Attributes with - | Value origName -> - match context.allCallables.TryGetValue origName with - | true, collision -> + | QsCallable c -> + match SymbolResolution.TryGetOriginalName c.Attributes with + | Value origName -> + match context.allCallables.TryGetValue origName with + | true, collision -> if context.GenerateCodeForSource collision.SourceFile then None else Some (origName.Namespace, QsCallable collision) | _ -> None | Null -> None elems |> List.choose tryGetCollision - if localElements.Any() then - let collisions = + if localElements.Any() then + let collisions = (localElements |> Seq.collect getNameCollisions).ToLookup(fst, snd) |> Seq.map (fun g -> g.Key, g |> Seq.toList) |> Seq.toList buildSyntaxTree (localElements @ collisions) context @@ -1661,14 +1668,14 @@ module SimulationCode = /// Main entry method for a CodeGenerator. /// Builds the SyntaxTree for the given Q# syntax tree, formats it and returns it as a string. - /// Omits code generation for intrinsic callables in references. - let generate (fileName : NonNullable) globalContext = + /// Omits code generation for intrinsic callables in references. + let generate (fileName : NonNullable) globalContext = let isIntrinsic = function | QsCallable c -> c.Signature.Information.InferredInformation.IsIntrinsic | QsCustomType _ -> false let filterIntrinsics (ns, elems) = ns, elems |> List.filter (not << isIntrinsic) - let context = {globalContext with fileName = Some fileName.Value} - let localElements = + let context = {globalContext with fileName = Some fileName.Value} + let localElements = let elements = findLocalElements Some fileName context.allQsElements if fileName.Value.EndsWith ".dll" then elements |> List.map filterIntrinsics else elements diff --git a/src/Simulation/EntryPointDriver.Tests/Tests.fs b/src/Simulation/EntryPointDriver.Tests/Tests.fs index 57f283a2d73..7f242fdc5a0 100644 --- a/src/Simulation/EntryPointDriver.Tests/Tests.fs +++ b/src/Simulation/EntryPointDriver.Tests/Tests.fs @@ -179,8 +179,6 @@ let private testWith testNum defaultSimulator = /// Standard command-line arguments for the "submit" command without specifying a target. let private submitWithoutTarget = [ "submit" - "--storage" - "myStorage" "--subscription" "mySubscription" "--resource-group" @@ -550,10 +548,10 @@ let ``Submit uses default values`` () = given (submitWithNothingTarget @ ["--verbose"]) |> yields "The friendly URI for viewing job results is not available yet. Showing the job ID instead. Target: test.nothing - Storage: myStorage Subscription: mySubscription Resource Group: myResourceGroup Workspace: myWorkspace + Storage: AAD Token: Base URI: Job Name: @@ -569,6 +567,8 @@ let ``Submit allows overriding default values`` () = let given = test 1 given (submitWithNothingTarget @ [ "--verbose" + "--storage" + "myStorage" "--aad-token" "myToken" "--base-uri" @@ -580,10 +580,10 @@ let ``Submit allows overriding default values`` () = ]) |> yields "The friendly URI for viewing job results is not available yet. Showing the job ID instead. Target: test.nothing - Storage: myStorage Subscription: mySubscription Resource Group: myResourceGroup Workspace: myWorkspace + Storage: myStorage AAD Token: myToken Base URI: myBaseUri Job Name: myJobName @@ -686,10 +686,10 @@ let ``Shows help text for submit command`` () = Options: --target (REQUIRED) The target device ID. - --storage (REQUIRED) The storage account connection string. --subscription (REQUIRED) The subscription ID. --resource-group (REQUIRED) The resource group name. --workspace (REQUIRED) The workspace name. + --storage The storage account connection string. --aad-token The Azure Active Directory authentication token. --base-uri The base URI of the Azure Quantum endpoint. --job-name The name of the submitted job. diff --git a/src/Simulation/EntryPointDriver/Azure.cs b/src/Simulation/EntryPointDriver/Azure.cs index 86ad79791a3..0f3b3a91e77 100644 --- a/src/Simulation/EntryPointDriver/Azure.cs +++ b/src/Simulation/EntryPointDriver/Azure.cs @@ -195,11 +195,6 @@ internal sealed class AzureSettings /// public string? Target { get; set; } - /// - /// The storage account connection string. - /// - public string? Storage { get; set; } - /// /// The subscription ID. /// @@ -215,6 +210,11 @@ internal sealed class AzureSettings /// public string? Workspace { get; set; } + /// + /// The storage account connection string. + /// + public string? Storage { get; set; } + /// /// The Azure Active Directory authentication token. /// @@ -262,10 +262,10 @@ AadToken is null public override string ToString() => string.Join(System.Environment.NewLine, $"Target: {Target}", - $"Storage: {Storage}", $"Subscription: {Subscription}", $"Resource Group: {ResourceGroup}", $"Workspace: {Workspace}", + $"Storage: {Storage}", $"AAD Token: {AadToken}", $"Base URI: {BaseUri}", $"Job Name: {JobName}", diff --git a/src/Simulation/EntryPointDriver/Driver.cs b/src/Simulation/EntryPointDriver/Driver.cs index daabf992cde..13a836e85f2 100644 --- a/src/Simulation/EntryPointDriver/Driver.cs +++ b/src/Simulation/EntryPointDriver/Driver.cs @@ -81,10 +81,10 @@ public async Task Run(string[] args) Handler = CommandHandler.Create(Submit) }; AddOptionIfAvailable(submit, TargetOption); - AddOptionIfAvailable(submit, StorageOption); AddOptionIfAvailable(submit, SubscriptionOption); AddOptionIfAvailable(submit, ResourceGroupOption); AddOptionIfAvailable(submit, WorkspaceOption); + AddOptionIfAvailable(submit, StorageOption); AddOptionIfAvailable(submit, AadTokenOption); AddOptionIfAvailable(submit, BaseUriOption); AddOptionIfAvailable(submit, JobNameOption); @@ -133,10 +133,10 @@ private async Task Submit(ParseResult parseResult, AzureSettings azureSetti await Azure.Submit(entryPoint, parseResult, new AzureSettings { Target = azureSettings.Target, - Storage = azureSettings.Storage, Subscription = azureSettings.Subscription, ResourceGroup = azureSettings.ResourceGroup, Workspace = azureSettings.Workspace, + Storage = DefaultIfShadowed(StorageOption, azureSettings.Storage), AadToken = DefaultIfShadowed(AadTokenOption, azureSettings.AadToken), BaseUri = DefaultIfShadowed(BaseUriOption, azureSettings.BaseUri), JobName = DefaultIfShadowed(JobNameOption, azureSettings.JobName), @@ -211,12 +211,6 @@ internal static class Driver internal static readonly OptionInfo TargetOption = new OptionInfo( ImmutableList.Create("--target"), "The target device ID."); - /// - /// The storage option. - /// - internal static readonly OptionInfo StorageOption = new OptionInfo( - ImmutableList.Create("--storage"), "The storage account connection string."); - /// /// The subscription option. /// @@ -235,6 +229,12 @@ internal static class Driver internal static readonly OptionInfo WorkspaceOption = new OptionInfo( ImmutableList.Create("--workspace"), "The workspace name."); + /// + /// The storage option. + /// + internal static readonly OptionInfo StorageOption = new OptionInfo( + ImmutableList.Create("--storage"), default, "The storage account connection string."); + /// /// The AAD token option. /// diff --git a/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj b/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj index f83db39edc0..93d81f193bb 100644 --- a/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj +++ b/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj index 6fa6d8bc6a1..03556c866bd 100644 --- a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj +++ b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators.Tests/Circuits/ClassicalRotationsTest.qs b/src/Simulation/Simulators.Tests/Circuits/ClassicalRotationsTest.qs new file mode 100644 index 00000000000..58993da3734 --- /dev/null +++ b/src/Simulation/Simulators.Tests/Circuits/ClassicalRotationsTest.qs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Math; + + + operation IncrementWithRotationsTest (start : Int) : Int { + + + using (qubits = Qubit[3]) { + for (shift in 0..2) { + if (((start >>> shift) &&& 1) == 1) { + R(PauliX, PI(), qubits[shift]); + } + } + + CCNOT(qubits[0], qubits[1], qubits[2]); + CNOT(qubits[0], qubits[1]); + //Rx(PI(), qubits[0]); + RFrac(PauliX, 1, 1, qubits[0]); + + let b0 = M(qubits[0]) == One ? 1 | 0; + let b1 = M(qubits[1]) == One ? 1 | 0; + let b2 = M(qubits[2]) == One ? 1 | 0; + + ResetAll(qubits); + + return b2 * 4 + b1 * 2 + b0; + } + } + +} + + diff --git a/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs b/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs index 78e9e2fc0af..75898a27657 100644 --- a/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs +++ b/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs @@ -540,7 +540,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { return Foo(3); } - operation ToffoliUsingQubitCheck () : Unit + operation UsingQubitCheck () : Unit { using (q = Qubit()) { @@ -549,15 +549,25 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { } } - operation ToffoliBorrowingQubitCheck () : Unit + operation ReleaseMeasuredQubitCheck () : Unit { using (q = Qubit()) { - ToffoliBorrower(); + X(q); + let r = M(q); + // Should not raise an exception + } + } + + operation BorrowingQubitCheck () : Unit + { + using (q = Qubit()) + { + QubitBorrower(); } } - operation ToffoliBorrower() : Unit + operation QubitBorrower() : Unit { borrowing (q = Qubit()) { diff --git a/src/Simulation/Simulators.Tests/Circuits/UserDefinedTypes.qs b/src/Simulation/Simulators.Tests/Circuits/UserDefinedTypes.qs index 70473404b9d..fa8cbc07cff 100644 --- a/src/Simulation/Simulators.Tests/Circuits/UserDefinedTypes.qs +++ b/src/Simulation/Simulators.Tests/Circuits/UserDefinedTypes.qs @@ -7,10 +7,12 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits newtype P1 = (Int, Int); newtype P2 = ((Int, Int), Int); + newtype NamedTuple = (FirstItem: (Int, Double), SecondItem: Int); + newtype InnerNamedTuple = ((Fst : Result, Snd : (Int, Int)), Trd : String); function TakesUdtPartial<'T, 'U> (build : ('T -> 'U), remainingArgs : 'T) : 'U { return build(remainingArgs); - } + } operation PassingUDTConstructorTest() : Unit { @@ -20,7 +22,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits AssertEqual(c1, 3); let partial = P2((_,2), _); - let full = TakesUdtPartial(partial, (3,1)); + let full = TakesUdtPartial(partial, (3,1)); let ((a2, b2), c2) = full!; AssertEqual(a2, 3); AssertEqual(b2, 2); @@ -31,7 +33,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { let partial = P2((_,2), _); let full = partial(3, 1); - + let ((a, b), c) = full!; AssertEqual(a, 3); AssertEqual(b, 2); @@ -42,10 +44,10 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { let partial = P1(2, _); let full = partial(3); - + let (a, b) = full!; AssertEqual(5, a+b); - + let full2 = partial(10); let (x, y) = full2!; AssertEqual(12, x + y); @@ -75,7 +77,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits return P2((3,_),_); } - function CallReturnedUdtConstructorTest () : Unit + function CallReturnedUdtConstructorTest () : Unit { let udt1 = (returnUdtConstructor())((1,2),3); let ((a1,b1),c1) = udt1!; @@ -107,5 +109,24 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits AssertEqual(c, 3); } } + + function UdtNamedTupleFieldTest () : Unit { + let data = NamedTuple((1, 2.0), 3); + let (a, b) = data::FirstItem; + let c = data::SecondItem; + AssertEqual(a, 1); + AssertEqual(b, 2.0); + AssertEqual(c, 3); + } + + function UdtInnerNamedTupleFieldTest () : Unit { + let t = InnerNamedTuple((Zero, (0,1)), ""); + AssertEqual(Zero, t::Fst); + let snd = t::Snd; + let (s1, s2) = snd; + AssertEqual(0, s1); + AssertEqual(1, s2); + AssertEqual("", t::Trd); + } } diff --git a/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs b/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs new file mode 100644 index 00000000000..a267a719274 --- /dev/null +++ b/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Simulation.Simulators.Exceptions; +using Microsoft.Quantum.Simulation.Simulators.Tests.Circuits; +using Xunit; + +namespace Microsoft.Quantum.Simulation.Simulators.Tests +{ + public partial class QuantumSimulatorTests + { + //test to check that qubit cannot be released if it is not in zero state + [Fact] + public async Task ZeroStateQubitReleaseTest() + { + var sim = new QuantumSimulator(); + + await Assert.ThrowsAsync(() => UsingQubitCheck.Run(sim)); + } + + //test to check that qubit can be released if measured + [Fact] + public async Task MeasuredQubitReleaseTest() + { + var sim = new QuantumSimulator(); + + //should not throw an exception, as Measured qubits are allowed to be released, and the release aspect is handled in the C++ code + await ReleaseMeasuredQubitCheck.Run(sim); + } + + //test to check that qubit that is released and reallocated is in state |0> + [Fact] + public async Task ReallocateQubitInGroundStateTest() + { + var sim = new QuantumSimulator(); + var allocate = sim.Get(); + var release = sim.Get(); + var q1 = allocate.Apply(1); + var q1Id = q1[0].Id; + var gate = sim.Get(); + var measure = sim.Get(); + gate.Apply(q1[0]); + var result1 = measure.Apply(q1[0]); + //Check X operation + Assert.Equal(result1, Result.One); + release.Apply(q1[0]); + var q2 = allocate.Apply(1); + var q2Id = q2[0].Id; + //Assert reallocated qubit has the same id as the one released + Assert.Equal(q1Id, q2Id); + var result2 = measure.Apply(q2[0]); + //Assert reallocated qubit has is initialized in state |0> + Assert.Equal(result2, Result.Zero); + + + + } + } +} diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj index c7cf8bab959..8e69c0a388d 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj index c7cf8bab959..8e69c0a388d 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj index c851ccd391c..9326805e5a9 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj b/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj index 6ff0e165ec6..73c103678c0 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj index 1255e9180a0..cc6001ef292 100644 --- a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj +++ b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs b/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs index a3638cb332a..74e031df283 100644 --- a/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs +++ b/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Xunit; @@ -143,6 +143,15 @@ public async Task ToffoliSwap() await Circuits.SwapTest.Run(sim); } + [Fact] + public async Task ToffoliRotations() + { + var sim = new ToffoliSimulator(); + + var result = await Circuits.IncrementWithRotationsTest.Run(sim, 4); + Assert.Equal(5, result); + } + [Fact] public async Task Bug2469() { @@ -156,7 +165,7 @@ public async Task ToffoliUsingCheck() { var sim = new ToffoliSimulator(); - await Assert.ThrowsAsync(() => ToffoliUsingQubitCheck.Run(sim)); + await Assert.ThrowsAsync(() => UsingQubitCheck.Run(sim)); } [Fact] @@ -164,7 +173,7 @@ public async Task ToffoliBorrowingCheck() { var sim = new ToffoliSimulator(); - await Assert.ThrowsAsync(() => ToffoliBorrowingQubitCheck.Run(sim)); + await Assert.ThrowsAsync(() => BorrowingQubitCheck.Run(sim)); } [Fact] @@ -290,7 +299,7 @@ void Prepare(IEnumerable qubits) sim.DumpFormat = ToffoliDumpFormat.Bits; testPath = Path.GetTempFileName(); dumpMachine.Apply(testPath); - var expectedBitsLarge = expectedHeader + + var expectedBitsLarge = expectedHeader + "00000000\t1001001001001001" + NL + "00000002\t0010010010010010" + NL + "00000004\t0100100100100100" + NL + @@ -301,7 +310,7 @@ void Prepare(IEnumerable qubits) testPath = Path.GetTempFileName(); dumpMachine.Apply(testPath); var expectedHexLarge = - expectedHeader + "00000000\t49 92 24 49 92 24 49 92" + NL; + expectedHeader + "00000000\t49 92 24 49 92 24 49 92" + NL; Assert.Equal(expectedHexLarge, File.ReadAllText(testPath)); // Reset and return our qubits for the next example. diff --git a/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj b/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj index d47e83a63ad..167a6619277 100644 --- a/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj +++ b/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators/QuantumSimulator/Assert.cs b/src/Simulation/Simulators/QuantumSimulator/Assert.cs index 50f198d01c7..d0936509470 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Assert.cs +++ b/src/Simulation/Simulators/QuantumSimulator/Assert.cs @@ -28,7 +28,7 @@ public QSimAssert(QuantumSimulator m) : base(m) { var (paulis, qubits, result, msg) = _args; - this.Simulator.CheckQubits(qubits); + this.Simulator.CheckAndPreserveQubits(qubits); if (paulis.Length != qubits.Length) { diff --git a/src/Simulation/Simulators/QuantumSimulator/AssertProb.cs b/src/Simulation/Simulators/QuantumSimulator/AssertProb.cs index cec9be07f3a..8f93eea3b31 100644 --- a/src/Simulation/Simulators/QuantumSimulator/AssertProb.cs +++ b/src/Simulation/Simulators/QuantumSimulator/AssertProb.cs @@ -29,7 +29,7 @@ public QSimAssertProb(QuantumSimulator m) : base(m) { var (paulis, qubits, result, expectedPr, msg, tol) = _args; - Simulator.CheckQubits(qubits); + Simulator.CheckAndPreserveQubits(qubits); if (paulis.Length != qubits.Length) { diff --git a/src/Simulation/Simulators/QuantumSimulator/Dump.cs b/src/Simulation/Simulators/QuantumSimulator/Dump.cs index ce83a813525..5845114baf4 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Dump.cs +++ b/src/Simulation/Simulators/QuantumSimulator/Dump.cs @@ -96,7 +96,7 @@ public QSimDumpRegister(QuantumSimulator m) : base(m) var (location, qubits) = __in; if (location == null) { throw new ArgumentNullException(nameof(location)); } - Simulator.CheckQubits(qubits); + Simulator.CheckAndPreserveQubits(qubits); return Simulator.Dump(location, qubits); }; diff --git a/src/Simulation/Simulators/QuantumSimulator/M.cs b/src/Simulation/Simulators/QuantumSimulator/M.cs index 3ea3717fd63..6f2766ea333 100644 --- a/src/Simulation/Simulators/QuantumSimulator/M.cs +++ b/src/Simulation/Simulators/QuantumSimulator/M.cs @@ -27,7 +27,8 @@ public QSimM(QuantumSimulator m) : base(m) public override Func Body => (q) => { Simulator.CheckQubit(q); - + //setting qubit as measured to allow for release + q.IsMeasured = true; return M(Simulator.Id, (uint)q.Id).ToResult(); }; } diff --git a/src/Simulation/Simulators/QuantumSimulator/Measure.cs b/src/Simulation/Simulators/QuantumSimulator/Measure.cs index 853b61ac8a5..40661c9b4d9 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Measure.cs +++ b/src/Simulation/Simulators/QuantumSimulator/Measure.cs @@ -27,12 +27,15 @@ public QSimMeasure(QuantumSimulator m) : base(m) var (paulis, qubits) = _args; Simulator.CheckQubits(qubits); - if (paulis.Length != qubits.Length) { throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size"); } - + foreach (Qubit q in qubits) + { + //setting qubit as measured to allow for release + q.IsMeasured = true; + } return Measure(Simulator.Id, (uint)paulis.Length, paulis.ToArray(), qubits.GetIds()).ToResult(); }; } diff --git a/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs b/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs index 478f511b756..e073a4ac39b 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs @@ -89,28 +89,35 @@ static void CheckAngle(double angle) /// /// Makes sure the target qubit of an operation is valid. In particular it checks that the qubit instance is not null. + /// Also sets the isMeasured flag to false for each qubit /// void CheckQubit(Qubit q1) { if (q1 == null) throw new ArgumentNullException(nameof(q1), "Trying to perform a primitive operation on a null Qubit"); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q1.IsMeasured = false; } /// /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that /// - none of the qubits are null /// - there are no duplicated qubits + /// Also sets the isMeasured flag to false for each qubit /// bool[] CheckQubits(IQArray ctrls, Qubit q1) { bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; CheckQubitInUse(q1, used); + q1.IsMeasured = false; if (ctrls != null && ctrls.Length > 0) { foreach (var q in ctrls) { CheckQubitInUse(q, used); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q.IsMeasured = false; } } @@ -122,6 +129,7 @@ bool[] CheckQubits(IQArray ctrls, Qubit q1) /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that /// - none of the qubits are null /// - there are no duplicated qubits + /// Also sets the isMeasured flag to false for each qubit /// bool[] CheckQubits(IQArray targets) { @@ -133,16 +141,40 @@ bool[] CheckQubits(IQArray targets) foreach (var q in targets) { CheckQubitInUse(q, used); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q.IsMeasured = false; } return used; } /// + /// Intended to be used with simulator functions like Dump, Assert, AssertProb /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that /// - none of the qubits are null /// - there are no duplicated qubits /// + bool[] CheckAndPreserveQubits(IQArray targets) + { + if (targets == null) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on a null Qubit array."); + if (targets.Length == 0) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on an empty Qubit array."); + + bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; + + foreach (var q in targets) + { + CheckQubitInUse(q, used); + } + + return used; + } + + /// + /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that + /// - none of the qubits are null + /// - there are no duplicated qubits + /// Also sets the isMeasured flag to false for each qubit + /// bool[] CheckQubits(IQArray ctrls, IQArray targets) { bool[] used = CheckQubits(targets); @@ -152,6 +184,8 @@ bool[] CheckQubits(IQArray ctrls, IQArray targets) foreach (var q in ctrls) { CheckQubitInUse(q, used); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q.IsMeasured = false; } } diff --git a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs index 58ff574fc34..7b45f3f9ba4 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs @@ -63,13 +63,14 @@ protected override void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing) base.ReleaseOneQubit(qubit, usedOnlyForBorrowing); if (qubit != null) { - bool areAllReleasedQubitsZero = ReleaseOne(this.SimulatorId, (uint)qubit.Id); - if (!areAllReleasedQubitsZero && throwOnReleasingQubitsNotInZeroState) + bool isReleasedQubitZero = ReleaseOne(this.SimulatorId, (uint)qubit.Id); + if (!(isReleasedQubitZero || qubit.IsMeasured) && throwOnReleasingQubitsNotInZeroState) { throw new ReleasedQubitsAreNotInZeroState(); } } } } + } } diff --git a/src/Simulation/Simulators/ToffoliSimulator/R.cs b/src/Simulation/Simulators/ToffoliSimulator/R.cs index 61969c72bf2..09debce8732 100644 --- a/src/Simulation/Simulators/ToffoliSimulator/R.cs +++ b/src/Simulation/Simulators/ToffoliSimulator/R.cs @@ -37,7 +37,7 @@ public R(ToffoliSimulator m) : base(m) simulator.CheckQubit(q1, "q1"); - var (isX, safe) = CheckRotation(basis, 2.0 * angle); + var (isX, safe) = CheckRotation(basis, angle / 2.0); if (isX) { simulator.DoX(q1); @@ -66,7 +66,7 @@ public R(ToffoliSimulator m) : base(m) simulator.CheckControlQubits(ctrls, q1); - var (isX, safe) = CheckRotation(basis, 2.0 * angle); + var (isX, safe) = CheckRotation(basis, angle / 2.0); if (!safe) { throw new InvalidOperationException($"The Toffoli simulator can only perform controlled rotations of multiples of 2*pi.");