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)); }
public async Task <ExecutionResult> ExecuteJobAsync(IChannel channel, AzureSubmissionContext submissionContext, CancellationToken?cancellationToken = null) => await SubmitOrExecuteJobAsync(channel, submissionContext, execute : true, cancellationToken ?? CancellationToken.None);
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)); }