Skip to content

Commit 55f79c0

Browse files
marwafarwsttiger
andauthored
Add uccgsd ansatz (#319)
In this PR: 1- We added UCCGSD in operator_pools for algorithm such as ADAPT-VQE 2- We added UCCGSD in stateprep for algorithm such as VQE --------- Signed-off-by: marwafar <[email protected]> Signed-off-by: Scott Thornton <[email protected]> Co-authored-by: Scott Thornton <[email protected]> Co-authored-by: Scott Thornton <[email protected]>
1 parent a61cc8d commit 55f79c0

File tree

13 files changed

+1156
-0
lines changed

13 files changed

+1156
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/****************************************************************-*- C++ -*-****
2+
* Copyright (c) 2025 NVIDIA Corporation & Affiliates. *
3+
* All rights reserved. *
4+
* *
5+
* This source code and the accompanying materials are made available under *
6+
* the terms of the Apache License 2.0 which accompanies this distribution. *
7+
******************************************************************************/
8+
9+
#pragma once
10+
11+
#include "../operator_pool.h"
12+
13+
namespace cudaq::solvers {
14+
15+
/// @brief UCCGSD operator pool is a class which generates a pool
16+
/// of UCCGSD operators for use in quantum algorithms, like Adapt-VQE.
17+
/// @details This class extends the operator_pool interface
18+
/// therefore inherits the extension_point template, allowing for
19+
/// runtime extensibility.
20+
class uccgsd : public operator_pool {
21+
22+
public:
23+
/// @brief Generate a vector of spin operators based on the provided
24+
/// configuration.
25+
/// @details The UCCGSD operator pool is generated with an imaginary factor
26+
/// 'i' in the coefficients of the operators, which simplifies the use for
27+
/// running Adapt-VQE.
28+
/// @param config A heterogeneous map containing configuration parameters for
29+
/// operator generation.
30+
/// @return A vector of cudaq::spin_op objects representing the generated
31+
/// operator pool.
32+
std::vector<cudaq::spin_op>
33+
generate(const heterogeneous_map &config) const override;
34+
35+
/// @brief Call to macro for defining the creator function for an extension
36+
/// @details This function is used by the extension point mechanism to create
37+
/// instances of the uccgsd class.
38+
CUDAQ_EXTENSION_CREATOR_FUNCTION(operator_pool, uccgsd)
39+
};
40+
/// @brief Register the uccgsd extension type with the CUDA-Q framework
41+
CUDAQ_REGISTER_TYPE(uccgsd)
42+
43+
} // namespace cudaq::solvers
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/****************************************************************-*- C++ -*-****
2+
* Copyright (c) 2025 NVIDIA Corporation & Affiliates. *
3+
* All rights reserved. *
4+
* *
5+
* This source code and the accompanying materials are made available under *
6+
* the terms of the Apache License 2.0 which accompanies this distribution. *
7+
******************************************************************************/
8+
9+
#pragma once
10+
11+
#include "cudaq/spin_op.h"
12+
#include <utility>
13+
#include <vector>
14+
15+
namespace cudaq::solvers {
16+
17+
/// @brief Generate all unique single excitation index pairs (p, q) with p > q
18+
/// @param numQubits Number of qubits in the system
19+
/// @return Vector of (p, q) pairs representing single excitations
20+
std::vector<std::pair<std::size_t, std::size_t>>
21+
generate_uccgsd_singles(std::size_t numQubits);
22+
23+
/// @brief Generate all unique double excitation index pairs
24+
/// @details For 4 indices a < b < c < d, generates all 3 unique pairings:
25+
/// (a,b)-(c,d), (a,c)-(b,d), (a,d)-(b,c)
26+
/// Each pair is normalized so that within each pair, first > second,
27+
/// and pairs are ordered.
28+
/// @param numQubits Number of qubits in the system
29+
/// @return Vector of ((p,q), (r,s)) pairs where p>q, r>s, representing double
30+
/// excitations
31+
std::vector<std::pair<std::pair<std::size_t, std::size_t>,
32+
std::pair<std::size_t, std::size_t>>>
33+
generate_uccgsd_doubles(std::size_t numQubits);
34+
35+
/// @brief Add a UCCGSD single excitation operator to the operator pool
36+
/// @details Generates the operator: 0.5 * (Y_q * Z_parity * X_p - X_q *
37+
/// Z_parity * Y_p)
38+
/// where Z_parity is the product of Z operators between q and p
39+
/// @param ops Vector to append the operator to
40+
/// @param p Higher qubit index (p > q)
41+
/// @param q Lower qubit index (p > q)
42+
void addUCCGSDSingleExcitation(std::vector<cudaq::spin_op> &ops, std::size_t p,
43+
std::size_t q);
44+
45+
/// @brief Add a UCCGSD double excitation operator to the operator pool
46+
/// @details Generates the generalized double excitation operator with 8 terms
47+
/// @param ops Vector to append the operator to
48+
/// @param p First qubit index (p > q)
49+
/// @param q Second qubit index (p > q)
50+
/// @param r Third qubit index (r > s)
51+
/// @param s Fourth qubit index (r > s)
52+
void addUCCGSDDoubleExcitation(std::vector<cudaq::spin_op> &ops, std::size_t p,
53+
std::size_t q, std::size_t r, std::size_t s);
54+
55+
} // namespace cudaq::solvers
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/****************************************************************-*- C++ -*-****
2+
* Copyright (c) 2025 NVIDIA Corporation & Affiliates. *
3+
* All rights reserved. *
4+
* *
5+
* This source code and the accompanying materials are made available under *
6+
* the terms of the Apache License 2.0 which accompanies this distribution. *
7+
******************************************************************************/
8+
#pragma once
9+
10+
#include "cudaq.h"
11+
#include <utility>
12+
#include <vector>
13+
14+
namespace cudaq::solvers::stateprep {
15+
16+
/// @brief Generate UCCGSD operator pool (Python-style unique singles/doubles)
17+
/// and extract Pauli words and coefficients
18+
/// @param norbitals Number of spin orbitals (qubits)
19+
/// @param only_singles If true, only single excitations
20+
/// @param only_doubles If true, only double excitations
21+
/// @return Pair of lists: [Pauli words grouped by excitation], [coefficients
22+
/// grouped by excitation]
23+
std::pair<std::vector<std::vector<cudaq::pauli_word>>,
24+
std::vector<std::vector<double>>>
25+
get_uccgsd_pauli_lists(std::size_t norbitals, bool only_singles = false,
26+
bool only_doubles = false);
27+
28+
/// \pure_device_kernel
29+
///
30+
/// @brief Apply UCCGSD ansatz to a qubit register using grouped Pauli words and
31+
/// coefficients
32+
/// @param qubits Qubit register
33+
/// @param thetas Vector of rotation angles (one per excitation group)
34+
/// @param pauliWordsList Pauli words grouped by excitation
35+
/// @param coefficientsList Coefficients grouped by excitation
36+
__qpu__ void
37+
uccgsd(cudaq::qview<> qubits, const std::vector<double> &thetas,
38+
const std::vector<std::vector<cudaq::pauli_word>> &pauliWordsList,
39+
const std::vector<std::vector<double>> &coefficientsList);
40+
41+
} // namespace cudaq::solvers::stateprep

libs/solvers/lib/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ add_library(cudaq-solvers SHARED
2323
operators/operator_pools/spin_complement_gsd.cpp
2424
operators/operator_pools/uccsd_operator_pool.cpp
2525
operators/operator_pools/qaoa_operator_pool.cpp
26+
operators/operator_pools/uccgsd_operator_pool.cpp
27+
operators/uccgsd_excitation_utils.cpp
2628
version.cpp
2729
)
2830

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 NVIDIA Corporation & Affiliates. *
3+
* All rights reserved. *
4+
* *
5+
* This source code and the accompanying materials are made available under *
6+
* the terms of the Apache License 2.0 which accompanies this distribution. *
7+
******************************************************************************/
8+
#include "cudaq/solvers/operators/operator_pools/uccgsd_operator_pool.h"
9+
#include "cudaq/solvers/operators/uccgsd_excitation_utils.h"
10+
11+
using namespace cudaqx;
12+
13+
namespace cudaq::solvers {
14+
15+
std::vector<cudaq::spin_op>
16+
uccgsd::generate(const heterogeneous_map &config) const {
17+
18+
auto numOrbitals = config.get<std::size_t>({"num-orbitals", "num_orbitals"});
19+
auto numQubits = 2 * numOrbitals;
20+
if (numOrbitals == 0)
21+
throw std::invalid_argument("num-orbitals must be > 0");
22+
23+
// For UCCGSD, we do not use alpha/beta/mixed excitations, but generate all
24+
// singles and doubles
25+
std::vector<cudaq::spin_op> ops;
26+
27+
// Generate all single excitations using shared utility
28+
auto singles = generate_uccgsd_singles(numQubits);
29+
for (const auto &[p, q] : singles) {
30+
addUCCGSDSingleExcitation(ops, p, q);
31+
}
32+
33+
// Generate all unique unordered double excitations using shared utility
34+
auto doubles = generate_uccgsd_doubles(numQubits);
35+
for (const auto &[pq, rs] : doubles) {
36+
addUCCGSDDoubleExcitation(ops, pq.first, pq.second, rs.first, rs.second);
37+
}
38+
39+
return ops;
40+
}
41+
42+
} // namespace cudaq::solvers
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 NVIDIA Corporation & Affiliates. *
3+
* All rights reserved. *
4+
* *
5+
* This source code and the accompanying materials are made available under *
6+
* the terms of the Apache License 2.0 which accompanies this distribution. *
7+
******************************************************************************/
8+
9+
#include "cudaq/solvers/operators/uccgsd_excitation_utils.h"
10+
#include <algorithm>
11+
#include <array>
12+
#include <set>
13+
14+
namespace cudaq::solvers {
15+
16+
std::vector<std::pair<std::size_t, std::size_t>>
17+
generate_uccgsd_singles(std::size_t numQubits) {
18+
std::vector<std::pair<std::size_t, std::size_t>> singles;
19+
singles.reserve(numQubits * (numQubits - 1) / 2);
20+
for (std::size_t p = 1; p < numQubits; ++p)
21+
for (std::size_t q = 0; q < p; ++q)
22+
singles.emplace_back(p, q);
23+
return singles;
24+
}
25+
26+
std::vector<std::pair<std::pair<std::size_t, std::size_t>,
27+
std::pair<std::size_t, std::size_t>>>
28+
generate_uccgsd_doubles(std::size_t numQubits) {
29+
std::set<std::pair<std::pair<std::size_t, std::size_t>,
30+
std::pair<std::size_t, std::size_t>>>
31+
doubles;
32+
33+
// Iterate over all combinations of 4 distinct qubits
34+
for (std::size_t a = 0; a < numQubits; ++a)
35+
for (std::size_t b = a + 1; b < numQubits; ++b)
36+
for (std::size_t c = b + 1; c < numQubits; ++c)
37+
for (std::size_t d = c + 1; d < numQubits; ++d) {
38+
std::array<std::size_t, 4> arr = {a, b, c, d};
39+
40+
// Generate all 3 unique pairings of the 4 indices
41+
std::vector<std::pair<std::pair<std::size_t, std::size_t>,
42+
std::pair<std::size_t, std::size_t>>>
43+
pairings = {{{arr[0], arr[1]}, {arr[2], arr[3]}},
44+
{{arr[0], arr[2]}, {arr[1], arr[3]}},
45+
{{arr[0], arr[3]}, {arr[1], arr[2]}}};
46+
47+
// Normalize and deduplicate each pairing
48+
for (auto &pairing : pairings) {
49+
auto p1 = pairing.first, p2 = pairing.second;
50+
51+
// Ensure within each pair: first > second
52+
if (p1.first < p1.second)
53+
std::swap(p1.first, p1.second);
54+
if (p2.first < p2.second)
55+
std::swap(p2.first, p2.second);
56+
57+
// Order the two pairs
58+
auto sorted_pairing = std::minmax(p1, p2);
59+
doubles.insert({sorted_pairing.first, sorted_pairing.second});
60+
}
61+
}
62+
63+
return std::vector<std::pair<std::pair<std::size_t, std::size_t>,
64+
std::pair<std::size_t, std::size_t>>>(
65+
doubles.begin(), doubles.end());
66+
}
67+
68+
void addUCCGSDSingleExcitation(std::vector<cudaq::spin_op> &ops, std::size_t p,
69+
std::size_t q) {
70+
if (p > q) {
71+
// Compute parity string (Z operators between q and p)
72+
cudaq::spin_op_term parity;
73+
for (std::size_t i = q + 1; i < p; ++i)
74+
parity *= cudaq::spin::z(i);
75+
76+
std::complex<double> c = {0.5, 0.0};
77+
78+
// Single excitation: Y_q * Z_parity * X_p - X_q * Z_parity * Y_p
79+
ops.emplace_back(c * cudaq::spin::y(q) * parity * cudaq::spin::x(p) -
80+
c * cudaq::spin::x(q) * parity * cudaq::spin::y(p));
81+
}
82+
}
83+
84+
void addUCCGSDDoubleExcitation(std::vector<cudaq::spin_op> &ops, std::size_t p,
85+
std::size_t q, std::size_t r, std::size_t s) {
86+
if (p > q && r > s) {
87+
// Compute parity strings
88+
cudaq::spin_op_term parity_a, parity_b;
89+
for (std::size_t i = q + 1; i < p; ++i)
90+
parity_a *= cudaq::spin::z(i);
91+
for (std::size_t i = s + 1; i < r; ++i)
92+
parity_b *= cudaq::spin::z(i);
93+
94+
std::complex<double> c = {0.125, 0.0};
95+
96+
// Build the 8-term double excitation operator
97+
cudaq::spin_op temp_op;
98+
99+
// Positive terms
100+
temp_op = c * cudaq::spin::y(s) * parity_b * cudaq::spin::x(r) *
101+
cudaq::spin::x(q) * parity_a * cudaq::spin::x(p);
102+
temp_op += c * cudaq::spin::x(s) * parity_b * cudaq::spin::y(r) *
103+
cudaq::spin::x(q) * parity_a * cudaq::spin::x(p);
104+
temp_op += c * cudaq::spin::y(s) * parity_b * cudaq::spin::y(r) *
105+
cudaq::spin::y(q) * parity_a * cudaq::spin::x(p);
106+
temp_op += c * cudaq::spin::y(s) * parity_b * cudaq::spin::y(r) *
107+
cudaq::spin::x(q) * parity_a * cudaq::spin::y(p);
108+
109+
// Negative terms
110+
temp_op -= c * cudaq::spin::x(s) * parity_b * cudaq::spin::x(r) *
111+
cudaq::spin::y(q) * parity_a * cudaq::spin::x(p);
112+
temp_op -= c * cudaq::spin::x(s) * parity_b * cudaq::spin::x(r) *
113+
cudaq::spin::x(q) * parity_a * cudaq::spin::y(p);
114+
temp_op -= c * cudaq::spin::x(s) * parity_b * cudaq::spin::y(r) *
115+
cudaq::spin::y(q) * parity_a * cudaq::spin::y(p);
116+
temp_op -= c * cudaq::spin::y(s) * parity_b * cudaq::spin::x(r) *
117+
cudaq::spin::y(q) * parity_a * cudaq::spin::y(p);
118+
119+
ops.emplace_back(temp_op);
120+
}
121+
}
122+
123+
} // namespace cudaq::solvers

libs/solvers/lib/stateprep/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
cudaqx_add_device_code(cudaq-solvers
1010
SOURCES
1111
uccsd.cpp
12+
uccgsd.cpp
1213
)

0 commit comments

Comments
 (0)