StationQ / Liquid

The Language-Integrated Quantum Operations (LIQUi|>) Simulator
http://StationQ.github.io/Liquid
Other
440 stars 97 forks source link

Nesting Circuit.Run will throw error #42

Closed Calavoow closed 7 years ago

Calavoow commented 7 years ago

I would like to partially Circuit.Fold a function, because circuit folding also includes moving labels on the right to the left. In this example I'm labelling the inputs of a function using the function labellingStart. I then compile the labelling to a circuit, to fold it so the labelling is executed in parallel. The labelling must then be applied to the larger circuit function in which it is embedded (not shown); I apply the Circuit.Run to make sure that the circStart is included in the larger circuit (otherwise circStart is not included in the output). This, however, seems to not be possible since it throws an error. Is this intended? What alternative way is there to put labels on the left and on the right which are shown in parallel, but are not moved by Circuit.Fold?

let k = Ket(4)
let qs = k.Qubits
let expand (qs: Qubits) =
    match (List.map(fun l -> [l]) qs) with
    | ki3 :: ki2 :: ki1 :: ki :: [] ->

        let labellingStart (qbs: Qubits) =
            LabelL "\\ket{k_i}" [qbs.[3]]
            LabelL "\\ket{k_{i+1}}" [qbs.[2]]
            LabelL "\\ket{k_{i+2}}" [qbs.[1]]
            LabelL "\\ket{k_{i+3}}" [qbs.[0]]

        let circStart = (Circuit.Compile labellingStart qs).Fold()
        circStart.Run qs

        // ... Remainder of circuit function ....
    | x -> failwithf "4 qubits must be given, instead was given %A" x
let circ = Circuit.Compile expand qs

I get the following error:

0:0000.0/=============== Logging to: Liquid.log opened ================
0:0000.0/Error running function draw(): Exception has been thrown by the target of an invocation.
0:0000.0/Inner: Circuit.Run: Must provide a ket state that has legal qubits
0:0000.0/Error occured at Invoke
0:0000.0/!!!!!!!!!!!!!!!!!!!!!! Stack Trace !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
0:0000.0/  at ad.c (System.String A_0) [0x0023c]
0:0000.0/    in <16e8952738114e09bd59d5cb36925823>:0 
0:0000.0/  at Microsoft.Research.Liquid.Parser.CommandRun (Microsoft.Research.Liquid.LiquidArgs las) [0x000c4]
0:0000.0/    in <16e8952738114e09bd59d5cb36925823>:0 
0:0000.0/!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
0:0000.0/!!!    ERROR: Exiting Liquid
0:0000.0/!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
dbwz8 commented 7 years ago

Yes. This is expected behavior. You cannot nest Circuit.Compile, Circuit.Run or Circuit.Fold. The standard technique is do each of these once. Here is a version of your code as an fsx script in samples:

#if INTERACTIVE
#I @"..\bin"         // Tell fsi where to find the Liquid dll
#r "Liquid1.dll"                 
#r "Liquid2.dll"                 
#else
namespace Microsoft.Research.Liquid // Tell the compiler our namespace
#endif

open System                         // Open any support libraries

open Microsoft.Research.Liquid      // Get necessary Liquid libraries
open Util                           // General utilites
open Operations                     // Basic gates and operations
open Tests                          // Just gets us the RenderTest call for dumping files

module Script =                     // The script module allows for incremental loading

    [<LQD>]                         // LQD flags this as being callable from the command line
    let Main() =                    // Name of callable function

        logOpen "Liquid.log" false
        show "Starting sample script..."    // show does printf + logs and ensemble runs

        let k = Ket(4)
        let qs = k.Qubits
        let expand (qs: Qubits) =
            match (List.map(fun l -> [l]) qs) with
            | [_;_;_;_] ->

                let labellingStart (qbs: Qubits) =
                    LabelL "\\ket{k_i}" [qbs.[3]]
                    LabelL "\\ket{k_{i+1}}" [qbs.[2]]
                    LabelL "\\ket{k_{i+2}}" [qbs.[1]]
                    LabelL "\\ket{k_{i+3}}" [qbs.[0]]

                labellingStart qs

                // ... Remainder of circuit function ....
                H >< qs
                M >< qs

            | x -> failwithf "4 qubits must be given, instead was given %A" x
        let circ = Circuit.Compile expand qs
        let circ = circ.Fold()
        circ.RenderHT "Test"

#if INTERACTIVE
do Script.Main()        // If interactive, then run the routine automatically
#endif

This will generate a drawing of the circuit as "Test.htm" (and Test.tex). What you really want to do comes under the area of Circuit manipulation. You can take any function and compile it to a circuit (as well as fold it). If you made your labels in one circuit and your real algorithm in one (or more) other compiled circuits, then you could just walk the circuit data structure and splice them together (this functionality is not built into the system).

If you take a look in the kit at \Liquid\UserCode\DaveWecker\AltOutput.fs you'll see an example where I programmatically walk the circuit data structure to emit QASM code. you could just walk your separate circuits to generate a single new one for execution or rendering.