diff --git a/src/AzureClient/AzureClient.cs b/src/AzureClient/AzureClient.cs index a83130bc7f..0de59c4c8f 100644 --- a/src/AzureClient/AzureClient.cs +++ b/src/AzureClient/AzureClient.cs @@ -23,6 +23,18 @@ namespace Microsoft.Quantum.IQSharp.AzureClient { + /// + /// Supported output data formats for QIR. + /// + internal static class OutputFormat + { + public const string QirResultsV1 = "microsoft.qir-results.v1"; + + public const string QuantumResultsV1 = "microsoft.quantum-results.v1"; + + public const string ResourceEstimatesV1 = "microsoft.resource-estimates.v1"; + } + /// public class AzureClient : IAzureClient { @@ -637,7 +649,7 @@ public async Task GetJobResultAsync(IChannel? channel, string? } } - private async Task CreateOutput(CloudJob job, IChannel? channel, CancellationToken cancellationToken) + internal async Task CreateOutput(CloudJob job, IChannel? channel, CancellationToken cancellationToken) { async Task ReadHttp() { @@ -651,16 +663,22 @@ async Task ReadHttp() using var stream = job.OutputDataUri.IsFile ? File.OpenRead(job.OutputDataUri.LocalPath) : await ReadHttp(); - if (this.ActiveTarget?.TargetId?.StartsWith(MicrosoftSimulator) ?? false) + + if (job.OutputDataFormat == OutputFormat.QirResultsV1) { var (messages, result) = ParseSimulatorOutput(stream); channel?.Stdout(messages); return result.ToExecutionResult(); } - else + else if (job.OutputDataFormat == OutputFormat.QuantumResultsV1) { return stream.ToHistogram(channel, Logger).ToExecutionResult(); } + else + { + channel?.Stderr($"Job ID {job.Id} has unsupported output format: {job.OutputDataFormat}"); + return AzureClientError.JobOutputDownloadFailed.ToExecutionResult(); + } } private static (string Messages, string Result) ParseSimulatorOutput(Stream stream) @@ -671,7 +689,7 @@ private static (string Messages, string Result) ParseSimulatorOutput(Stream stre var line = String.Empty; while ((line = reader.ReadLine()) != null) { - outputLines.Add(line.Trim()); + outputLines.Add(line.Trim()); } } diff --git a/src/AzureClient/Mocks/MockCloudJob.cs b/src/AzureClient/Mocks/MockCloudJob.cs index 63a20f3cbe..6c21c9bd20 100644 --- a/src/AzureClient/Mocks/MockCloudJob.cs +++ b/src/AzureClient/Mocks/MockCloudJob.cs @@ -55,12 +55,13 @@ public float? EstimatedTotal /// internal class MockJobDetails : JobDetails { - public MockJobDetails(string containerUri, string inputDataFormat, string providerId, string target) + public MockJobDetails(string containerUri, string inputDataFormat, string providerId, string target, string outputDataFormat) : base(containerUri: containerUri, inputDataFormat: inputDataFormat, providerId: providerId, target: target) { + OutputDataFormat = outputDataFormat; } private MockCostEstimate? costEstimate; @@ -110,14 +111,15 @@ internal class MockCloudJob : CloudJob private string _id; private string? _outputFile; - public MockCloudJob(string? id = null) + public MockCloudJob(string? id = null, string outputFormat = OutputFormat.QuantumResultsV1) : base( new MockAzureWorkspace("mockSubscriptionId", "mockResourceGroupName", "mockWorkspaceName", "mockLocation"), new MockJobDetails( containerUri: string.Empty, inputDataFormat: string.Empty, providerId: string.Empty, - target: string.Empty + target: string.Empty, + outputDataFormat: outputFormat )) { _id = id ?? Guid.NewGuid().ToString(); @@ -135,7 +137,16 @@ public override Uri OutputDataUri { var path = Path.GetTempFileName(); using var outputFile = new StreamWriter(path); - outputFile.WriteLine(@"{'Histogram':['0',0.5,'1',0.5]}"); + if (OutputDataFormat == OutputFormat.QirResultsV1) + { + outputFile.WriteLine("\"This is a message.\""); + outputFile.WriteLine("\"The is a two-line"); + outputFile.WriteLine("string result.\""); + } + else + { + outputFile.WriteLine(@"{'Histogram':['0',0.5,'1',0.5]}"); + } _outputFile = path; } diff --git a/src/Tests/AzureClientTests.cs b/src/Tests/AzureClientTests.cs index 1ecc570599..ba411090ac 100644 --- a/src/Tests/AzureClientTests.cs +++ b/src/Tests/AzureClientTests.cs @@ -331,6 +331,35 @@ public void TestJobExecution() Assert.IsNotNull(histogram); } + [TestMethod] + public void TestJobOutputFormats() + { + var services = Startup.CreateServiceProvider("Workspace"); + var azureClient = (AzureClient)services.GetRequiredService(); + + // connect + var targets = ExpectSuccess>(ConnectToWorkspaceAsync(azureClient)); + Assert.IsFalse(targets.Any()); + + // add a target + var azureWorkspace = azureClient.ActiveWorkspace as MockAzureWorkspace; + Assert.IsNotNull(azureWorkspace); + azureWorkspace?.AddProviders("microsoft"); + + // set the active target + var target = ExpectSuccess(azureClient.SetActiveTargetAsync(new MockChannel(), "microsoft.simulator")); + Assert.AreEqual("microsoft.simulator", target.TargetId); + + var qirResultsJob = new MockCloudJob(null, OutputFormat.QirResultsV1); + var quantumResultsJob = new MockCloudJob(null, OutputFormat.QuantumResultsV1); + + var histogram = ExpectSuccess(azureClient.CreateOutput(quantumResultsJob, new MockChannel(), CancellationToken.None)); + Assert.IsNotNull(histogram); + + var stringOutput = ExpectSuccess(azureClient.CreateOutput(qirResultsJob, new MockChannel(), CancellationToken.None)); + Assert.IsNotNull(stringOutput); + } + [TestMethod] public void TestJobExecutionWithArrayInput() {