From 9481c4117b9d0324c63aa7481124b2ce12090206 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 6 Oct 2025 17:30:19 +0900 Subject: [PATCH 1/2] Implement Parameter class by using Qiskit C-API --- src/circuit/parameter.hpp | 781 ++++++++++++++++++++++---------------- test/test_parameter.cpp | 350 +++++++++++++++++ 2 files changed, 809 insertions(+), 322 deletions(-) create mode 100644 test/test_parameter.cpp diff --git a/src/circuit/parameter.hpp b/src/circuit/parameter.hpp index 4f10a37..8c203c9 100644 --- a/src/circuit/parameter.hpp +++ b/src/circuit/parameter.hpp @@ -17,350 +17,489 @@ #ifndef __qiskitcpp_circuit_parameter_hpp__ #define __qiskitcpp_circuit_parameter_hpp__ -// this macro replaces Complex64 used in rust FFI -#define Complex64 std::complex +#include +#include -// We will enable Parameter if C-API will support ParameterExpression -#ifdef ENABLE_QISKIT_PARAMETER +#include "utils/types.hpp" #include "qiskit.h" -using rust_parameter = ::QkParameterExpression; -#else -using rust_parameter = void*; -#endif -namespace Qiskit { -namespace circuit { +using qiskit_param = ::QkParam; +namespace Qiskit +{ +namespace circuit +{ -#ifdef ENABLE_QISKIT_PARAMETER class Parameter { - friend class QuantumCircuit; + friend class QuantumCircuit; protected: - rust_parameter* expr_ = nullptr; + std::shared_ptr qiskit_param_ = nullptr; public: - /// @brief Create a new Parameter - Parameter() - { - expr_ = qk_parameter_from_int(0); - } - - /// @brief Create a new Parameter with v - /// @param (v) - Parameter(double v) - { - expr_ = qk_parameter_from_real(v); - } - - /// @brief Create a new Parameter with v - /// @param (v) - Parameter(int_t v) - { - expr_ = qk_parameter_from_int(v); - } - - /// @brief Create a new symbol - /// @param (expr) - Parameter(std::string name) - { - expr_ = qk_parameter_symbol((char*)name.c_str()); - } - - /// @brief Create a new Parameter as a copy of prm - /// @param (prm) copy source - Parameter(const Parameter& prm) - { - expr_ = qk_parameter_copy(prm.expr_); - } - - /// @brief Create a new Parameter with expr - /// @param (expr) - Parameter(rust_parameter* expr) - { - expr_ = expr; - } - - ~Parameter() - { - qk_parameter_free(expr_); - } - - std::string as_str(void) - { - return std::string(qk_parameter_to_string(expr_)); - } - - - Parameter operator-(); - - Parameter operator+(Parameter& prm); - Parameter operator-(Parameter& prm); - Parameter operator*(Parameter& prm); - Parameter operator/(Parameter& prm); - - Parameter operator+(double prm); - Parameter operator-(double prm); - Parameter operator*(double prm); - Parameter operator/(double prm); - - Parameter& operator=(Parameter& prm) - { -// qc_param_assign(expr_, prm.expr_); - return *this; - } - - Parameter& operator+=(Parameter& rhs) - { - rust_parameter* t = qk_parameter_add(expr_, rhs.expr_); - qk_parameter_free(expr_); - expr_ = t; - return *this; - } - - Parameter& operator-=(Parameter& rhs) - { - rust_parameter* t = qk_parameter_sub(expr_, rhs.expr_); - qk_parameter_free(expr_); - expr_ = t; - return *this; - } - - Parameter& operator*=(Parameter& rhs) - { - rust_parameter* t = qk_parameter_mul(expr_, rhs.expr_); - qk_parameter_free(expr_); - expr_ = t; - return *this; - } - - Parameter& operator/=(Parameter& rhs) - { - rust_parameter* t = qk_parameter_div(expr_, rhs.expr_); - qk_parameter_free(expr_); - expr_ = t; - return *this; - } - - Parameter& pow(Parameter& prm) - { - rust_parameter* t = qk_parameter_pow(expr_, prm.expr_); - qk_parameter_free(expr_); - expr_ = t; - return *this; - } - - Parameter exp(void) - { - Parameter ret(qk_parameter_exp(expr_)); - return ret; - } - - Parameter log(void) - { - Parameter ret(qk_parameter_log(expr_)); - return ret; - } - - Parameter abs(void) - { - Parameter ret(qk_parameter_abs(expr_)); - return ret; - } - - Parameter sin(void) - { - Parameter ret(qk_parameter_sin(expr_)); - return ret; - } - - Parameter cos(void) - { - Parameter ret(qk_parameter_cos(expr_)); - return ret; - } - - Parameter tan(void) - { - Parameter ret(qk_parameter_tan(expr_)); - return ret; - } - - Parameter asin(void) - { - Parameter ret(qk_parameter_asin(expr_)); - return ret; - } - - Parameter acos(void) - { - Parameter ret(qk_parameter_acos(expr_)); - return ret; - } - - Parameter atan(void) - { - Parameter ret(qk_parameter_atan(expr_)); - return ret; - } - + /// @brief Create a new Parameter + Parameter() + { + qiskit_param_ = std::shared_ptr(qk_param_zero(), qk_param_free); + } + + /// @brief Create a new Parameter with v + /// @param v floating point value to initialize the Parameter + Parameter(double v) + { + qiskit_param_ = std::shared_ptr(qk_param_from_double(v), qk_param_free); + } + + /// @brief Create a new Parameter with v + /// @param v floating point value to initialize the Parameter + Parameter(std::complex v) + { + qiskit_param_ = std::shared_ptr(qk_param_from_complex(qk_complex64_from_native(&v)), qk_param_free); + } + + /// @brief Create a new Parameter with v + /// @param v integer value to initialize the Parameter + Parameter(int_t v) + { + qiskit_param_ = std::shared_ptr(qk_param_from_double((double)v), qk_param_free); + } + + /// @brief Create a new symbol + /// @param name a name of symbol + Parameter(std::string name) + { + qiskit_param_ = std::shared_ptr(qk_param_new_symbol((char *)name.c_str()), qk_param_free); + } + + /// @brief Create a new Parameter from other Parameter + /// @param prm source Parameter + Parameter(const Parameter &prm) + { + // copying reference + qiskit_param_ = prm.qiskit_param_; + } + + /// @brief Create a new Parameter from QkParam + /// @param prm source Parameter + Parameter(qiskit_param* prm) + { + qiskit_param_ = std::shared_ptr(prm, qk_param_free); + } + + ~Parameter() + { + if (qiskit_param_) + qiskit_param_.reset(); + } + + /// @brief get string expression of the Parameter + /// @return a string expression of the Parameter + std::string as_str(void) + { + char* str = qk_param_str(qiskit_param_.get()); + std::string ret = str; + qk_str_free(str); + return ret; + } + + /// @brief get value of the Parameter expression + /// @param out a reference to the returned value + /// @return true if real number can be obtained + double as_real(void) + { + return qk_param_as_real(qiskit_param_.get()); + } + + /// @brief Negate a Parameter + /// @return a new Parameter (-this) + Parameter operator-() + { + Parameter ret; + qk_param_neg(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief add parameters + /// @param prm a Parameter to be added + /// @return a new Parameter (this + prm) + Parameter operator+(const Parameter &prm) + { + Parameter ret; + qk_param_add(ret.qiskit_param_.get(), qiskit_param_.get(), prm.qiskit_param_.get()); + return ret; + } + + /// @brief subtract parameters + /// @param prm a Parameter to be subtracted + /// @return a new Parameter (this - prm) + Parameter operator-(const Parameter &prm) + { + Parameter ret; + qk_param_sub(ret.qiskit_param_.get(), qiskit_param_.get(), prm.qiskit_param_.get()); + return ret; + } + + /// @brief multiply parameters + /// @param prm a Parameter to be multiplied + /// @return a new Parameter (this * prm) + Parameter operator*(const Parameter &prm) + { + Parameter ret; + qk_param_mul(ret.qiskit_param_.get(), qiskit_param_.get(), prm.qiskit_param_.get()); + return ret; + } + + /// @brief divide by a Parameter + /// @param prm a Parameter to be divided by + /// @return a new Parameter (this / prm) + Parameter operator/(const Parameter &prm) + { + Parameter ret; + qk_param_div(ret.qiskit_param_.get(), qiskit_param_.get(), prm.qiskit_param_.get()); + return ret; + } + + /// @brief add a value + /// @param prm a floating point value to be added + /// @return a new Parameter (this + prm) + Parameter operator+(const double prm) + { + Parameter ret; + Parameter rhs(prm); + qk_param_add(ret.qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return ret; + } + + /// @brief subtract a value + /// @param prm a floating point value to be subtracted + /// @return a new Parameter (this - prm) + Parameter operator-(const double prm) + { + Parameter ret; + Parameter rhs(prm); + qk_param_sub(ret.qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return ret; + } + + /// @brief multiply a value + /// @param prm a floating point value to be multiplied + /// @return a new Parameter (this * prm) + Parameter operator*(const double prm) + { + Parameter ret; + Parameter rhs(prm); + qk_param_mul(ret.qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return ret; + } + + /// @brief divide by a value + /// @param prm a floating point value to be divided by + /// @return a new Parameter (this / prm) + Parameter operator/(const double prm) + { + Parameter ret; + Parameter rhs(prm); + qk_param_div(ret.qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return ret; + } + + /// @brief calculate this Parameter raised to the power other Parameter + /// @param prm an exponent Parameter + /// @return a new Parameter (this ^ prm) + Parameter pow(const Parameter &prm) + { + Parameter ret; + qk_param_pow(ret.qiskit_param_.get(), qiskit_param_.get(), prm.qiskit_param_.get()); + return ret; + } + + /// @brief calculate this Parameter raised to the power a value + /// @param prm an exponent value + /// @return a new Parameter (this ^ prm) + Parameter pow(const double prm) + { + Parameter ret; + Parameter rhs(prm); + qk_param_pow(ret.qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return ret; + } + + /// @brief Copy parameter from other + /// @param prm source Parameter + Parameter &operator=(const Parameter &prm) + { + if (qiskit_param_) + qiskit_param_.reset(); + qiskit_param_ = std::shared_ptr(qk_param_copy(prm.qiskit_param_.get()), qk_param_free); + return *this; + } + + /// @brief add other Parameter to this Parameter + /// @param rhs a Parameter to be added + /// @return a reference to this + Parameter &operator+=(const Parameter &rhs) + { + qk_param_add(qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return *this; + } + + /// @brief add a value to this Parameter + /// @param rhs a value to be added + /// @return a reference to this + Parameter &operator+=(const double rhs) + { + qiskit_param* rval = qk_param_from_double(rhs); + qk_param_add(qiskit_param_.get(), qiskit_param_.get(), rval); + qk_param_free(rval); + return *this; + } + + /// @brief subtract this Parameter and other Parameter + /// @param rhs a Parameter to be subtracted + /// @return a reference to this + Parameter &operator-=(const Parameter &rhs) + { + qk_param_sub(qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return *this; + } + + /// @brief subtract this Parameter and a value + /// @param rhs a value to be subtracted + /// @return a reference to this + Parameter &operator-=(const double rhs) + { + qiskit_param* rval = qk_param_from_double(rhs); + qk_param_sub(qiskit_param_.get(), qiskit_param_.get(), rval); + qk_param_free(rval); + return *this; + } + + /// @brief multiply other Parameter to this Parameter + /// @param rhs a Parameter to be multiplied + /// @return a reference to this + Parameter &operator*=(const Parameter &rhs) + { + qk_param_mul(qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return *this; + } + + /// @brief multiply a value to this Parameter + /// @param rhs a value to be multiplied + /// @return a reference to this + Parameter &operator*=(const double rhs) + { + qiskit_param* rval = qk_param_from_double(rhs); + qk_param_mul(qiskit_param_.get(), qiskit_param_.get(), rval); + qk_param_free(rval); + return *this; + } + + /// @brief divide this Parameter by other Parameter + /// @param rhs a Parameter to be divided by + /// @return a reference to this + Parameter &operator/=(const Parameter &rhs) + { + qk_param_div(qiskit_param_.get(), qiskit_param_.get(), rhs.qiskit_param_.get()); + return *this; + } + + /// @brief divide this Parameter by a value + /// @param rhs a value to be divided by + /// @return a reference to this + Parameter &operator/=(const double rhs) + { + qiskit_param* rval = qk_param_from_double(rhs); + qk_param_div(qiskit_param_.get(), qiskit_param_.get(), rval); + qk_param_free(rval); + return *this; + } + + /// @brief compare 2 Parameters + /// @param rhs a Parameter to be compared + /// @return true if 2 Parameters are equal + bool operator==(const Parameter &rhs) const + { + return qk_param_equal(qiskit_param_.get(), rhs.qiskit_param_.get()); + } + + /// @brief compare 2 Parameters + /// @param rhs a Parameter to be compared + /// @return true if 2 Parameters are equal + bool operator!=(const Parameter &rhs) const + { + return !qk_param_equal(qiskit_param_.get(), rhs.qiskit_param_.get()); + } + + /// @brief calculate exponent of this Parameter + /// @return a new Parameter for the result + Parameter exp(void) + { + Parameter ret; + qk_param_exp(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate log of this Parameter + /// @return a new Parameter for the result + Parameter log(void) + { + Parameter ret; + qk_param_log(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate absolute of this Parameter + /// @return a new Parameter for the result + Parameter abs(void) + { + Parameter ret; + qk_param_abs(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate sine of this Parameter + /// @return a new Parameter for the result + Parameter sin(void) + { + Parameter ret; + qk_param_sin(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate cosine of this Parameter + /// @return a new Parameter for the result + Parameter cos(void) + { + Parameter ret; + qk_param_cos(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate tangent of this Parameter + /// @return a new Parameter for the result + Parameter tan(void) + { + Parameter ret; + qk_param_tan(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate arcsine of this Parameter + /// @return a new Parameter for the result + Parameter asin(void) + { + Parameter ret; + qk_param_asin(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate arccosine of this Parameter + /// @return a new Parameter for the result + Parameter acos(void) + { + Parameter ret; + qk_param_acos(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate arctangent of this Parameter + /// @return a new Parameter for the result + Parameter atan(void) + { + Parameter ret; + qk_param_atan(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate sign of this Parameter + /// @return a new Parameter for the result + Parameter sign(void) + { + Parameter ret; + qk_param_sign(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + + /// @brief calculate conjugate of this Parameter + /// @return a new Parameter for the result + Parameter conjugate(void) + { + Parameter ret; + qk_param_conjugate(ret.qiskit_param_.get(), qiskit_param_.get()); + return ret; + } + +#ifdef QISKIT_CAPI_HAS_SUBS + /// @brief bind a value to a symbol + /// @param symbol a symbol to be bound + /// @param value a value to be set + /// @return a new bound Parameter + Parameter bind(const Parameter& symbol, const double value); + + /// @brief bind values to symbols + /// @param symbols a list symbols to be bound + /// @param value a list of values to be set + /// @return a new bound Parameter + Parameter bind(const std::vector& symbols, const std::vector values); + + /// @brief substitute a symbol to other symbol + /// @param symbol a symbol to be bound + /// @param other a symbol to be set + /// @return a new substituted Parameter + Parameter subs(const Parameter& symbol, const Parameter& other); + + /// @brief substitute symbols to other symbols + /// @param symbols a list of symbols to be bound + /// @param others a list of symbols to be set + /// @return a new substituted Parameter + Parameter subs(const std::vector& symbols, const std::vector& others); +#endif }; -Parameter Parameter::operator-() -{ - Parameter ret(qk_parameter_neg(expr_)); - return ret; -} - -Parameter Parameter::operator+(Parameter& rhs) -{ - Parameter ret(qk_parameter_add(expr_, rhs.expr_)); - return ret; -} - -Parameter Parameter::operator-(Parameter& rhs) +#ifdef QISKIT_CAPI_HAS_SUBS +Parameter Parameter::bind(const Parameter& symbol, const double value) { - Parameter ret(qk_parameter_sub(expr_, rhs.expr_)); - return ret; -} + Parameter ret; -Parameter Parameter::operator*(Parameter& rhs) -{ - Parameter ret(qk_parameter_mul(expr_, rhs.expr_)); - return ret; + qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), &symbol.qiskit_param_.get(), &value, 1); + return ret; } -Parameter Parameter::operator/(Parameter& rhs) +Parameter Parameter::bind(const std::vector& symbols, const std::vector values) { - Parameter ret(qk_parameter_div(expr_, rhs.expr_)); - return ret; -} + size_t size = std::min(symbols.size(), values.size()); + Parameter ret; + std::vector list(size); + for (uint_t i = 0; i < size; i++) { + list[i] = symbols[i].qiskit_param_.get(); + } + + qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), list.data(), values.data(), size); + return ret; -Parameter Parameter::operator+(double prm) -{ - Parameter t(prm); - Parameter ret(qk_parameter_add(expr_, t.expr_)); - return ret; } -Parameter Parameter::operator-(double prm) +Parameter Parameter::subs(const Parameter& symbol, const Parameter& other) { - Parameter t(prm); - Parameter ret(qk_parameter_sub(expr_, t.expr_)); - return ret; -} + Parameter ret; -Parameter Parameter::operator*(double prm) -{ - Parameter t(prm); - Parameter ret(qk_parameter_mul(expr_, t.expr_)); - return ret; + qk_param_subs(ret.qiskit_param_.get(), qiskit_param_.get(), &symbol.qiskit_param_.get(), &other.qiskit_param_.get(), 1); + return ret; } -Parameter Parameter::operator/(double prm) +Parameter Parameter::subs(const std::vector& symbol, const std::vector& others) { - Parameter t(prm); - Parameter ret(qk_parameter_div(expr_, t.expr_)); - return ret; + size_t size = std::min(symbols.size(), values.size()); + Parameter ret; + std::vector slist(size); + std::vector olist(size); + for (uint_t i = 0; i < size; i++) { + slist[i] = symbols[i].qiskit_param_.get(); + olist[i] = others[i].qiskit_param_.get(); + } + + qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), slist.data(), olist.data(), size); + return ret; } -#else -class Parameter -{ - friend class QuantumCircuit; -protected: - rust_parameter* expr_ = nullptr; -public: - /// @brief Create a new Parameter - Parameter() - { - } - - /// @brief Create a new Parameter with v - /// @param (v) - Parameter(double v) - { - } - - /// @brief Create a new Parameter with v - /// @param (v) - Parameter(int_t v) - { - } - - /// @brief Create a new symbol - /// @param (expr) - Parameter(::std::string name) - { - } - - /// @brief Create a new Parameter as a copy of prm - /// @param (prm) copy source - Parameter(const Parameter& prm) - { - } - - /// @brief Create a new Parameter with expr - /// @param (expr) - Parameter(rust_parameter* expr) - { - expr_ = expr; - } - - ~Parameter() - { - } - - /* - std::string as_str(void) - { - } - */ - - - /* - Parameter operator-(); - - Parameter operator+(Parameter& prm); - Parameter operator-(Parameter& prm); - Parameter operator*(Parameter& prm); - Parameter operator/(Parameter& prm); - - Parameter operator+(double prm); - Parameter operator-(double prm); - Parameter operator*(double prm); - Parameter operator/(double prm); - */ - - Parameter& operator=(Parameter& prm) - { - return *this; - } - - Parameter& operator+=(Parameter& rhs) - { - return *this; - } - - Parameter& operator-=(Parameter& rhs) - { - return *this; - } - - Parameter& operator*=(Parameter& rhs) - { - return *this; - } - - Parameter& operator/=(Parameter& rhs) - { - return *this; - } - - Parameter& pow(Parameter& prm) - { - return *this; - } -}; - #endif @@ -368,6 +507,4 @@ class Parameter } // namespace circuit } // namespace Qiskit -#endif // __qiskitcpp_circuit_parameter_hpp__ - - +#endif // __qiskitcpp_circuit_parameter_hpp__ diff --git a/test/test_parameter.cpp b/test/test_parameter.cpp new file mode 100644 index 0000000..1989d53 --- /dev/null +++ b/test/test_parameter.cpp @@ -0,0 +1,350 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2025. +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +#include +#include +#include + +#include "circuit/parameter.hpp" +using namespace Qiskit; +using namespace Qiskit::circuit; + +extern "C" { + #include "common.h" +} + +/** + * Test creating a new free symbol and check the name. + */ +int test_parameter_new(void) { + auto p = Parameter("a"); + + if (p.as_str() != "a") { + std::cerr << "The parameter " << p.as_str() << " is not a" << std::endl; + return EqualityError; + } + return Ok; +} + +/** + * Test creating a new symbol from values. + */ +int test_parameter_new_values(void) { + auto real = Parameter(0.1); + if (real.as_str() != "0.1") { + std::cerr << "The parameter value " << real.as_str() << " is not 0.1" << std::endl; + return EqualityError; + } + return Ok; +} + +/** + * Test casting to real values. + */ +int test_parameter_to_real(void) { + auto x = Parameter("x"); + auto cmplx = Parameter(std::complex({1.0, 2.0})); + auto val = Parameter(10.0); + + double x_out = x.as_real(); + double cmplx_out = cmplx.as_real(); + double val_out = val.as_real(); + + if (!std::isnan(x_out) || std::isnan(cmplx_out) || std::isnan(val_out)) { + std::cerr << "Unexpected success/failure in as_real." << std::endl; + return EqualityError; + } + + if (std::abs(val_out - 10.0) > 1e-10) { + std::cerr << "Unexpected extracted value in as_real." << std::endl; + return EqualityError; + } + + // qk_param_as_real extracts the real part of a complex value + if (std::abs(cmplx_out - 1.0) > 1e-10) { + std::cerr << "Unexpected extracted value in as_real." << std::endl; + return EqualityError; + } + + return Ok; +} + +/** + * Test calling all binary operations and verify their string representation. + */ +int test_parameter_binary_ops(void) { + auto a = Parameter("a"); + auto b = Parameter("b"); + auto ret = Parameter(); + int result = Ok; + + // add + ret = a + b; + if (ret.as_str() != "a + b") { + std::cerr << "qk_param_add " << ret.as_str() << " is not a + b" << std::endl; + result = EqualityError; + goto cleanup; + } + + // sub + ret = a - b; + if (ret.as_str() != "a - b") { + std::cerr << "qk_param_sub " << ret.as_str() << " is not a - b" << std::endl; + result = EqualityError; + goto cleanup; + } + + // mul + ret = a * b; + if (ret.as_str() != "a*b") { + std::cerr << "qk_param_mul " << ret.as_str() << " is not a*b" << std::endl; + result = EqualityError; + goto cleanup; + } + + // div + ret = a / b; + if (ret.as_str() != "a/b") { + std::cerr << "qk_param_div " << ret.as_str() << " is not a/b" << std::endl; + result = EqualityError; + goto cleanup; + } + + // pow + ret = a.pow(b); + if (ret.as_str() != "a**b") { + std::cerr << "qk_param_pow " << ret.as_str() << " is not a**b" << std::endl; + result = EqualityError; + goto cleanup; + } +cleanup: + return result; +} + +/** + * Test calling all unary operations and verify their string representation. + */ +int test_parameter_unary_ops(void) { + auto a = Parameter("a"); + auto b = Parameter("b"); + auto c = a + b; + auto ret = Parameter(); + int result = Ok; + + // sin + ret = c.sin(); + if (ret.as_str() != "sin(a + b)") { + std::cerr << "qk_param_sin " << ret.as_str() << " is not sin(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // cos + ret = c.cos(); + if (ret.as_str() != "cos(a + b)") { + std::cerr << "qk_param_cos " << ret.as_str() << " is not cos(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // tan + ret = c.tan(); + if (ret.as_str() != "tan(a + b)") { + std::cerr << "qk_param_tan " << ret.as_str() << " is not tan(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // asin + ret = c.asin(); + if (ret.as_str() != "asin(a + b)") { + std::cerr << "qk_param_asin " << ret.as_str() << " is not asin(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // acos + ret = c.acos(); + if (ret.as_str() != "acos(a + b)") { + std::cerr << "qk_param_acos " << ret.as_str() << " is not acos(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // atan + ret = c.atan(); + if (ret.as_str() != "atan(a + b)") { + std::cerr << "qk_param_atan " << ret.as_str() << " is not atan(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // log + ret = c.log(); + if (ret.as_str() != "log(a + b)") { + std::cerr << "qk_param_log " << ret.as_str() << " is not log(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // exp + ret = c.exp(); + if (ret.as_str() != "exp(a + b)") { + std::cerr << "qk_param_exp " << ret.as_str() << " is not exp(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // abs + ret = c.abs(); + if (ret.as_str() != "abs(a + b)") { + std::cerr << "qk_param_abs " << ret.as_str() << " is not abs(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // sign + ret = c.sign(); + if (ret.as_str() != "sign(a + b)") { + std::cerr << "qk_param_sign " << ret.as_str() << " is not sign(a + b)" << std::endl; + result = EqualityError; + goto cleanup; + } + + // neg + ret = -c; + if (ret.as_str() != "-a - b") { + std::cerr << "qk_param_neg " << ret.as_str() << " is not -a - b" << std::endl; + result = EqualityError; + goto cleanup; + } + + // conj + ret = c.conjugate(); + if (ret.as_str() != "conj(a) + conj(b)") { + std::cerr << "qk_param_conj " << ret.as_str() << " is not conj(a) + conj(b)" << std::endl; + result = EqualityError; + goto cleanup; + } + +cleanup: + return result; +} + +/** + * Test operations with free parameters and fixed values. + */ +int test_parameter_with_value(void) { + auto a = Parameter("a"); + auto v = Parameter(2.5); + auto ret = Parameter(); + int result = Ok; + + // add + ret = a + v; + if (ret.as_str() != "2.5 + a") { + std::cerr << "qk_param_add " << ret.as_str() << " is not 2.5 + a" << std::endl; + result = EqualityError; + } + return result; +} + +/** + * Test equality. + */ +int test_parameter_equal(void) { + Parameter x = Parameter("x"); + Parameter x_imposter = Parameter("x"); + Parameter y = Parameter("y"); + Parameter z = Parameter("z"); + Parameter val = Parameter(0.2); + Parameter sum1 = Parameter(); + Parameter sum1_clone = Parameter(); + Parameter sum2 = Parameter(); + Parameter mul = Parameter(); + + int result = Ok; + + sum1 = x + y; + sum1_clone = x + y; + sum2 = x + z; + mul = x * val; + + if (x != x) { + std::cerr << "Symbol not equal to itself" << std::endl; + result = EqualityError; + goto cleanup; + } + + if (x == x_imposter) { + std::cerr << "Symbol equal a new instance with the same name" << std::endl; + result = EqualityError; + goto cleanup; + } + + if (x == mul) { + std::cerr << "Symbol equals but they differ by a coefficient" << std::endl; + result = EqualityError; + goto cleanup; + } + + if (sum1 != sum1_clone) { + std::cerr << "Expression not equal to the same expression." << std::endl; + result = EqualityError; + goto cleanup; + } + + if (sum1 == sum2) { + std::cerr << "Expression equal to a different sum." << std::endl; + result = EqualityError; + goto cleanup; + } +cleanup: + return result; +} + +/** + * Test copy. + */ +int test_parameter_copy(void) { + Parameter x = Parameter("x"); + Parameter y = Parameter("y"); + Parameter sum = Parameter(); + + int result = Ok; + + sum = x + y; + Parameter copy = sum; + if (sum != copy) { + std::cerr << "Copy not equal to original"; + result = EqualityError; + } + + return result; +} + +extern "C" int test_parameter(void) { + int num_failed = 0; + num_failed += RUN_TEST(test_parameter_new); + num_failed += RUN_TEST(test_parameter_new_values); + num_failed += RUN_TEST(test_parameter_to_real); + num_failed += RUN_TEST(test_parameter_equal); + num_failed += RUN_TEST(test_parameter_copy); + num_failed += RUN_TEST(test_parameter_binary_ops); + num_failed += RUN_TEST(test_parameter_unary_ops); + num_failed += RUN_TEST(test_parameter_with_value); + + std::cerr << "=== Number of failed subtests: " << num_failed << std::endl; + + return num_failed; +} + From 2219ec47c241071627fa3b5b3e67fd2e27444b91 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 6 Oct 2025 17:45:41 +0900 Subject: [PATCH 2/2] fix test --- test/test_parameter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_parameter.cpp b/test/test_parameter.cpp index 1989d53..0de8040 100644 --- a/test/test_parameter.cpp +++ b/test/test_parameter.cpp @@ -52,7 +52,7 @@ int test_parameter_new_values(void) { */ int test_parameter_to_real(void) { auto x = Parameter("x"); - auto cmplx = Parameter(std::complex({1.0, 2.0})); + auto cmplx = Parameter(std::complex(1.0, 2.0)); auto val = Parameter(10.0); double x_out = x.as_real();