Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Using the QIR Tracer with a Q# project #865

Open
@anpaz

Description

@anpaz

After working on #864, I was able to compile and analyze the database-search sample project using the QIR Tracer runtime on a Mac laptop.

Since QIR's Tracer is still not incorporated into Q#'s build framework or the internal qir-tool, there are a few more manual steps need to achieve this. These are my notes.

Pre-reqs

Same set=up as #864: checked out the repos qsharp-runtime and Quantum (i.e. samples) under a ~/Repos folder. Then installed:

  • powershell 7+ (brew install --cask powershell): needed to run all build scripts
  • cmake 3.20+ (brew install cmake): all our native projects are based on cmake for x-platform support
  • clang (xcode-select --install): needed to compile native code
  • dotnet: needed by the Q# compiler and qir-cli tool.

Note: there might be other dependencies that were already installed on my environment. Also, bootstrap.ps1 installs Rust automatically (used for the experimental simulator), and might install other things.

Build QIR Runtime components

Run bootstrap.ps1 under root to build Native simulators and basic Qir runtime

cd ~/Repos/qsharp-rutnime
pwhs ./bootstrap.ps1

Build rest of QIR:

cd ~/Repos/qsharp-runtime/src/Qir
pwsh ./build_all.ps1

Note: The database-search project calls Measure for the output, which currently triggers an Exception on Tracer.
I modified the code and recompile to simply return Zero.

1. Generate QIR from Q# project

We can't use the OOTB QIR generation for the Tracer library. Tracer requires its own set of intrinsic operations and all regular intrinsic operations need to be decomposed accordingly. At a high level, all operations we wish to track need to make a call to either single_qubit_op or multi_qubit_op, everything needs to be decomposed into these two.

A Q# file with such decompositions can be found at qsharp-runtime/src/Qir/Tests/QIR-tracer/qsharp/tracer-target.qs.
To incorporate this into your project, download and copy it to your project's src folder, e.g.:

cd ~/Repos/Quantum/samples/algorithms/database-search
cp ~/Repos/qsharp-runtime/src/Qir/Tests/QIR-tracer/qsharp/tracer-target.qs .

However, trying to compile this with dotnet build /property:QirGeneration=true triggers errors as the intrinsics are duplicated.

To fix this we need to remove the built-in intrinsics library when calling the Q# compiler.

There are a couple of ways to do this, what I did is I modify the resource file generated for the
QirGeneration=true the parameter (found in obj/qsharp/config/qsc.rsp) and remove the Microsoft.Quantum.QSharp.Core.dll from it, then call directly the Q# compiler using this file:

dotnet ~/.nuget/packages/microsoft.quantum.sdk/0.19.2109165653/DefaultItems/../tools/qsc/qsc.dll  build --format MsBuild -v Normal --response-files  obj/qsharp/config/qsc.rsp 

Note the existing tracer-target.qs is missing a couple of intrinsics:

  • R1
  • Reset
  • ResetAll
  • MResetZ
    which I manually added to compile successfully.

This generates two versions of the QIR code:

  1. qir/DatabaseSearchSample.ll: with the text version
  2. obj/qsharp/DatabaseSearchSample.bc: with the binary version

Compile QIR

It's very simple:

c++ -c qir/DatabaseSearchSample.ll -o output/qir.o

Generate & compile driver

The generated QIR code does not have a built-in main function. A driver
program that initializes the Tracer and invokes the operation is needed. The
driver also needs a mapping from operation ids to names.

I chose to modify the driver auto-generated by the qir-tool. The new file can be found in this gist:
tracer-driver.cpp

Download the file into the database-search folder and compile it:

wget https://gist.githubusercontent.com/anpaz/893fec94a6d58b0bfc8c12267c7f0a7a/raw/e00872d0d7904b8174f17c807e1d1efccb73098c/tracer-driver.cpp -O tracer-driver.cpp 
c++ -c tracer-driver.cpp -o output/tracer-driver.o  -std=gnu++17 -I ~/Repos/qsharp-runtime/src/Qir/Runtime/public

Another required step is to make the runtime QIR libraries discoverable for the linker and at runtime.
To achieve this, create a lib folder, and copy all the dlls from the Qir bin output folder. Then set

mkdir lib
find ~/Repos/qsharp-runtime/src/Qir/Runtime/bin/Debug/bin -name "*.dylib" -exec cp "{}" lib \;
export LIBRARY_PATH=$LIBRARY_PATH:lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:lib

Now we can link everything to generate an executble a.out:

c++ output/qir.o output/tracer-driver.o  \
    -lMicrosoft.Quantum.Qir.Runtime  \
    -lMicrosoft.Quantum.Qir.QSharp.Foundation  \
    -lMicrosoft.Quantum.Qir.QSharp.Core \
    -lMicrosoft.Quantum.Qir.Tracer

This creates an a.out file. To trace the Q# operation, run the program, the output should be something like this:

$ ./a.out

Quantum search for marked element in database.
  Database size: 64.
  Classical success probability: 0.015625
  Queries per search: 7 
  Quantum success probability: 0.59138015005737521

Attempt 10. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 20. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 30. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 40. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 50. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 60. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 70. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 80. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 90. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
Attempt 100. Success: Zero,  Probability: 1.0 Speedup: 9.14300000000000068 Found database index [Zero, Zero, Zero, Zero, Zero, Zero]
layer_id,name,X,MCX,MCZ,H,Rx,100
0,,0,0,0,600,0,0
1,,0,100,0,0,0,0
2,,0,0,0,0,100,0
3,,0,100,0,0,0,0
4,,100,0,0,600,0,0
5,,600,0,0,0,0,0
6,,0,0,100,0,0,0
7,,700,0,0,0,0,0
8,,0,0,0,600,0,0
9,,0,100,0,0,0,0
10,,0,0,0,0,100,0
11,,0,100,0,0,0,0
12,,100,0,0,600,0,0
13,,600,0,0,0,0,0
14,,0,0,100,0,0,0
15,,700,0,0,0,0,0
16,,0,0,0,600,0,0
17,,0,100,0,0,0,0
18,,0,0,0,0,100,0
19,,0,100,0,0,0,0
20,,100,0,0,600,0,0
21,,600,0,0,0,0,0
22,,0,0,100,0,0,0
23,,700,0,0,0,0,0
24,,0,0,0,600,0,0
25,,0,100,0,0,0,0
26,,0,0,0,0,0,700

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintenanceImprove codebase quality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions