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

Commit

Permalink
Added some math funcs implementation (#500)
Browse files Browse the repository at this point in the history
* Added sqrt implementation and tests.
* Restructured the files.
* Restructured sqrt.
* CR changes
* Fixed the Linux build break.
* Added Log() and ArcTan2().
* Added pauli_to_string
* CR changes.
* CR changes.
  • Loading branch information
kuzminrobin authored Feb 9, 2021
1 parent ce2580e commit fbd4b38
Show file tree
Hide file tree
Showing 19 changed files with 1,034 additions and 196 deletions.
1 change: 1 addition & 0 deletions src/QirRuntime/lib/QIR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ add_dependencies(qir-rt ${bridge_rt_target})
#
set(qis_sup_source_files
"intrinsics.cpp"
"intrinsicsMath.cpp"
)

add_library(qir-qis-support ${qis_sup_source_files})
Expand Down
103 changes: 79 additions & 24 deletions src/QirRuntime/lib/QIR/bridge-qis.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
%Range = type { i64, i64, i64 }
%Result = type opaque
%String = type opaque
%Pauli = type {i2}
%Pauli = type i2

;=======================================================================================================================
; Native types
Expand All @@ -29,9 +29,7 @@
%struct.QirCallable = type opaque
%struct.QirRange = type { i64, i64, i64 }
%struct.QirString = type opaque

; Assumptions:
; %PauliId = type {i32}
%PauliId = type i32

;===============================================================================
; declarations of the native methods this bridge delegates to
Expand Down Expand Up @@ -139,53 +137,53 @@ define %Result* @__quantum__qis__measure__body(%Array* %.paulis, %Array* %.qubit
ret %Result* %.r
}

define void @__quantum__qis__r__body(i2 %.pauli, double %theta, %Qubit* %.q) {
define void @__quantum__qis__r__body(%Pauli %.pauli, double %theta, %Qubit* %.q) {
%q = bitcast %Qubit* %.q to %class.QUBIT*
%pauli = zext i2 %.pauli to i32
call void @quantum__qis__r__body(i32 %pauli, double %theta, %class.QUBIT* %q)
%pauli = zext %Pauli %.pauli to %PauliId
call void @quantum__qis__r__body(%PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

define void @__quantum__qis__r__adj(i2 %.pauli, double %theta, %Qubit* %.q) {
define void @__quantum__qis__r__adj(%Pauli %.pauli, double %theta, %Qubit* %.q) {
%q = bitcast %Qubit* %.q to %class.QUBIT*
%pauli = zext i2 %.pauli to i32
call void @quantum__qis__r__adj(i32 %pauli, double %theta, %class.QUBIT* %q)
%pauli = zext %Pauli %.pauli to %PauliId
call void @quantum__qis__r__adj(%PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

define void @__quantum__qis__r__ctl(%Array* %.ctls, {i2, double, %Qubit*}* %.args) {
define void @__quantum__qis__r__ctl(%Array* %.ctls, {%Pauli, double, %Qubit*}* %.args) {
%ctls = bitcast %Array* %.ctls to %struct.QirArray*

%.ppauli = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load i2, i2* %.ppauli
%pauli = zext i2 %.pauli to i32
%.ppauli = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load %Pauli, %Pauli* %.ppauli
%pauli = zext %Pauli %.pauli to %PauliId

%.ptheta = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 1
%.ptheta = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 1
%theta = load double, double* %.ptheta

%.pq = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 2
%.pq = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 2
%.q = load %Qubit*, %Qubit** %.pq
%q = bitcast %Qubit* %.q to %class.QUBIT*

call void @quantum__qis__r__ctl(%struct.QirArray* %ctls, i32 %pauli, double %theta, %class.QUBIT* %q)
call void @quantum__qis__r__ctl(%struct.QirArray* %ctls, %PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

define void @__quantum__qis__r__ctladj(%Array* %.ctls, {i2, double, %Qubit*}* %.args) {
define void @__quantum__qis__r__ctladj(%Array* %.ctls, {%Pauli, double, %Qubit*}* %.args) {
%ctls = bitcast %Array* %.ctls to %struct.QirArray*

%.ppauli = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load i2, i2* %.ppauli
%pauli = zext i2 %.pauli to i32
%.ppauli = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load %Pauli, %Pauli* %.ppauli
%pauli = zext %Pauli %.pauli to %PauliId

%.ptheta = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 1
%.ptheta = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 1
%theta = load double, double* %.ptheta

%.pq = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 2
%.pq = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 2
%.q = load %Qubit*, %Qubit** %.pq
%q = bitcast %Qubit* %.q to %class.QUBIT*

call void @quantum__qis__r__ctladj(%struct.QirArray* %ctls, i32 %pauli, double %theta, %class.QUBIT* %q)
call void @quantum__qis__r__ctladj(%struct.QirArray* %ctls, %PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

Expand Down Expand Up @@ -281,3 +279,60 @@ define void @__quantum__qis__z__ctl(%Array* %.ctls, %Qubit* %.q) {
}


;===============================================================================
; quantum.qis math functions
;

; LLVM intrinsics (https://llvm.org/docs/LangRef.html):
declare double @llvm.sqrt.f64(double %.val)
declare double @llvm.log.f64(double %Val)

; Native implementations:
declare i1 @quantum__qis__isnan__body(double %d)
declare double @quantum__qis__infinity__body()
declare i1 @quantum__qis__isinf__body(double %d)
declare double @quantum__qis__arctan2__body(double %y, double %x)

; API for the user code:
define double @__quantum__qis__nan__body() { ; Q#: function NAN() : Double http://www.cplusplus.com/reference/cmath/nan-function/
%result = call double @llvm.sqrt.f64(double -1.0) ; sqrt(<negative>) -> NaN
ret double %result
}

define i1 @__quantum__qis__isnan__body(double %d) { ; http://www.cplusplus.com/reference/cmath/isnan/
%result = call i1 @quantum__qis__isnan__body(double %d)
ret i1 %result
}

define double @__quantum__qis__infinity__body() { ; https://en.cppreference.com/w/c/numeric/math/INFINITY
%result = call double @quantum__qis__infinity__body()
ret double %result
}

define i1 @__quantum__qis__isinf__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/isinf
%result = call i1 @quantum__qis__isinf__body(double %d)
ret i1 %result
}

define double @__quantum__qis__sqrt__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/sqrt
%result = call double @llvm.sqrt.f64(double %d)
ret double %result
}

define double @__quantum__qis__log__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/log
%result = call double @llvm.log.f64(double %d)
ret double %result
}

define i1 @__quantum__qis__isnegativeinfinity__body(double %d) { ; Q#: function IsNegativeInfinity(d : Double) : Bool
; https://en.cppreference.com/w/cpp/numeric/math/log https://llvm.org/docs/LangRef.html#llvm-log-intrinsic
%negInf = call double @llvm.log.f64(double 0.0) ; ln(0) -> (-infinity)
%result = fcmp oeq double %negInf, %d ; %result = (%negInf == %d)
ret i1 %result
}

define double @__quantum__qis__arctan2__body(double %y, double %x) { ; Q#: function ArcTan2 (y : Double, x : Double) : Double
; https://en.cppreference.com/w/cpp/numeric/math/atan2
%result = call double @quantum__qis__arctan2__body(double %y, double %x)
ret double %result
}
16 changes: 11 additions & 5 deletions src/QirRuntime/lib/QIR/bridge-rt.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
%Result = type opaque
%String = type opaque
%Tuple = type opaque
%Pauli = type {i2}
%Pauli = type i2

;=======================================================================================================================
; Native types
Expand All @@ -27,6 +27,7 @@
%"struct.QirCallable" = type opaque
%"struct.QirRange" = type { i64, i64, i64 }
%"struct.QirString" = type opaque
%PauliId = type i32
; %Tuple* is mapped to i8*

;=======================================================================================================================
Expand Down Expand Up @@ -97,7 +98,7 @@ declare %"struct.QirString"* @quantum__rt__int_to_string(i64)
declare %"struct.QirString"* @quantum__rt__double_to_string(double)
declare %"struct.QirString"* @quantum__rt__bool_to_string(i1)
declare %"struct.QirString"* @quantum__rt__result_to_string(%class.RESULT*)
declare %"struct.QirString"* @quantum__rt__pauli_to_string(i32)
declare %"struct.QirString"* @quantum__rt__pauli_to_string(%PauliId)
declare %"struct.QirString"* @quantum__rt__qubit_to_string(%class.QUBIT*)
declare %"struct.QirString"* @quantum__rt__range_to_string(%"struct.QirRange"* dereferenceable(24) %range)

Expand Down Expand Up @@ -378,10 +379,9 @@ define void @__quantum__rt__callable_memory_management(i32 %index, %Callable* %.
; strings bridge
;
; NYI:
;define %String* @__quantum__rt__pauli_to_string(%Pauli) ; need to check that the type is lowered correctly
;define %String* @__quantum__rt__bigint_to_string(%BigInt*)

define %String* @__quantum__rt__string_create(i8* %null_terminated_buffer) {
define %String* @__quantum__rt__string_create(i32 %ignoredStrLength, i8* %null_terminated_buffer) {
%str = call %"struct.QirString"* @quantum__rt__string_create(i8* %null_terminated_buffer)
%.str = bitcast %"struct.QirString"* %str to %String*
ret %String* %.str
Expand Down Expand Up @@ -435,6 +435,13 @@ define %String* @__quantum__rt__result_to_string(%Result* %.r) {
ret %String* %.str
}

define %String* @__quantum__rt__pauli_to_string(%Pauli %.pauli) {
%pauli = zext %Pauli %.pauli to %PauliId
%str = call %"struct.QirString"* @quantum__rt__pauli_to_string(%PauliId %pauli)
%.str = bitcast %"struct.QirString"* %str to %String*
ret %String* %.str
}

define %String* @__quantum__rt__qubit_to_string(%Qubit* %.q) {
%q = bitcast %Qubit* %.q to %"class.QUBIT"*
%str = call %"struct.QirString"* @quantum__rt__qubit_to_string(%"class.QUBIT"* %q)
Expand All @@ -451,7 +458,6 @@ define %String* @__quantum__rt__range_to_string(%Range %.range) {
ret %String* %.str
}


;------------------------------------------------------------------------------
; bigints bridge
;
Expand Down
31 changes: 31 additions & 0 deletions src/QirRuntime/lib/QIR/intrinsicsMath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include <cmath>
#include "quantum__qis.hpp"

extern "C"
{

// Implementations:
bool quantum__qis__isnan__body(double d)
{
return std::isnan(d); // https://en.cppreference.com/w/cpp/numeric/math/isnan
}

double quantum__qis__infinity__body()
{
return INFINITY; // https://en.cppreference.com/w/c/numeric/math/INFINITY
}

bool quantum__qis__isinf__body(double d)
{
return std::isinf(d); // https://en.cppreference.com/w/cpp/numeric/math/isinf
}

double quantum__qis__arctan2__body(double y, double x)
{
return std::atan2(y, x); // https://en.cppreference.com/w/cpp/numeric/math/atan2
}

} // extern "C"
6 changes: 6 additions & 0 deletions src/QirRuntime/lib/QIR/quantum__qis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@ extern "C"
QIR_SHARED_API void quantum__qis__y__ctl(QirArray*, QUBIT*); // NOLINT
QIR_SHARED_API void quantum__qis__z__body(QUBIT*); // NOLINT
QIR_SHARED_API void quantum__qis__z__ctl(QirArray*, QUBIT*); // NOLINT

QIR_SHARED_API bool quantum__qis__isnan__body(double d); // NOLINT
QIR_SHARED_API double quantum__qis__infinity__body(); // NOLINT
QIR_SHARED_API bool quantum__qis__isinf__body(double d); // NOLINT
QIR_SHARED_API double quantum__qis__arctan2__body(double y, double x); // NOLINT

}
3 changes: 3 additions & 0 deletions src/QirRuntime/lib/QIR/strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ extern "C"
return quantum__rt__string_create("PauliY");
case PauliId_Z:
return quantum__rt__string_create("PauliZ");
default:
break;
}
return quantum__rt__string_create("<Unexpected Pauli Value>");
}

// Returns a string representation of the range.
Expand Down
4 changes: 3 additions & 1 deletion src/QirRuntime/public/CoreTypes.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <cstdint>

// The core types will be exposed in the C-interfaces for interop, thus no
// namespaces or scoped enums can be used to define them.

Expand Down Expand Up @@ -27,7 +29,7 @@ enum ResultValue
/*==============================================================================
PauliId matrices
==============================================================================*/
enum PauliId
enum PauliId : int32_t
{
PauliId_I = 0,
PauliId_X = 1,
Expand Down
5 changes: 4 additions & 1 deletion src/QirRuntime/test/QIR-static/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ add_custom_target(qir_static_test_lib DEPENDS ${QIR_TESTS_LIBS})
# The executable target for QIR tests triggers the custom actions to compile ll files
#
add_executable(qir-static-tests
qir-driver.cpp)
qir-driver.cpp
qir-test-math.cpp
qir-test-strings.cpp
)

target_link_libraries(qir-static-tests PUBLIC
${QIR_TESTS_LIBS}
Expand Down
37 changes: 37 additions & 0 deletions src/QirRuntime/test/QIR-static/compiler/Constants.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// these are all the static methods and const fields form System.Math class of .NET CLR
// that are not exposed as language operators and are relevant within type System.
// If there are two versions of the function for Int and Double types, the corresponding
// functions have suffix I or D. ExpD also has a suffix to avoid name clash with Primitives.Exp.

namespace Microsoft.Quantum.Math {

/// # Summary
/// Returns the natural logarithmic base to double-precision.
///
/// # Output
/// A double-precision approximation of the natural logarithic base,
/// $e \approx 2.7182818284590452354$.
///
/// # See Also
/// - Microsoft.Quantum.Math.PI
function E() : Double {
return 2.7182818284590452354;
}

/// # Summary
/// Represents the ratio of the circumference of a circle to its diameter.
///
/// # Ouptut
/// A double-precision approximation of the the circumference of a circle
/// to its diameter, $\pi \approx 3.14159265358979323846$.
///
/// # See Also
/// - Microsoft.Quantum.Math.E
function PI() : Double {
return 3.14159265358979323846;
}

}
41 changes: 41 additions & 0 deletions src/QirRuntime/test/QIR-static/compiler/QirTarget.qs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@ namespace Microsoft.Quantum.Intrinsic {

open Microsoft.Quantum.Targeting;

@Inline()
function NAN() : Double {
body intrinsic;
}

@Inline()
function IsNan(d: Double) : Bool {
body intrinsic;
}

@Inline()
function INFINITY() : Double {
body intrinsic;
}

@Inline()
function IsInf(d: Double) : Bool {
body intrinsic;
}

@Inline()
function IsNegativeInfinity(d : Double) : Bool {
body intrinsic;
}

@Inline()
function Sqrt(d : Double) : Double {
body intrinsic;
}

@Inline()
function Log(d : Double) : Double {
body intrinsic;
}

@Inline()
function ArcTan2(y : Double, x : Double) : Double {
body intrinsic;
}


operation X(qb : Qubit) : Unit
is Adj + Ctl {
body intrinsic;
Expand Down
Loading

0 comments on commit fbd4b38

Please sign in to comment.