Commit 8e502cf3 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

[WIP] working on passing C++ functions from qcor to qsharp



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 731de70f
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
namespace QCOR 
{
open QCOR.Intrinsic;
// Running VQE with an externally-provided optimization "stepper" interface:
// The stepper interface is "(current_params, energy) => (new_params)"
// Note: parameter initialization is done here.
// Returns the final energy.
operation DeuteronVqe(shots: Int, stepper : ((Double, Double[]) => Double[])) : Double {
    // Stopping conditions:
    let max_iters = 100;
    let f_tol = 0.01;
    let initial_params = [0.0];
        
    mutable opt_params = initial_params;

    mutable numParityOnes = 0;
    use (qubits = Qubit[2])
    {
        for test in 1..shots {
            X(qubits[0]);
            Ry(opt_params[0], qubits[1]);
            CNOT(qubits[1], qubits[0]);
            // Let's measure <X0X1>
            H(qubits[0]);
            H(qubits[1]);
            if M(qubits[0]) != M(qubits[1]) 
            {
                set numParityOnes += 1;
            }
            if M(qubits[0]) == One {
                X(qubits[0]);
            }
            if M(qubits[1]) == One {
                X(qubits[1]);
            }
        }
    }
    let res =  IntAsDouble(shots - numParityOnes)/IntAsDouble(shots) - IntAsDouble(numParityOnes)/IntAsDouble(shots);
    
    set opt_params = stepper(res, opt_params);
    return res;
}
}
 No newline at end of file
+26 −0
Original line number Diff line number Diff line
#include <iostream> 
#include <vector>
#include "qir-types.hpp"

// Include the external QSharp function.
qcor_include_qsharp(QCOR__DeuteronVqe__body, double, int64_t shots, Callable* opt_stepper);

// Compile with:
// Include both the qsharp source and this driver file
// in the command line.
// $ qcor -qrt ftqc vqe_ansatz.qs vqe_driver.cpp
// Run with:
// $ ./a.out
int main() {
  std::function<std::vector<double>(double, std::vector<double>)> stepper =
      [&](double in_costVal, std::vector<double> previous_params) -> std::vector<double> {
        std::cout << "HELLO CALLBACK!\n";
        return {1.0};
      };
  qcor::qsharp::CallBack<std::vector<double>, double, std::vector<double>> cbFunc(
      stepper);

  Callable cb(&cbFunc);
  const double exp_val_xx = QCOR__DeuteronVqe__body(1024, &cb);
  return 0;
}
 No newline at end of file
+15 −0
Original line number Diff line number Diff line
@@ -103,4 +103,19 @@ Array *__quantum__rt__array_project(Array *array, int dim, int64_t index);

// String-related API
void __quantum__rt__string_update_reference_count(void *str, int64_t count);

// Tuples:
TuplePtr __quantum__rt__tuple_create(int64_t size);
void __quantum__rt__tuple_update_reference_count(TuplePtr th, int32_t c);
void __quantum__rt__tuple_update_alias_count(TuplePtr th, int32_t c);

// Callables:
void __quantum__rt__callable_update_reference_count(Callable *clb, int32_t c);
void __quantum__rt__callable_update_alias_count(Callable *clb, int32_t c);
void __quantum__rt__callable_invoke(Callable *clb, TuplePtr args, TuplePtr res);
Callable *__quantum__rt__callable_copy(Callable *clb, bool force);
void __quantum__rt__capture_update_reference_count(Callable *clb,
                                                   int32_t count);
void __quantum__rt__capture_update_alias_count(Callable *clb, int32_t count);
void __quantum__rt__callable_memory_management(int32_t index, Callable* clb, int64_t parameter);
}
 No newline at end of file
+62 −4
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@

#include <cassert>
#include <stdexcept>

#include <functional>
// Defines implementations of QIR Opaque types

// FIXME - Qubit should be a struct that keeps track of idx
@@ -69,8 +69,6 @@ private:
  Storage m_storage;
};

using TupleHeader = int *;

enum Pauli : int8_t {
  Pauli_I = 0,
  Pauli_X,
@@ -87,7 +85,67 @@ struct Range {
  int64_t end;
};

using TuplePtr = int8_t *;
struct TupleHeader {
  // Opaque/generic storage
  using Storage = std::vector<int8_t>;
  TuplePtr getTuple() { return &m_storage.front(); }
  static TupleHeader *create(int size) { return new TupleHeader(size); }
  static TupleHeader *getHeader(TuplePtr tuple) {
    // Get the TupleHeader wrapper
    return reinterpret_cast<TupleHeader *>(tuple -
                                        offsetof(TupleHeader, m_storage));
  }

private:
  TupleHeader(int size) : m_storage(size, 0){};
  Storage m_storage;
};

// Callable:
// Note: this implementation is not fully spec-conformed
// since we don't handle complex adj or ctrl callables.
// Currently, this is to support wrapping a C++ function (classical)
// and providing it to Q# for invocation.
// TODO: we need a strategy to incorporate MSFT runtime implementation
// to support callables that are *created* by Q# code.
// These Q#-created callables have many more features as described in:
// https://github.com/microsoft/qsharp-language/blob/main/Specifications/QIR/Callables.md
// Forward declare:
namespace qcor {
namespace qsharp {
class IFunctor;
}
} // namespace qcor

struct Callable {
  void invoke(TuplePtr args, TuplePtr result);
  Callable(qcor::qsharp::IFunctor *in_functor) : m_functor(in_functor) {}

private:
  qcor::qsharp::IFunctor *m_functor;
};

namespace qcor {
// Helper func.
std::vector<int64_t> getRangeValues(Array *in_array, const Range &in_range);
std::vector<int64_t> getRangeValues(::Array *in_array, const ::Range &in_range);

namespace qsharp {
class IFunctor {
public:
  virtual void execute(TuplePtr args, TuplePtr result) = 0;
};
template <typename ReturnType, typename... ArgTypes>
class CallBack : public IFunctor {
public:
  CallBack(std::function<ReturnType(ArgTypes...)> in_func) : m_func(in_func){};
  virtual void execute(TuplePtr args, TuplePtr result) override {
    printf("Howdy callable\n");
    printf(__PRETTY_FUNCTION__);
  }

private:
  std::function<ReturnType(ArgTypes...)> m_func;
};
} // namespace qsharp
} // namespace qcor
+43 −0
Original line number Diff line number Diff line
#include "qir-qrt.hpp"
#include <iostream>

extern "C" {
void __quantum__rt__callable_update_reference_count(Callable *clb, int32_t c) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
}
void __quantum__rt__callable_update_alias_count(Callable *clb, int32_t c) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
}
void __quantum__rt__callable_invoke(Callable *clb, TuplePtr args,
                                    TuplePtr res) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
  if (clb) {
    clb->invoke(args, res);
  }
  else {
    std::cout << "Callback is NULL.\n";
  }
}
Callable *__quantum__rt__callable_copy(Callable *clb, bool force) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
  return nullptr;
}
void __quantum__rt__capture_update_reference_count(Callable *clb,
                                                   int32_t count) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
}
void __quantum__rt__capture_update_alias_count(Callable *clb, int32_t count) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
}
void __quantum__rt__callable_memory_management(int32_t index, Callable *clb,
                                               int64_t parameter) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
}
}
 No newline at end of file
Loading