Skip to content

Commit

Permalink
grid synth (#65)
Browse files Browse the repository at this point in the history
* refactor qasm_synth options

* fix qasm_synth options order

* add qasm_synth to staq_wrapper [not working]

* delete temp files

* Update setup.py

* fix gmp linking issues

* Update setup.py

* Update mat_vec_2x2.hpp

* Update staq_wrapper.cpp

* build grid synth if gmp is detected

* add gmp link args

* simplification

* refactor; create GridSynthesizer

* remove pessimizing moves

* finish pystaq wrapping grid_synth

* add tests for grid_synth and qasm_synth

* rename angle_cache

* Changed the name of the synthesis function to not conflict with other
conventions

* removed --theta required

* Added error msg if no angle provided

* rename get_op_str in pystaq

* formatting

---------

Co-authored-by: Kevin Guo <[email protected]>
Co-authored-by: James Lambert <[email protected]>
  • Loading branch information
3 people authored Oct 6, 2023
1 parent aeae045 commit 74689f9
Show file tree
Hide file tree
Showing 18 changed files with 8,135 additions and 409 deletions.
8 changes: 0 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ add_compile_definitions(STAQ_VERSION_STR="${STAQ_VERSION_STR}")
#### staq root directory
add_compile_definitions(PROJECT_ROOT_DIR="${PROJECT_SOURCE_DIR}")

#### grid synth
option(BUILD_GRID_SYNTH "Builds staq_grid_synth, requires GMP" OFF)
if (${BUILD_GRID_SYNTH})
message(STATUS "Builds staq_grid_synth - ON")
else ()
message(STATUS "Builds staq_grid_synth - OFF")
endif ()

#### Force clang to use libc++
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
Expand Down
2 changes: 1 addition & 1 deletion examples/rz_test1.qasm
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ include "qelib1.inc";

qreg q[2];

rz(2*pi/4) q;
rx(2*pi/4) q[0];
6 changes: 3 additions & 3 deletions examples/rz_test2.qasm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ include "qelib1.inc";

qreg q[2];

rz(0.3) q[0];
rx(3/10) q[0];
ry(3*100/10/100) q[1];
rz(-0.3) q[0];
rz(-3/10) q[0];
rz(9*-27/100*10/81) q[0];
37 changes: 24 additions & 13 deletions include/grid_synth/exact_synthesis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,38 @@ namespace grid_synth {
// 1/(sqrt(omega)).
inline str_t check_common_cases(real_t theta, const real_t& eps) {

while (theta > real_t("2"))
theta = theta - real_t("2");
// Normalize theta to the range [0,4)
while (theta >= real_t("4"))
theta = theta - real_t("4");
while (theta < 0)
theta = theta + real_t("2");
theta = theta + real_t("4");

// Deal with the case where theta is in [2,4)
str_t ret = "";
if (theta >= real_t("2")) {
theta = theta - real_t("2");
ret = "WWWW";
}

if (abs(theta - real_t("0.25")) < eps) {
return "T w";
// Check multiples of 1/4 in [0,2)
if (abs(theta) < eps) {
if (ret != "")
return ret;
return "I";
} else if (abs(theta - real_t("0.25")) < eps) {
return "Tw" + ret;
} else if (abs(theta - real_t("0.5")) < eps) {
return "S W W W W W W W";
return "SWWWWWWW" + ret;
} else if (abs(theta - real_t("0.75")) < eps) {
return "S T W W W W W W W w";
return "STWWWWWWWw" + ret;
} else if (abs(theta - real_t("1")) < eps) {
return "S S W W W W W W";
return "SSWWWWWW" + ret;
} else if (abs(theta - real_t("1.25")) < eps) {
return "S S T W W W W W W w";
return "SSTWWWWWWw" + ret;
} else if (abs(theta - real_t("1.5")) < eps) {
return "S S S W W W W W";
return "SSSWWWWW" + ret;
} else if (abs(theta - real_t("1.75")) < eps) {
return "S S S T W W W W W w";
} else if (abs(theta - real_t("2")) < eps) {
return "W W W W";
return "SSSTWWWWWw" + ret;
} else {
return "";
}
Expand Down
232 changes: 232 additions & 0 deletions include/grid_synth/grid_synth.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*
* This file is part of staq.
*
* Copyright (c) 2019 - 2023 softwareQ Inc. All rights reserved.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef GRID_SYNTH_GRID_SYNTH_HPP_
#define GRID_SYNTH_GRID_SYNTH_HPP_

#include "exact_synthesis.hpp"
#include "matrix.hpp"
#include "rz_approximation.hpp"
#include "s3_table.hpp"
#include "types.hpp"

namespace staq {
namespace grid_synth {

/* Converts a GMP float to a string suitable for hashing. */
static str_t to_string(const mpf_class& x) {
mp_exp_t exp;
// Use base 32 to get a shorter string; truncate the string
// to keep only the significant figures.
int sig_len = mpf_get_default_prec() / 5;
if (x < 0)
++sig_len; // account for leading minus sign
str_t s = x.get_str(exp, 32).substr(0, sig_len);
return s + str_t(" ") + std::to_string(exp);
}

/* Options passed when constructing a GridSynthesizer. */
struct GridSynthOptions {
long int prec; // Precision in base 10 as a positive integer (10^p)
int factor_effort = MAX_ATTEMPTS_POLLARD_RHO;
bool check = false;
bool details = false;
bool verbose = false;
bool timer = false;
};

class GridSynthesizer {
private:
std::unordered_map<str_t, str_t> angle_cache_;
const domega_matrix_table_t S3_TABLE;

real_t eps_;
bool check_;
bool details_;
bool verbose_;
bool timer_;

long long duration_;
bool valid_;

/* Construct GridSynthesizer objects using the make_synthesizer
* factory function.
*/
GridSynthesizer(domega_matrix_table_t s3_table, real_t eps, bool check,
bool details, bool verbose, bool timer)
: angle_cache_(), S3_TABLE(std::move(s3_table)), eps_(std::move(eps)),
check_(check), details_(details), verbose_(verbose), timer_(timer),
duration_(0), valid_(true) {}

public:
~GridSynthesizer() {}

double get_duration() const { return static_cast<double>(duration_) / 1e6; }
bool is_valid() const { return valid_; }

/*! \brief Find RZ-approximation for an angle. */
str_t get_op_str(const real_t& angle) {
if (verbose_)
std::cerr << "Checking common cases..."
<< "\n";
str_t common_case = check_common_cases(angle / gmpf::gmp_pi(), eps_);
if (common_case != "") {
if (details_)
std::cerr
<< "Angle is multiple of pi/4, answer is known exactly"
<< '\n';
if (check_)
std::cerr << "Check flag = " << 1 << '\n';
return common_case;
}
if (verbose_)
std::cerr << "No common cases found" << '\n';

RzApproximation rz_approx;
str_t op_str;
if (timer_) {
// If timer is enabled, don't check cache or produce debug
// output. Just synthesize the angle.
auto start = std::chrono::steady_clock::now();
rz_approx = find_fast_rz_approximation(
real_t(angle) * PI / real_t("-2"), eps_);
op_str = synthesize(rz_approx.matrix(), S3_TABLE);
auto end = std::chrono::steady_clock::now();
duration_ += std::chrono::duration_cast<std::chrono::microseconds>(
end - start)
.count();
} else {
str_t angle_str = to_string(angle);
if (verbose_)
std::cerr << "Checking local cache..." << '\n';
if (details_)
std::cerr << "Angle has string representation " << angle_str
<< '\n';
if (angle_cache_.count(angle_str)) {
if (verbose_ || details_)
std::cerr << "Angle is found in local cache" << '\n';
return angle_cache_[angle_str];
}

if (verbose_)
std::cerr
<< "Running grid_synth to find new rz approximation..."
<< '\n';
RzApproximation rz_approx =
find_fast_rz_approximation(angle / real_t("-2.0"), eps_);
if (!rz_approx.solution_found()) {
std::cerr << "No approximation found for RzApproximation. "
"Try changing factorization effort."
<< '\n';
exit(EXIT_FAILURE);
}
if (verbose_)
std::cerr << "Approximation found. Synthesizing..." << '\n';
op_str = synthesize(rz_approx.matrix(), S3_TABLE);

if (verbose_)
std::cerr << "Synthesis complete." << '\n';
bool good = (rz_approx.matrix() ==
domega_matrix_from_str(full_simplify_str(op_str)));
valid_ = valid_ && good;
valid_ = valid_ && (rz_approx.error() < eps_);

if (check_)
std::cerr << "Check flag = " << good << '\n';
if (details_) {
real_t scale = gmpf::pow(SQRT2, rz_approx.matrix().k());
std::cerr << "angle = " << std::scientific << angle << '\n';
std::cerr << rz_approx.matrix();
std::cerr << "u decimal value = "
<< "("
<< rz_approx.matrix().u().decimal().real() / scale
<< ","
<< rz_approx.matrix().u().decimal().imag() / scale
<< ")" << '\n';
std::cerr << "t decimal value = "
<< "("
<< rz_approx.matrix().t().decimal().real() / scale
<< ","
<< rz_approx.matrix().t().decimal().imag() / scale
<< ")" << '\n';
std::cerr << "error = " << rz_approx.error() << '\n';
str_t simplified = full_simplify_str(op_str);
std::string::difference_type n =
count(simplified.begin(), simplified.end(), 'T');
std::cerr << "T count = " << n << '\n';
std::cerr << "----" << '\n' << std::fixed;
}
angle_cache_[angle_str] = op_str;
}
return op_str;
}

friend GridSynthesizer make_synthesizer(const GridSynthOptions& opt);
};

/*! \brief Initializes a GridSynthesizer object. */
inline GridSynthesizer make_synthesizer(const GridSynthOptions& opt) {
domega_matrix_table_t s3_table = load_s3_table();

real_t eps = gmpf::pow(real_t(10), -opt.prec);
MP_CONSTS = initialize_constants(opt.prec);
MAX_ATTEMPTS_POLLARD_RHO = opt.factor_effort;

if (opt.verbose) {
std::cerr << "Runtime Parameters" << '\n';
std::cerr << "------------------" << '\n';
std::cerr << std::setw(3 * COLW) << std::left
<< "TOL (Tolerance for float equality) " << std::setw(1)
<< ": " << std::setw(3 * COLW) << std::left << std::scientific
<< TOL << '\n';
std::cerr << std::setw(3 * COLW) << std::left
<< "KMIN (Minimum scaling exponent) " << std::setw(1) << ": "
<< std::setw(3 * COLW) << std::left << std::fixed << KMIN
<< '\n';
std::cerr << std::setw(2 * COLW) << std::left
<< "KMAX (Maximum scaling exponent) " << std::setw(1) << ": "
<< std::setw(3 * COLW) << std::left << std::fixed << KMAX
<< '\n';
std::cerr << std::setw(3 * COLW) << std::left
<< "MAX_ATTEMPTS_POLLARD_RHO (How hard we try to factor) "
<< std::setw(1) << ": " << std::setw(3 * COLW) << std::left
<< MAX_ATTEMPTS_POLLARD_RHO << '\n';
std::cerr << std::setw(3 * COLW) << std::left
<< "MAX_ITERATIONS_FERMAT_TEST (How hard we try to check "
"primality) "
<< std::setw(1) << ": " << std::setw(3 * COLW) << std::left
<< MAX_ITERATIONS_FERMAT_TEST << '\n';
}
std::cerr << std::scientific;

return GridSynthesizer(std::move(s3_table), std::move(eps), opt.check,
opt.details, opt.verbose, opt.timer);
}

} // namespace grid_synth
} // namespace staq

#endif // GRID_SYNTH_GRID_SYNTH_HPP_
2 changes: 1 addition & 1 deletion include/grid_synth/mat_vec_2x2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace grid_synth {
using real_t = mpf_class;

template <typename T = real_t>
struct row_vec2_t;
class row_vec2_t;

// 2x1 column vector
template <typename T = real_t>
Expand Down
4 changes: 4 additions & 0 deletions include/grid_synth/matrix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ inline str_t full_simplify_str(str_t str) {
return curr_str;
}

// ========================================================================= //
// Note: These functions are no longer used by grid_synth.
// ========================================================================= //

// Generate the set of all unitary matrices with SDE less than three
inline domega_matrix_table_t generate_s3_table() {
using namespace std;
Expand Down
Loading

0 comments on commit 74689f9

Please sign in to comment.