Exemple #1
0
        public Task <IQuantumMachineJob> SubmitAsync(IQuantumMachine machine, AzureSubmissionContext submissionContext)
        {
            var parameterTypes  = new List <Type>();
            var parameterValues = new List <object>();

            foreach (var parameter in OperationInfo.RoslynParameters)
            {
                if (!submissionContext.InputParameters.ContainsKey(parameter.Name))
                {
                    throw new ArgumentException($"Required parameter {parameter.Name} was not specified.");
                }

                string rawParameterValue = submissionContext.InputParameters[parameter.Name];
                try
                {
                    var parameterValue = submissionContext.InputParameters.DecodeParameter(parameter.Name, type: parameter.ParameterType);

                    if (parameterValue != null)
                    {
                        parameterTypes.Add(parameter.ParameterType);
                        parameterValues.Add(parameterValue);
                    }
                }
                catch (Exception e)
                {
                    throw new ArgumentException($"The value {rawParameterValue} provided for parameter {parameter.Name} could not be converted to the expected type: {e.Message}");
                }
            }

            var entryPointInput = parameterValues.Count switch
            {
                0 => QVoid.Instance,
                1 => parameterValues.Single(),
                _ => InputType.GetConstructor(parameterTypes.ToArray()).Invoke(parameterValues.ToArray())
            };

            // Find and invoke the method on IQuantumMachine that is declared as:
            // Task<IQuantumMachineJob> SubmitAsync<TInput, TOutput>(EntryPointInfo<TInput, TOutput> info, TInput input, SubmissionContext context)
            var submitMethod = typeof(IQuantumMachine)
                               .GetMethods()
                               .Single(method =>
                                       method.Name == "SubmitAsync" &&
                                       method.IsGenericMethodDefinition &&
                                       method.GetParameters().Length == 3 &&
                                       method.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == EntryPointInfo.GetType().GetGenericTypeDefinition() &&
                                       method.GetParameters()[1].ParameterType.IsGenericMethodParameter &&
                                       method.GetParameters()[2].ParameterType == typeof(IQuantumMachineSubmissionContext))
                               .MakeGenericMethod(new Type[] { InputType, OutputType });
            var submitParameters = new object[] { EntryPointInfo, entryPointInput, submissionContext };

            return((Task <IQuantumMachineJob>)submitMethod.Invoke(machine, submitParameters));
        }
    }
 public override async Task <ExecutionResult> RunAsync(string input, IChannel channel, CancellationToken cancellationToken)
 {
     return(await AzureClient.ExecuteJobAsync(channel, AzureSubmissionContext.Parse(input), cancellationToken));
 }
Exemple #3
0
 public async Task <ExecutionResult> ExecuteJobAsync(IChannel channel, AzureSubmissionContext submissionContext, CancellationToken?cancellationToken = null) =>
 await SubmitOrExecuteJobAsync(channel, submissionContext, execute : true, cancellationToken ?? CancellationToken.None);
Exemple #4
0
        private async Task <ExecutionResult> SubmitOrExecuteJobAsync(
            IChannel channel,
            AzureSubmissionContext submissionContext,
            bool execute,
            CancellationToken cancellationToken)
        {
            if (ActiveWorkspace == null)
            {
                channel.Stderr($"Please call {GetCommandDisplayName("connect")} before submitting a job.");
                return(AzureClientError.NotConnected.ToExecutionResult());
            }

            if (ActiveTarget == null)
            {
                channel.Stderr($"Please call {GetCommandDisplayName("target")} before submitting a job.");
                return(AzureClientError.NoTarget.ToExecutionResult());
            }

            if (string.IsNullOrEmpty(submissionContext.OperationName))
            {
                channel.Stderr($"Please pass a valid Q# operation name to {GetCommandDisplayName(execute ? "execute" : "submit")}.");
                return(AzureClientError.NoOperationName.ToExecutionResult());
            }

            var connectionResult = await RefreshConnectionAsync(channel);

            if (connectionResult.Status != ExecuteStatus.Ok)
            {
                return(connectionResult);
            }

            var machine = ActiveWorkspace.CreateQuantumMachine(ActiveTarget.TargetId, ConnectionString);

            if (machine == null)
            {
                // We should never get here, since ActiveTarget should have already been validated at the time it was set.
                channel.Stderr($"Unexpected error while preparing job for execution on target {ActiveTarget.TargetId}.");
                return(AzureClientError.InvalidTarget.ToExecutionResult());
            }

            channel.Stdout($"Submitting {submissionContext.OperationName} to target {ActiveTarget.TargetId}...");

            IEntryPoint?entryPoint = null;

            try
            {
                entryPoint = EntryPointGenerator.Generate(submissionContext.OperationName, ActiveTarget.TargetId, ActiveTarget.RuntimeCapability);
            }
            catch (UnsupportedOperationException)
            {
                channel.Stderr($"{submissionContext.OperationName} is not a recognized Q# operation name.");
                return(AzureClientError.UnrecognizedOperationName.ToExecutionResult());
            }
            catch (CompilationErrorsException e)
            {
                channel.Stderr($"The Q# operation {submissionContext.OperationName} could not be compiled as an entry point for job execution.");
                foreach (var message in e.Errors)
                {
                    channel.Stderr(message);
                }
                return(AzureClientError.InvalidEntryPoint.ToExecutionResult());
            }

            try
            {
                var job = await entryPoint.SubmitAsync(machine, submissionContext);

                channel.Stdout($"Job successfully submitted for {submissionContext.Shots} shots.");
                channel.Stdout($"   Job name: {submissionContext.FriendlyName}");
                channel.Stdout($"   Job ID: {job.Id}");
                MostRecentJobId = job.Id;
            }
            catch (ArgumentException e)
            {
                channel.Stderr($"Failed to parse all expected parameters for Q# operation {submissionContext.OperationName}.");
                channel.Stderr(e.Message);
                return(AzureClientError.JobSubmissionFailed.ToExecutionResult());
            }
            catch (Exception e)
            {
                channel.Stderr($"Failed to submit Q# operation {submissionContext.OperationName} for execution.");
                channel.Stderr(e.InnerException?.Message ?? e.Message);
                return(AzureClientError.JobSubmissionFailed.ToExecutionResult());
            }

            // If the command was not %azure.execute, simply return the job status.
            if (!execute)
            {
                return(await GetJobStatusAsync(channel, MostRecentJobId));
            }

            // If the command was %azure.execute, wait for the job to complete and return the job output.
            channel.Stdout($"Waiting up to {submissionContext.ExecutionTimeout} seconds for Azure Quantum job to complete...");

            using var executionTimeoutTokenSource      = new CancellationTokenSource(TimeSpan.FromSeconds(submissionContext.ExecutionTimeout));
            using var executionCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(executionTimeoutTokenSource.Token, cancellationToken);
            {
                try
                {
                    CloudJob?cloudJob = null;
                    while (cloudJob == null || cloudJob.InProgress)
                    {
                        executionCancellationTokenSource.Token.ThrowIfCancellationRequested();
                        await Task.Delay(TimeSpan.FromSeconds(submissionContext.ExecutionPollingInterval), executionCancellationTokenSource.Token);

                        cloudJob = await ActiveWorkspace.GetJobAsync(MostRecentJobId);

                        channel.Stdout($"[{DateTime.Now.ToLongTimeString()}] Current job status: {cloudJob?.Status ?? "Unknown"}");
                    }
                }
                catch (Exception e) when(e is TaskCanceledException || e is OperationCanceledException)
                {
                    Logger?.LogInformation($"Operation canceled while waiting for job execution to complete: {e.Message}");
                }
            }

            return(await GetJobResultAsync(channel, MostRecentJobId));
        }