From 419042290339b14613c5cd353c89431f8c3c7ae7 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 18 Mar 2021 12:52:56 -0700 Subject: [PATCH] Fix dynamic assembly load logic in Tracer This fixes an issue where the fallback logic in the `QCTraceSimulator` for dynamically loading the QSharp.Core target package wouldn't work for manually written C# drivers. This fixes the issue by introducing new fallback logic that relies on the assembly name of the current simulator assembly to determine the full name of the QSharp.Core assembly to load. Fixes #540 Fixes #542 --- src/Simulation/EntryPointDriver/Simulation.cs | 6 +- .../QCTraceSimulator/QCTraceSimulatorImpl.cs | 58 ++++++++++--------- .../ResourcesEstimator/ResourcesEstimator.cs | 2 +- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/Simulation/EntryPointDriver/Simulation.cs b/src/Simulation/EntryPointDriver/Simulation.cs index 4e942364fe4..dfa3a9a72f5 100644 --- a/src/Simulation/EntryPointDriver/Simulation.cs +++ b/src/Simulation/EntryPointDriver/Simulation.cs @@ -38,8 +38,10 @@ internal static async Task Simulate( var coreAssemblyName = (from aName in entryPoint.GetType().Assembly.GetReferencedAssemblies() where aName.Name == "Microsoft.Quantum.QSharp.Core" - select aName).First(); - var coreAssembly = Assembly.Load(coreAssemblyName.FullName); + select aName).FirstOrDefault(); + var coreAssembly = coreAssemblyName != null ? + Assembly.Load(coreAssemblyName.FullName) : + null; var resourcesEstimator = new ResourcesEstimator(coreAssembly); await resourcesEstimator.Run(entryPoint.CreateArgument(parseResult)); diff --git a/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulatorImpl.cs b/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulatorImpl.cs index 5d37224316e..630dced7b4e 100644 --- a/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulatorImpl.cs +++ b/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulatorImpl.cs @@ -152,41 +152,43 @@ private void RegisterPrimitiveOperationsGivenAsCircuits(Assembly? coreAssembly) var intrinsicAssembly = coreAssembly; if (intrinsicAssembly == null) { - intrinsicAssembly = - (from assembly in AppDomain.CurrentDomain.GetAssemblies() - where assembly.GetType("Microsoft.Quantum.Intrinsic.X") != null - select assembly).First(); + var currentName = this.GetType().Assembly.GetName(); + var coreName = currentName.FullName.Replace("Simulators", "QSharp.Core"); + try + { + intrinsicAssembly = AppDomain.CurrentDomain.Load(coreName); + } + catch { } } - IEnumerable primitiveOperationTypes = - from op in intrinsicAssembly.GetExportedTypes() - where op.IsSubclassOf(typeof(AbstractCallable)) - select op; - if (primitiveOperationTypes.Count() == 0) + if (intrinsicAssembly != null) { - throw new Exception("Unable to load intrinsic types. The ResourcesEstimator can only be used with the default execution target."); - } - - IEnumerable primitiveOperationAsCircuits = - from op in typeof(Circuits.X).Assembly.GetExportedTypes() - where op.IsSubclassOf(typeof(AbstractCallable)) - && op.Namespace == typeof(Circuits.X).Namespace - select op; + IEnumerable primitiveOperationTypes = + from op in intrinsicAssembly.GetExportedTypes() + where op.IsSubclassOf(typeof(AbstractCallable)) + select op; - foreach (Type operationType in primitiveOperationTypes) - { - IEnumerable machingCircuitTypes = - from op in primitiveOperationAsCircuits - where op.Name == operationType.Name + IEnumerable primitiveOperationAsCircuits = + from op in typeof(Circuits.X).Assembly.GetExportedTypes() + where op.IsSubclassOf(typeof(AbstractCallable)) + && op.Namespace == typeof(Circuits.X).Namespace select op; - int numberOfMatchesFound = machingCircuitTypes.Count(); - Debug.Assert( - numberOfMatchesFound <= 1, - "There should be at most one matching operation."); - if (numberOfMatchesFound == 1) + foreach (Type operationType in primitiveOperationTypes) { - Register(operationType, machingCircuitTypes.First(), operationType.ICallableType()); + IEnumerable machingCircuitTypes = + from op in primitiveOperationAsCircuits + where op.Name == operationType.Name + select op; + + int numberOfMatchesFound = machingCircuitTypes.Count(); + Debug.Assert( + numberOfMatchesFound <= 1, + "There should be at most one matching operation."); + if (numberOfMatchesFound == 1) + { + Register(operationType, machingCircuitTypes.First(), operationType.ICallableType()); + } } } } diff --git a/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs b/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs index a821fd37663..253c14cb2f0 100644 --- a/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs +++ b/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs @@ -48,7 +48,7 @@ public static QCTraceSimulatorConfiguration RecommendedConfig() => /// Constructor used by entry point driver to provide the assembly for core types that /// need to be overriden. /// - public ResourcesEstimator(Assembly coreAssembly) : base(RecommendedConfig(), coreAssembly) + public ResourcesEstimator(Assembly? coreAssembly) : base(RecommendedConfig(), coreAssembly) { }