diff --git a/src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt b/src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt index fb694fa533b..4d1dd20a3bf 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt +++ b/src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt @@ -32,7 +32,7 @@ install(TARGETS qir-input-reference-standalone RUNTIME DESTINATION "${CMAKE_BINA include(CTest) add_test( NAME qir-input-reference-standalone - COMMAND qir-input-reference-standalone --int-value 1 --integer-array 1 2 3 4 5 --double-value 0.5 --double-array 0.1 0.2 0.3 0.4 0.5 --bool-value true --bool-array true TRUE false fALSe 1 --pauli-value PauliX --pauli-array PauliI paulix PAULIY PAulIZ --range-value 1 2 10 --range-array 1 2 10 5 5 50 10 1 20 --string-value ASampleString --result-value one --result-array one ONE true TRUE 1 zero ZERO false FALSE 0 + COMMAND qir-input-reference-standalone --int-value 1 --integer-array 1 2 3 4 5 --double-value 0.5 --double-array 0.1 0.2 0.3 0.4 0.5 --bool-value true --bool-array true TRUE false fALSe 1 --pauli-value PauliI --pauli-array PauliI paulix PAULIY PAulIZ --range-value 1 2 10 --range-array 1 2 10 5 5 50 10 1 20 --string-value ASampleString --result-value one --result-array one ONE 1 0 zero ZERO --string-array StringA StringB StringC ) # set the environment path for loading shared libs the tests are using diff --git a/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp b/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp index ee1d07a7cde..d5a3e934f82 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp +++ b/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include // for memcpy #include #include #include @@ -10,30 +9,63 @@ #include "CLI11.hpp" -#include "CoreTypes.hpp" #include "QirContext.hpp" -#include "QirTypes.hpp" -#include "QirRuntimeApi_I.hpp" -#include "SimFactory.hpp" #include "QirRuntime.hpp" +#include "SimFactory.hpp" using namespace Microsoft::Quantum; using namespace std; +struct InteropArray +{ + int64_t Size; + void* Data; + + InteropArray(int64_t size, void* data) : + Size(size), + Data(data){} +}; + +using RangeTuple = tuple; +struct InteropRange +{ + int64_t Start; + int64_t Step; + int64_t End; + + InteropRange() : + Start(0), + Step(0), + End(0){} + + InteropRange(RangeTuple rangeTuple) : + Start(get<0>(rangeTuple)), + Step(get<1>(rangeTuple)), + End(get<2>(rangeTuple)){} +}; + // This is the function corresponding to the QIR entry-point. -extern "C" int64_t Quantum__StandaloneSupportedInputs__ExerciseInputs__body( // NOLINT +extern "C" void Quantum__StandaloneSupportedInputs__ExerciseInputs( // NOLINT int64_t intValue, + InteropArray* integerArray, double doubleValue, - Result resultValue, - QirString* stringValue); - -const char FalseAsChar = 0x0; -const char TrueAsChar = 0x1; + InteropArray* doubleArray, + char boolValue, + InteropArray* boolArray, + char pauliValue, + InteropArray* pauliArray, + InteropRange* rangeValue, + char resultValue, + InteropArray* resultArray, + const char* stringValue); + +const char InteropFalseAsChar = 0x0; +const char InteropTrueAsChar = 0x1; map BoolAsCharMap{ - {"0", FalseAsChar}, - {"false", FalseAsChar}, - {"1", TrueAsChar}, - {"true", TrueAsChar}}; + {"0", InteropFalseAsChar}, + {"false", InteropFalseAsChar}, + {"1", InteropTrueAsChar}, + {"true", InteropTrueAsChar}}; map PauliMap{ {"PauliI", PauliId::PauliId_I}, @@ -41,59 +73,58 @@ map PauliMap{ {"PauliY", PauliId::PauliId_Y}, {"PauliZ", PauliId::PauliId_Z}}; +const char InteropResultZeroAsChar = 0x0; +const char InteropResultOneAsChar = 0x1; map ResultAsCharMap{ - {"0", FalseAsChar}, - {"Zero", FalseAsChar}, - {"false", FalseAsChar}, - {"1", TrueAsChar}, - {"One", TrueAsChar}, - {"true", TrueAsChar}}; + {"0", InteropResultZeroAsChar}, + {"Zero", InteropResultZeroAsChar}, + {"1", InteropResultOneAsChar}, + {"One", InteropResultOneAsChar} +}; template -QirArray* CreateQirArray(T* dataBuffer, int64_t itemCount) +unique_ptr CreateInteropArray(vector& v) +{ + unique_ptr array(new InteropArray(v.size(), v.data())); + return array; +} + +unique_ptr CreateInteropRange(RangeTuple rangeTuple) { - int32_t typeSize = sizeof(T); // NOLINT - QirArray* qirArray = quantum__rt__array_create_1d(typeSize, itemCount); - memcpy(qirArray->buffer, dataBuffer, typeSize * itemCount); - return qirArray; + unique_ptr range(new InteropRange(rangeTuple)); + return range; } -template -unique_ptr TranslateVectorToBuffer(vectorsourceVector, function translationFunction) +template +void FreePointerVector(vector& v) { - unique_ptr buffer (new D[sourceVector.size()]); - for (int index = 0; index < sourceVector.size(); index++) + for (auto p : v) { - buffer[index] = translationFunction(sourceVector[index]); + delete p; } - - return buffer; } -using RangeTuple = tuple; -QirRange TranslateRangeTupleToQirRange(RangeTuple rangeTuple) +char TranslatePauliToChar(PauliId& pauli) { - QirRange qirRange = { - get<0>(rangeTuple), // Start - get<1>(rangeTuple), // Step - get<2>(rangeTuple) // End - }; + return static_cast(pauli); +} - return qirRange; +template +void TranslateVector(vector& sourceVector, vector& destinationVector, function translationFunction) +{ + destinationVector.resize(sourceVector.size()); + transform(sourceVector.begin(), sourceVector.end(), destinationVector.begin(), translationFunction); } -bool TranslateCharToBool(char boolAsChar) +InteropRange* TranslateRangeTupleToInteropRangePointer(RangeTuple& rangeTuple) { - return (boolAsChar != FalseAsChar); + InteropRange* range = new InteropRange(rangeTuple); + return range; } -// Result Zero and One are opaque types defined by the runtime. They are declared here and initialized before executing -// the simulation. -Result RuntimeResultZero = nullptr; -Result RuntimeResultOne = nullptr; -Result TranslateCharToResult(char resultAsChar) +const char* TranslateStringToCharBuffer(string& s) { - return resultAsChar == FalseAsChar ? RuntimeResultZero : RuntimeResultOne; + return s.c_str(); } int main(int argc, char* argv[]) @@ -103,20 +134,14 @@ int main(int argc, char* argv[]) // Initialize simulator. unique_ptr sim = CreateFullstateSimulator(); QirContextScope qirctx(sim.get(), false /*trackAllocatedObjects*/); - RuntimeResultZero = sim->UseZero(); - RuntimeResultOne = sim->UseOne(); - // Add the --simulation-output and --operation-output options. - // N.B. These options should be present in all standalone drivers. + // Add the --simulation-output options. + // N.B. This option should be present in all standalone drivers. string simulationOutputFile; CLI::Option* simulationOutputFileOpt = app.add_option( "-s,--simulation-output", simulationOutputFile, "File where the output produced during the simulation is written"); - string operationOutputFile; - CLI::Option* operationOutputFileOpt = app.add_option( - "-o,--operation-output", operationOutputFile, "File where the output of the Q# operation is written"); - // Add the options that correspond to the parameters that the QIR entry-point needs. // Option for a Q# Int type. int64_t intValue = 0; @@ -135,8 +160,10 @@ int main(int argc, char* argv[]) app.add_option("--double-array", doubleVector, "A double array")->required(); // Option for a Q# Bool type. - bool boolValue = false; - app.add_option("--bool-value", boolValue, "A bool value")->required(); + char boolAsCharValue = InteropFalseAsChar; + app.add_option("--bool-value", boolAsCharValue, "A bool value") + ->required() + ->transform(CLI::CheckedTransformer(BoolAsCharMap, CLI::ignore_case)); // Option for a Q# Array type. // N.B. For command line parsing, a char vector is used because vector is a specialized version of vector not @@ -161,8 +188,8 @@ int main(int argc, char* argv[]) // Option for Q# Range type. // N.B. RangeTuple type is used here instead of QirRange because CLI11 supports tuple parsing which is leveraged and // the tuple is later translated to QirRange. - RangeTuple rangeValue(0, 0, 0); - app.add_option("--range-value", rangeValue, "A Range value (start, step, end)")->required(); + RangeTuple rangeTuple(0, 0, 0); + app.add_option("--range-value", rangeTuple, "A Range value (start, step, end)")->required(); // Option for a Q# Array type. vector rangeTupleVector; @@ -171,7 +198,7 @@ int main(int argc, char* argv[]) // Option for Q# Result type. // N.B. This is implemented as a char rather than a boolean to be consistent with the way an array of results has to // be implemented. - char resultAsCharValue = FalseAsChar; + char resultAsCharValue = InteropResultZeroAsChar; app.add_option("--result-value", resultAsCharValue, "A Result value") ->required() ->transform(CLI::CheckedTransformer(ResultAsCharMap, CLI::ignore_case)); @@ -188,41 +215,45 @@ int main(int argc, char* argv[]) string stringValue; app.add_option("--string-value", stringValue, "A String value")->required(); + // Option for a Q# Array type. + vector stringVector; + app.add_option("--string-array", stringVector, "A String array")->required(); + + // With all the options added, parse arguments from the command line. CLI11_PARSE(app, argc, argv); // Translate values to its final form after parsing. - // Create a QirArray of integer values. - QirArray* qirIntegerArray = CreateQirArray(integerVector.data(), integerVector.size()); - - // Create a QirArray of double values. - QirArray* qirDoubleArray = CreateQirArray(doubleVector.data(), doubleVector.size()); - - // Create a QirArray of bool values. - unique_ptr boolArray = TranslateVectorToBuffer(boolAsCharVector, TranslateCharToBool); - QirArray* qirboolArray = CreateQirArray(boolArray.get(), boolAsCharVector.size()); + // Create an interop array of integer values. + unique_ptr integerArray = CreateInteropArray(integerVector); - // Create a QirArray of Pauli values. - QirArray* qirPauliArray = CreateQirArray(pauliVector.data(), pauliVector.size()); + // Create an interop array of double values. + unique_ptr doubleArray = CreateInteropArray(doubleVector); - // Create a QirRange. - QirRange qirRange = TranslateRangeTupleToQirRange(rangeValue); + // Create an interop array of bool values. + unique_ptr boolArray = CreateInteropArray(boolAsCharVector); - // Create a QirArray of Range values. - unique_ptr rangeArray = TranslateVectorToBuffer( - rangeTupleVector, TranslateRangeTupleToQirRange); + // Translate a PauliID value to its char representation. + char pauliAsCharValue = TranslatePauliToChar(pauliValue); - QirArray* qirRangeArray = CreateQirArray(rangeArray.get(), rangeTupleVector.size()); + // Create an interop array of Pauli values represented as chars. + vector pauliAsCharVector; + TranslateVector(pauliVector, pauliAsCharVector, TranslatePauliToChar); + unique_ptr pauliArray = CreateInteropArray(pauliAsCharVector); - // Create a Result. - Result result = TranslateCharToResult(resultAsCharValue); + // Create an interop range. + unique_ptr rangeValue = CreateInteropRange(rangeTuple); + vector rangeVector; + TranslateVector(rangeTupleVector, rangeVector, TranslateRangeTupleToInteropRangePointer); + unique_ptr rangeArray = CreateInteropArray(rangeVector); - // Create a QirArray of Result values. - unique_ptr resultArray = TranslateVectorToBuffer(resultAsCharVector, TranslateCharToResult); - QirArray* qirResultArray = CreateQirArray(resultArray.get(), resultAsCharVector.size()); + // Create an interop array of Result values. + unique_ptr resultArray = CreateInteropArray(resultAsCharVector); - // Create a QirString. - QirString* qirString = quantum__rt__string_create(stringValue.c_str()); + // Create an interop array of String values. + vector stringBufferVector; + TranslateVector(stringVector, stringBufferVector, TranslateStringToCharBuffer); + unique_ptr stringArray = CreateInteropArray(stringBufferVector); // Redirect the simulator output from std::cout if the --simulation-output option is present. ostream* simulatorOutputStream = &cout; @@ -234,29 +265,23 @@ int main(int argc, char* argv[]) simulatorOutputStream = &simulationOutputFileStream; } - // Redirect the Q# operation output from std::cout if the --operation-output option is present. - ostream* operationOutputStream = &cout; - ofstream operationOutputFileStream; - if (!operationOutputFileOpt->empty()) - { - operationOutputFileStream.open(operationOutputFile); - operationOutputStream = &operationOutputFileStream; - } - // Run simulation and write the output of the operation to the corresponding stream. - int64_t operationOutput = Quantum__StandaloneSupportedInputs__ExerciseInputs__body( - intValue, doubleValue, result, qirString); - + Quantum__StandaloneSupportedInputs__ExerciseInputs( + intValue, + integerArray.get(), + doubleValue, + doubleArray.get(), + boolAsCharValue, + boolArray.get(), + pauliAsCharValue, + pauliArray.get(), + rangeValue.get(), + resultAsCharValue, + resultArray.get(), + stringValue.c_str()); + + FreePointerVector(rangeVector); simulatorOutputStream->flush(); - (*operationOutputStream) << operationOutput << endl; - operationOutputStream->flush(); - - // Close opened file buffers; - if (operationOutputFileStream.is_open()) - { - operationOutputFileStream.close(); - } - if (simulationOutputFileStream.is_open()) { simulationOutputFileStream.close(); diff --git a/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs b/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs index 0d6223eadab..23908eaa514 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs +++ b/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs @@ -1,15 +1,49 @@ namespace Quantum.StandaloneSupportedInputs { + open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; + function ArrayToString<'T> (array : 'T[]) : String + { + mutable first = true; + mutable itemsString = "["; + for item in array + { + if (first) + { + set first = false; + set itemsString = itemsString + $"{item}"; + } + else + { + set itemsString = itemsString + $", {item}"; + } + } + + set itemsString = itemsString + "]"; + return itemsString; + } + + function TautologyPredicate<'T> (input : 'T) : Bool + { + return true; + } + @EntryPoint() - operation ExerciseInputs (intValue : Int, doubleValue : Double, resultValue : Result, stringValue : String) : Int { - Message("Exercise Supported Inputs"); + operation ExerciseInputs (intValue : Int, intArray : Int[], doubleValue : Double, doubleArray : Double[], boolValue : Bool, boolArray : Bool[], pauliValue : Pauli, pauliArray : Pauli[], rangeValue : Range, resultValue : Result, resultArray : Result[], stringValue : String) : Unit { + Message("Exercise Supported Inputs Reference"); Message($"intValue: {intValue}"); + Message($"intArray: {ArrayToString(intArray)} ({Count(TautologyPredicate, intArray)})"); Message($"doubleValue: {doubleValue}"); + Message($"doubleArray: {ArrayToString(doubleArray)} ({Count(TautologyPredicate, doubleArray)})"); + Message($"boolValue: {boolValue}"); + Message($"boolArray: {ArrayToString(boolArray)} ({Count(TautologyPredicate, boolArray)})"); + Message($"pauliValue: {pauliValue}"); + Message($"pauliArray: {ArrayToString(pauliArray)} ({Count(TautologyPredicate, pauliArray)})"); + Message($"rangeValue: {rangeValue}"); Message($"resultValue: {resultValue}"); + Message($"resultArray: {ArrayToString(resultArray)} ({Count(TautologyPredicate, resultArray)})"); Message($"stringValue: {stringValue}"); - return 0; } } diff --git a/src/QirRuntime/test.py b/src/QirRuntime/test.py index 2c6e1a8e701..4e62ea33be7 100644 --- a/src/QirRuntime/test.py +++ b/src/QirRuntime/test.py @@ -100,8 +100,10 @@ def log(message): subprocess.run(test_binary + " ~[skip]", shell = True) log("========= Running samples =========") + sample_binary = os.path.join(install_dir, "qir-input-reference-standalone" + exe_ext) + log(sample_binary) subprocess.run( - "qir-input-reference-standalone" +\ + sample_binary +\ " --int-value 1" +\ " --integer-array 1 2 3 4 5" +\ " --double-value 0.5" +\ @@ -114,6 +116,7 @@ def log(message): " --range-array 1 2 10 5 5 50 10 1 20" +\ " --string-value ASampleString" +\ " --result-value one" +\ - " --result-array one ONE true TRUE 1 zero ZERO false FALSE 0") + " --result-array one ONE 1 zero ZERO 0" +\ + " --string-array StringA StringB StringC") print("\n")