Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a property flag in kraus_op to identify whether it is a 'scaled' unitary matrix #2085

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions runtime/common/NoiseModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,35 @@ noise_model::get_channels(const std::string &quantumOp,
return iter->second;
}

template <typename T>
bool isScaledUnitaryImpl(const std::vector<std::complex<T>> &mat) {
typedef Eigen::Matrix<std::complex<T>, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>
RowMajorMatTy;
const int dim = std::log2(mat.size());
Eigen::Map<const RowMajorMatTy> kMat(mat.data(), dim, dim);
if (kMat.isZero())
return true;
// Check that (K_dag * K) is a scaled identity matrix
// i.e., the K matrix is a scaled unitary.
auto kdK = kMat.adjoint() * kMat;
if (!kdK.isDiagonal())
return false;
// First element
std::complex<T> val = kdK(0, 0);
constexpr T eps = 1e-12;
if (std::abs(val) > eps) {
auto scaledKdK = (std::complex<T>{1.0} / val) * kdK;
return scaledKdK.isIdentity();
}
return false;
}

bool kraus_op::isScaledUnitary(const std::vector<std::complex<double>> &mat) {
return isScaledUnitaryImpl(mat);
}

bool kraus_op::isScaledUnitary(const std::vector<std::complex<float>> &mat) {
return isScaledUnitaryImpl(mat);
}
} // namespace cudaq
11 changes: 11 additions & 0 deletions runtime/common/NoiseModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ struct kraus_op {
/// NOTE we currently assume nRows == nCols
std::size_t nCols = 0;

/// @brief If true, the Kraus operator is a unitary operator times a constant.
bool unitary = false;

/// @brief Copy constructor
kraus_op(const kraus_op &) = default;

Expand All @@ -47,6 +50,7 @@ struct kraus_op {

nRows = (std::size_t)std::round(sqrtNEl);
nCols = nRows;
unitary = isScaledUnitary(data);
}

/// @brief Constructor, initialize from initializer_list
Expand All @@ -61,11 +65,13 @@ struct kraus_op {

nRows = (std::size_t)std::round(sqrtNEl);
nCols = nRows;
unitary = isScaledUnitary(data);
}

/// @brief Set this kraus_op equal to the other
kraus_op &operator=(const kraus_op &other) {
data = other.data;
unitary = other.unitary;
return *this;
}

Expand All @@ -78,6 +84,11 @@ struct kraus_op {
newData[i * nRows + j] = std::conj(data[j * nCols + i]);
return kraus_op(newData);
}

private:
/// @brief Return true if the input matrix is a scaled unitary matrix.
static bool isScaledUnitary(const std::vector<std::complex<double>> &mat);
static bool isScaledUnitary(const std::vector<std::complex<float>> &mat);
};

void validateCompletenessRelation_fp32(const std::vector<kraus_op> &ops);
Expand Down
32 changes: 32 additions & 0 deletions unittests/integration/noise_tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,36 @@ CUDAQ_TEST(NoiseTest, checkPhaseFlipType) {
cudaq::unset_noise(); // clear for subsequent tests
}

CUDAQ_TEST(NoiseTest, checkNoiseModelUtils) {
{
cudaq::depolarization_channel depol(0.1);
for (const auto &op : depol.get_ops())
EXPECT_TRUE(op.unitary);
}
{
cudaq::depolarization_channel depol(1.0);
for (const auto &op : depol.get_ops())
EXPECT_TRUE(op.unitary);
}
{
cudaq::bit_flip_channel bf(0.1);
for (const auto &op : bf.get_ops())
EXPECT_TRUE(op.unitary);
}
{
cudaq::phase_flip_channel pf(0.1);
for (const auto &op : pf.get_ops())
EXPECT_TRUE(op.unitary);
}
{
// Amplitude damping has a non-unitary Kraus matrix.
cudaq::amplitude_damping_channel ad(0.1);
const auto krausOps = ad.get_ops();
const bool hasNonUnitaryOp =
std::any_of(krausOps.begin(), krausOps.end(),
[](const auto &op) { return !op.unitary; });
EXPECT_TRUE(hasNonUnitaryOp);
}
}

#endif
Loading