@@ -42,7 +42,7 @@ use qsc_circuit::{
42
42
operations:: entry_expr_for_qubit_operation, Builder as CircuitBuilder , Circuit ,
43
43
Config as CircuitConfig ,
44
44
} ;
45
- use qsc_codegen:: qir:: fir_to_qir;
45
+ use qsc_codegen:: qir:: { fir_to_qir, fir_to_qir_from_callable } ;
46
46
use qsc_data_structures:: {
47
47
functors:: FunctorApp ,
48
48
language_features:: LanguageFeatures ,
@@ -103,6 +103,9 @@ pub enum Error {
103
103
#[ diagnostic( code( "Qsc.Interpret.NotAnOperation" ) ) ]
104
104
#[ diagnostic( help( "provide the name of a callable or a lambda expression" ) ) ]
105
105
NotAnOperation ,
106
+ #[ error( "value is not a global callable" ) ]
107
+ #[ diagnostic( code( "Qsc.Interpret.NotACallable" ) ) ]
108
+ NotACallable ,
106
109
#[ error( "partial evaluation error" ) ]
107
110
#[ diagnostic( transparent) ]
108
111
PartialEvaluation ( #[ from] WithSource < qsc_partial_eval:: Error > ) ,
@@ -563,6 +566,39 @@ impl Interpreter {
563
566
} )
564
567
}
565
568
569
+ // Invokes the given callable with the given arguments using the current environment and compilation but with a fresh
570
+ // simulator configured with the given noise, if any.
571
+ pub fn invoke_with_noise (
572
+ & mut self ,
573
+ receiver : & mut impl Receiver ,
574
+ callable : Value ,
575
+ args : Value ,
576
+ noise : Option < PauliNoise > ,
577
+ ) -> InterpretResult {
578
+ let mut sim = match noise {
579
+ Some ( noise) => SparseSim :: new_with_noise ( & noise) ,
580
+ None => SparseSim :: new ( ) ,
581
+ } ;
582
+ qsc_eval:: invoke (
583
+ self . package ,
584
+ self . classical_seed ,
585
+ & self . fir_store ,
586
+ & mut self . env ,
587
+ & mut sim,
588
+ receiver,
589
+ callable,
590
+ args,
591
+ )
592
+ . map_err ( |( error, call_stack) | {
593
+ eval_error (
594
+ self . compiler . package_store ( ) ,
595
+ & self . fir_store ,
596
+ call_stack,
597
+ error,
598
+ )
599
+ } )
600
+ }
601
+
566
602
/// Runs the given entry expression on a new instance of the environment and simulator,
567
603
/// but using the current compilation.
568
604
pub fn run (
@@ -639,6 +675,45 @@ impl Interpreter {
639
675
} )
640
676
}
641
677
678
+ /// Performs QIR codegen using the given callable with the given arguments on a new instance of the environment
679
+ /// and simulator but using the current compilation.
680
+ pub fn qirgen_from_callable (
681
+ & mut self ,
682
+ callable : & Value ,
683
+ args : Value ,
684
+ ) -> std:: result:: Result < String , Vec < Error > > {
685
+ if self . capabilities == TargetCapabilityFlags :: all ( ) {
686
+ return Err ( vec ! [ Error :: UnsupportedRuntimeCapabilities ] ) ;
687
+ }
688
+
689
+ let Value :: Global ( store_item_id, _) = callable else {
690
+ return Err ( vec ! [ Error :: NotACallable ] ) ;
691
+ } ;
692
+
693
+ fir_to_qir_from_callable (
694
+ & self . fir_store ,
695
+ self . capabilities ,
696
+ None ,
697
+ * store_item_id,
698
+ args,
699
+ )
700
+ . map_err ( |e| {
701
+ let hir_package_id = match e. span ( ) {
702
+ Some ( span) => span. package ,
703
+ None => map_fir_package_to_hir ( self . package ) ,
704
+ } ;
705
+ let source_package = self
706
+ . compiler
707
+ . package_store ( )
708
+ . get ( hir_package_id)
709
+ . expect ( "package should exist in the package store" ) ;
710
+ vec ! [ Error :: PartialEvaluation ( WithSource :: from_map(
711
+ & source_package. sources,
712
+ e,
713
+ ) ) ]
714
+ } )
715
+ }
716
+
642
717
/// Generates a circuit representation for the program.
643
718
///
644
719
/// `entry` can be the current entrypoint, an entry expression, or any operation
@@ -656,21 +731,30 @@ impl Interpreter {
656
731
entry : CircuitEntryPoint ,
657
732
simulate : bool ,
658
733
) -> std:: result:: Result < Circuit , Vec < Error > > {
659
- let entry_expr = match entry {
734
+ let ( entry_expr, invoke_params ) = match entry {
660
735
CircuitEntryPoint :: Operation ( operation_expr) => {
661
736
let ( item, functor_app) = self . eval_to_operation ( & operation_expr) ?;
662
737
let expr = entry_expr_for_qubit_operation ( item, functor_app, & operation_expr)
663
738
. map_err ( |e| vec ! [ e. into( ) ] ) ?;
664
- Some ( expr)
739
+ ( Some ( expr) , None )
665
740
}
666
- CircuitEntryPoint :: EntryExpr ( expr) => Some ( expr) ,
667
- CircuitEntryPoint :: EntryPoint => None ,
741
+ CircuitEntryPoint :: EntryExpr ( expr) => ( Some ( expr) , None ) ,
742
+ CircuitEntryPoint :: Callable ( call_val, args_val) => ( None , Some ( ( call_val, args_val) ) ) ,
743
+ CircuitEntryPoint :: EntryPoint => ( None , None ) ,
668
744
} ;
669
745
670
746
let circuit = if simulate {
671
747
let mut sim = sim_circuit_backend ( ) ;
672
748
673
- self . run_with_sim_no_output ( entry_expr, & mut sim) ?;
749
+ match invoke_params {
750
+ Some ( ( callable, args) ) => {
751
+ let mut sink = std:: io:: sink ( ) ;
752
+ let mut out = GenericReceiver :: new ( & mut sink) ;
753
+
754
+ self . invoke_with_sim ( & mut sim, & mut out, callable, args) ?
755
+ }
756
+ None => self . run_with_sim_no_output ( entry_expr, & mut sim) ?,
757
+ } ;
674
758
675
759
sim. chained . finish ( )
676
760
} else {
@@ -679,7 +763,15 @@ impl Interpreter {
679
763
max_operations : CircuitConfig :: DEFAULT_MAX_OPERATIONS ,
680
764
} ) ;
681
765
682
- self . run_with_sim_no_output ( entry_expr, & mut sim) ?;
766
+ match invoke_params {
767
+ Some ( ( callable, args) ) => {
768
+ let mut sink = std:: io:: sink ( ) ;
769
+ let mut out = GenericReceiver :: new ( & mut sink) ;
770
+
771
+ self . invoke_with_sim ( & mut sim, & mut out, callable, args) ?
772
+ }
773
+ None => self . run_with_sim_no_output ( entry_expr, & mut sim) ?,
774
+ } ;
683
775
684
776
sim. finish ( )
685
777
} ;
@@ -759,6 +851,35 @@ impl Interpreter {
759
851
)
760
852
}
761
853
854
+ /// Invokes the given callable with the given arguments on the given simulator with a new instance of the environment
855
+ /// but using the current compilation.
856
+ pub fn invoke_with_sim (
857
+ & mut self ,
858
+ sim : & mut impl Backend < ResultType = impl Into < val:: Result > > ,
859
+ receiver : & mut impl Receiver ,
860
+ callable : Value ,
861
+ args : Value ,
862
+ ) -> InterpretResult {
863
+ qsc_eval:: invoke (
864
+ self . package ,
865
+ self . classical_seed ,
866
+ & self . fir_store ,
867
+ & mut Env :: default ( ) ,
868
+ sim,
869
+ receiver,
870
+ callable,
871
+ args,
872
+ )
873
+ . map_err ( |( error, call_stack) | {
874
+ eval_error (
875
+ self . compiler . package_store ( ) ,
876
+ & self . fir_store ,
877
+ call_stack,
878
+ error,
879
+ )
880
+ } )
881
+ }
882
+
762
883
fn compile_entry_expr (
763
884
& mut self ,
764
885
expr : & str ,
@@ -904,6 +1025,8 @@ pub enum CircuitEntryPoint {
904
1025
Operation ( String ) ,
905
1026
/// An explicitly provided entry expression.
906
1027
EntryExpr ( String ) ,
1028
+ /// A global callable with arguments.
1029
+ Callable ( Value , Value ) ,
907
1030
/// The entry point for the current package.
908
1031
EntryPoint ,
909
1032
}
0 commit comments