29 #define LAPACK_ROW_MAJOR 101 30 #define LAPACK_COL_MAJOR 102 40 extern "C" int LAPACKE_zgesvd(
int matrix_order,
char jobu,
char jobvt,
44 int ldvt,
double* superb );
49 extern "C" int LAPACKE_cgesvd(
int matrix_order,
char jobu,
char jobvt,
53 int ldvt,
float* superb );
137 double trace_real = 0.0;
139 if ( trace_offset == 0 ) {
143 trace_real += matrix[idx*matrix.
stride + idx].real;
151 trace_real += matrix[(idx+trace_offset)*matrix.
stride + idx].real;
158 double cost_function = (1.0 - trace_real/
matrix_size);
160 return cost_function;
167 double trace_real = 0.0;
169 if ( trace_offset == 0 ) {
171 trace_real += matrix[idx*matrix.
stride + idx].real;
176 trace_real += matrix[(idx+trace_offset)*matrix.
stride + idx].real;
204 double trace_real = 0.0;
206 if ( trace_offset == 0 ) {
207 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
209 int qbit_error_mask = 1 << qbit_idx;
211 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
214 int row_idx = col_idx ^ qbit_error_mask;
216 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
224 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
226 int qbit_error_mask = 1 << qbit_idx;
228 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
231 int row_idx = (col_idx + trace_offset) ^ qbit_error_mask;
233 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
246 ret[1] = cost_function;
261 double trace_real = 0.0;
263 if ( trace_offset == 0 ) {
264 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
265 int qbit_error_mask = 1 << qbit_idx;
266 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
267 int row_idx = col_idx ^ qbit_error_mask;
268 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
273 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
274 int qbit_error_mask = 1 << qbit_idx;
275 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
276 int row_idx = (col_idx + trace_offset) ^ qbit_error_mask;
277 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
282 ret[1] =
static_cast<float>(trace_real/
matrix_size);
309 double trace_real = 0.0;
311 if ( trace_offset == 0 ) {
312 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
314 int qbit_error_mask = 1 << qbit_idx;
316 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
319 int row_idx = col_idx ^ qbit_error_mask;
321 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
329 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
331 int qbit_error_mask = 1 << qbit_idx;
333 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
336 int row_idx = (col_idx+trace_offset) ^ qbit_error_mask;
338 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
347 ret[1] = cost_function;
356 if ( trace_offset == 0 ) {
357 for (
int qbit_idx=0; qbit_idx<qbit_num-1; qbit_idx++) {
358 for (
int qbit_idx2=qbit_idx+1; qbit_idx2<
qbit_num; qbit_idx2++) {
360 int qbit_error_mask = (1 << qbit_idx) + (1 << qbit_idx2);
362 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
365 int row_idx = col_idx ^ qbit_error_mask;
367 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
375 for (
int qbit_idx=0; qbit_idx<qbit_num-1; qbit_idx++) {
376 for (
int qbit_idx2=qbit_idx+1; qbit_idx2<
qbit_num; qbit_idx2++) {
378 int qbit_error_mask = (1 << qbit_idx) + (1 << qbit_idx2);
380 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
383 int row_idx = (col_idx+trace_offset) ^ qbit_error_mask;
385 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
396 ret[2] = cost_function2;
410 ret[0] = correction1[0];
411 ret[1] = correction1[1];
414 double trace_real = 0.0;
416 if ( trace_offset == 0 ) {
417 for (
int qbit_idx=0; qbit_idx<qbit_num-1; qbit_idx++) {
418 for (
int qbit_idx2=qbit_idx+1; qbit_idx2<
qbit_num; qbit_idx2++) {
419 int qbit_error_mask = (1 << qbit_idx) + (1 << qbit_idx2);
420 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
421 int row_idx = col_idx ^ qbit_error_mask;
422 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
428 for (
int qbit_idx=0; qbit_idx<qbit_num-1; qbit_idx++) {
429 for (
int qbit_idx2=qbit_idx+1; qbit_idx2<
qbit_num; qbit_idx2++) {
430 int qbit_error_mask = (1 << qbit_idx) + (1 << qbit_idx2);
431 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
432 int row_idx = (col_idx+trace_offset) ^ qbit_error_mask;
433 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
439 ret[2] =
static_cast<float>(trace_real/
matrix_size);
446 for (
int rowidx = 0; rowidx < matrix.
rows; rowidx++) {
447 int baseidx = rowidx*matrix.
stride;
448 for (
int colidx = 0; colidx < matrix.
cols; colidx++) {
449 if (rowidx == colidx) {
450 ret += (matrix[baseidx+colidx].real - 1.0) * (matrix[baseidx+colidx].real - 1.0) + matrix[baseidx+colidx].imag * matrix[baseidx+colidx].imag;
452 ret += matrix[baseidx+colidx].real * matrix[baseidx+colidx].real + matrix[baseidx+colidx].imag * matrix[baseidx+colidx].imag;
462 for (
int rowidx = 0; rowidx < matrix.
rows; rowidx++) {
463 int baseidx = rowidx*matrix.
stride;
464 for (
int colidx = 0; colidx < matrix.
cols; colidx++) {
465 if (rowidx == colidx) {
466 ret[baseidx+colidx].real = 2 * (matrix[baseidx+colidx].real - 1.0);
467 ret[baseidx+colidx].imag = 2 * matrix[baseidx+colidx].imag;
469 ret[baseidx+colidx].real = 2 * matrix[baseidx+colidx].real;
470 ret[baseidx+colidx].imag = 2 * matrix[baseidx+colidx].imag;
485 double trace_real=0.0;
486 double trace_imag=0.0;
491 trace_real += matrix[idx*matrix.
stride + idx].real;
492 trace_imag += matrix[idx*matrix.
stride + idx].imag;
495 ret.
real = trace_real;
496 ret.
imag = trace_imag;
504 double trace_real=0.0;
505 double trace_imag=0.0;
509 trace_real += matrix[idx*matrix.
stride + idx].real;
510 trace_imag += matrix[idx*matrix.
stride + idx].imag;
512 ret.
real = trace_real;
513 ret.
imag = trace_imag;
526 double d = 1.0/matrix.
cols;
527 double cost_function = 0.0;
531 return cost_function;
536 double d = 1.0/matrix.
cols;
543 double d = matrix.
cols;
544 double cost_function = 0.0;
548 return cost_function;
553 double d = matrix.
cols;
572 double trace_real = 0.0;
573 double trace_imag = 0.0;
575 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
577 int qbit_error_mask = 1 << qbit_idx;
579 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
582 int row_idx = col_idx ^ qbit_error_mask;
584 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
585 trace_imag += matrix[row_idx*matrix.
stride + col_idx].imag;
589 ret[0].real = trace_tmp.
real;
590 ret[0].imag = trace_tmp.
imag;
591 ret[1].real = trace_real;
592 ret[1].imag = trace_imag;
612 double trace_real = 0.0;
613 double trace_imag = 0.0;
615 for (
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++) {
617 int qbit_error_mask = 1 << qbit_idx;
619 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
622 int row_idx = col_idx ^ qbit_error_mask;
624 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
625 trace_imag += matrix[row_idx*matrix.
stride + col_idx].imag;
630 ret[1].real = trace_real;
631 ret[1].imag = trace_imag;
640 for (
int qbit_idx=0; qbit_idx<qbit_num-1; qbit_idx++) {
641 for (
int qbit_idx2=qbit_idx+1; qbit_idx2<
qbit_num; qbit_idx2++) {
643 int qbit_error_mask = (1 << qbit_idx) + (1 << qbit_idx2);
645 for (
int col_idx=0; col_idx<
matrix_size; col_idx++) {
648 int row_idx = col_idx ^ qbit_error_mask;
650 trace_real += matrix[row_idx*matrix.
stride + col_idx].real;
651 trace_imag += matrix[row_idx*matrix.
stride + col_idx].imag;
658 ret[2].real = trace_real;
659 ret[2].imag = trace_imag;
660 ret[0].real = trace_tmp.
real;
661 ret[0].imag = trace_tmp.
imag;
690 for (
int row_idx = r.begin(); row_idx != r.end(); row_idx++) {
692 if ( row_idx > matrix_size ) {
693 std::string err(
"Error: row idx should be less than the number of roes in the matrix.");
702 double partial_cost_function = 0;
704 int idx_max = idx_offset + row_idx;
705 for (
int idx=idx_offset; idx<idx_max; idx++ ) {
709 int diag_element_idx = row_idx*matrix_size + row_idx;
710 double diag_real =
data[diag_element_idx].
real - corner_element.
real;
711 double diag_imag =
data[diag_element_idx].
imag - corner_element.
imag;
712 partial_cost_function = partial_cost_function + diag_real*diag_real + diag_imag*diag_imag;
715 idx_offset = idx_max + 1;
717 for (
int idx=idx_offset; idx<idx_max; idx++ ) {
722 cost_function_priv = cost_function_priv + partial_cost_function;
737 r = (v > 0xFFFF) << 4; v >>= r;
738 shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
739 shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
740 shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
746 static inline uint32_t
lg_up(uint32_t
x) {
747 return x <= 1 ? 0 :
lg_down(x - 1) + 1;
753 for (
int p : pos) { y |= ((x >> p) & 1) <<
k; ++
k; }
758 static inline size_t mat_idx(
int row,
int col,
int nrows,
int ncols) {
760 return (
size_t)row + (size_t)col * (
size_t)nrows;
762 return (
size_t)row * (size_t)ncols + (
size_t)col;
772 template<
class MatrixT,
class ComplexT>
774 const std::vector<int>& A,
775 int& m_rows,
int& m_cols)
777 std::vector<int> A_sorted = A;
778 std::sort(A_sorted.begin(), A_sorted.end());
780 B.reserve(n - (
int)A_sorted.size());
781 for (
int q = 0; q <
n; ++q)
782 if (!std::binary_search(A_sorted.begin(), A_sorted.end(), q)) B.push_back(q);
784 const int dA = 1 << (
int)A_sorted.size();
785 const int dB = 1 << (n - (
int)A_sorted.size());
786 const int N = 1 <<
n;
790 std::vector<ComplexT> M;
791 M.resize((
size_t)m_rows * (
size_t)m_cols);
794 for (
int in = 0; in <
N; ++in) {
797 for (
int out = 0; out <
N; ++out) {
800 const int r = a + ap;
801 const int c = b + bp;
802 const auto& val = U[(size_t)in + (
size_t)out * (size_t)N];
803 M[
mat_idx(r, c, m_rows, m_cols)] = val;
809 template<
class MatrixT,
class ComplexT>
811 const std::vector<ComplexT> & Umat,
812 const std::vector<ComplexT> & VTmat,
813 int n,
const std::vector<int>& A,
int rank=-1)
815 std::vector<int> A_sorted = A;
816 std::sort(A_sorted.begin(), A_sorted.end());
818 B.reserve(n - (
int)A_sorted.size());
819 for (
int q = 0; q <
n; ++q)
820 if (!std::binary_search(A_sorted.begin(), A_sorted.end(), q)) B.push_back(q);
822 const int dA = 1 << (
int)A_sorted.size();
823 const int dB = 1 << (n - (
int)A_sorted.size());
824 const int N = 1 <<
n;
826 int m_rows = dA * dA;
827 int m_cols = dB * dB;
829 int k = std::min(m_rows, m_cols);
830 int tot_dyadic =
static_cast<int>(G.size());
833 for (
int in = 0; in <
N; ++in) {
836 for (
int out = 0; out <
N; ++out) {
839 const int r = a + ap;
840 const int c = b + bp;
841 double val_real = 0.0;
842 double val_imag = 0.0;
845 for (
int i = 0; i < tot_dyadic; i++) {
848 ComplexT u_val = Umat[
mat_idx(r, idx, m_rows, k)];
849 ComplexT vt_val = VTmat[
mat_idx(idx, c, k, m_cols)];
852 double re_prod = u_val.real * vt_val.real - u_val.imag * vt_val.imag;
853 double im_prod = u_val.real * vt_val.imag + u_val.imag * vt_val.real;
855 val_real += G[i] * re_prod;
856 val_imag += G[i] * im_prod;
860 const int diag_len = std::min<int>((
int)G.size(),
k);
861 for (
int j = 0; j < diag_len; ++j) {
862 const ComplexT u_val = Umat[
mat_idx(r, j, m_rows, k)];
863 const ComplexT vt_val = VTmat[
mat_idx(j, c, k, m_cols)];
865 const double re_prod = u_val.real * vt_val.real - u_val.imag * vt_val.imag;
866 const double im_prod = u_val.real * vt_val.imag + u_val.imag * vt_val.real;
868 val_real += G[j] * re_prod;
869 val_imag += G[j] * im_prod;
872 accum[(size_t)in + (
size_t)out * (size_t)N].
real +=
static_cast<decltype(accum[0].
real)
>(val_real);
873 accum[(size_t)in + (
size_t)out * (size_t)N].imag +=
static_cast<decltype(accum[0].imag)
>(val_imag);
881 return LAPACKE_zgesdd(lapack_layout, jobz, m, n, a, lda, s, u, ldu, vt, ldvt);
887 return LAPACKE_cgesdd(lapack_layout, jobz, m, n, a, lda, s, u, ldu, vt, ldvt);
891 static int lapack_gesvd_dispatch(
int lapack_layout,
char jobu,
char jobvt,
int m,
int n,
QGD_Complex16* a,
894 return LAPACKE_zgesvd(lapack_layout, jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, superb);
897 static int lapack_gesvd_dispatch(
int lapack_layout,
char jobu,
char jobvt,
int m,
int n,
QGD_Complex8* a,
900 return LAPACKE_cgesvd(lapack_layout, jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, superb);
904 template<
class ComplexT,
class RealT>
905 static std::vector<double>
osr(std::vector<ComplexT>& A,
int m_rows,
int m_cols,
double Fnorm)
907 int k = std::min(m_rows, m_cols);
908 std::vector<RealT>
S(k);
911 const int lda = m_rows;
912 const int ldu = m_rows;
916 const int lda = m_cols;
918 const int ldvt = m_cols;
929 std::vector<RealT> superb(std::max(1, k - 1));
931 int info = lapack_gesvd_dispatch(lapack_layout,
941 throw std::runtime_error(
"gesvd failed, info=" + std::to_string(info));
943 std::vector<double> normalized;
944 normalized.reserve(S.size());
945 for (RealT s : S) normalized.push_back(static_cast<double>(s)/Fnorm);
954 for (
double s : S)
if (s > S[0]*tol) ++rnk;
960 std::vector<int>& current,
961 std::vector<std::vector<int>>& out)
963 if ((
int)current.size() == r) {
964 out.push_back(current);
967 for (
int i = start; i <
n; ++i) {
968 current.push_back(i);
977 std::vector<std::vector<int>> cuts;
978 if (n <= 1)
return cuts;
980 for (
int r = 1; r <= n / 2; ++r) {
981 std::vector<std::vector<int>> combs;
982 std::vector<int> current;
985 for (
auto&
S : combs) {
989 std::vector<int> comp;
990 for (
int q = 0; q <
n; ++q)
991 if (std::find(
S.begin(),
S.end(), q) ==
S.end())
1003 double m = *std::max_element(Lc.begin(), Lc.end());
1005 for (
double v : Lc) sum += std::exp((v - m)/tau);
1006 return tau * std::log(sum) + m;
1012 const int start_i =
static_cast<int>(
start);
1015 for (
int k = static_cast<int>(S.size()) - 1;
k >= start_i; --
k) {
1017 acc += w * val * val;
1028 if (start >= S.size())
return 0.0;
1031 for (
size_t i = start; i < S.size(); ++i) {
1038 if (cuts_S.empty())
return 0.0;
1041 for (
const auto&
S : cuts_S) {
1044 return tot /
static_cast<double>(cuts_S.size());
1048 int rank,
double tau = 1e-2) {
1050 throw std::invalid_argument(
"cuts_softmax_rank_cost: tau must be > 0");
1052 if (cuts_S.empty())
return 0.0;
1054 std::vector<double> Lc;
1055 Lc.reserve(cuts_S.size());
1056 for (
const auto&
S : cuts_S) {
1063 const size_t n = S.size();
1066 std::vector<double> grad(n, 0.0);
1067 if (start >= n)
return grad;
1069 const double invF = 1.0 / Fnorm;
1070 for (
size_t i = start; i <
n; ++i) {
1071 grad[i] = 2.0 * S[i] * invF;
1077 const std::vector<std::vector<double>>& cuts_S,
1081 const size_t C = cuts_S.size();
1082 if (C == 0)
return {};
1084 const double scale = 1.0 /
static_cast<double>(C);
1086 std::vector<std::vector<double>>
G;
1089 for (
const auto&
S : cuts_S) {
1091 for (
double& v : g) v *= scale;
1092 G.emplace_back(std::move(g));
1098 const std::vector<std::vector<double>>& cuts_S,
1103 const size_t C = cuts_S.size();
1104 if (C == 0)
return {};
1106 throw std::invalid_argument(
"cuts_softmax_rank_grad: tau must be > 0");
1110 std::vector<double> Lc(C, 0.0);
1111 for (
size_t c = 0; c < C; ++c) {
1116 const double m = *std::max_element(Lc.begin(), Lc.end());
1117 std::vector<double> w(C, 0.0);
1119 for (
size_t c = 0; c < C; ++c) {
1120 w[c] = std::exp((Lc[c] - m) / tau);
1123 if (Z <= 0.0) Z = 1.0;
1124 for (
size_t c = 0; c < C; ++c) {
1129 std::vector<std::vector<double>>
G;
1132 for (
size_t c = 0; c < C; ++c) {
1134 for (
double& v : g) v *= w[c];
1135 G.emplace_back(std::move(g));
1141 double tail_loss(
const std::vector<double>&
S,
int max_dyadic,
double rho=0.1,
double tol=1e-4) {
1142 int tot_dyadic =
static_cast<int>(
lg_up(static_cast<uint32_t>(S.size())));
1145 for (
int k = max_dyadic-1;
k >= 0; --
k) {
1146 if (
k < tot_dyadic) {
1147 double val = S[
static_cast<size_t>(1) <<
k] - S[0] * tol;
1148 acc += w * val * val;
1155 double avg_tail_loss(
const std::vector<std::vector<double>>& cuts_S,
double rho=0.1) {
1157 int max_dyadic =
static_cast<int>(
lg_up(static_cast<uint32_t>(std::max_element(
1158 cuts_S.begin(), cuts_S.end(),
1159 [](
const std::vector<double>& a,
const std::vector<double>& b) {
1160 return a.size() < b.size();
1162 for (
const auto&
S : cuts_S)
1164 return tot /
static_cast<double>(cuts_S.size());
1169 double rho=0.1,
double tau=1e-2)
1171 if (tau <= 0.0)
throw std::invalid_argument(
"cuts_softmax_tail_cost: tau must be > 0");
1172 std::vector<double> Lc; Lc.reserve(cuts_S.size());
1173 int max_dyadic =
static_cast<int>(
lg_up(static_cast<uint32_t>(std::max_element(
1174 cuts_S.begin(), cuts_S.end(),
1175 [](
const std::vector<double>& a,
const std::vector<double>& b) {
1176 return a.size() < b.size();
1178 for (
const auto&
S : cuts_S)
1184 std::vector<double>
tail_loss_grad_diag(
const std::vector<double>&
S,
int max_dyadic,
double Fnorm,
double rho=0.1,
double tol=1e-4) {
1185 const size_t n = S.size();
1188 int tot_dyadic =
static_cast<int>(
lg_up(static_cast<uint32_t>(n)));
1189 std::vector<double> grad(tot_dyadic, 0.0);
1191 for (
int k = max_dyadic-1;
k >= 0; --
k) {
1192 if (
k < tot_dyadic) {
1194 grad[
k] = 2.0 * w * S[idx] * (1.0-tol) / Fnorm;
1201 std::vector<std::vector<double>>
cuts_avg_tail_grad(
const std::vector<std::vector<double>>& cuts_S,
double Fnorm,
double rho=0.1) {
1202 const size_t C = cuts_S.size();
1203 int max_dyadic =
static_cast<int>(
lg_up(static_cast<uint32_t>(std::max_element(
1204 cuts_S.begin(), cuts_S.end(),
1205 [](
const std::vector<double>& a,
const std::vector<double>& b) {
1206 return a.size() < b.size();
1208 std::vector<std::vector<double>> Lc;
1210 for (
size_t c = 0; c < C; ++c) {
1220 const std::vector<std::vector<double>>& cuts_S,
double Fnorm,
1221 double rho=0.1,
double tau=1e-2)
1223 const size_t C = cuts_S.size();
1224 if (C == 0)
return {};
1225 int max_dyadic =
static_cast<int>(
lg_up(static_cast<uint32_t>(std::max_element(
1226 cuts_S.begin(), cuts_S.end(),
1227 [](
const std::vector<double>& a,
const std::vector<double>& b) {
1228 return a.size() < b.size();
1232 std::vector<double> Lc(C, 0.0);
1233 for (
size_t c = 0; c < C; ++c)
1234 Lc[c] =
tail_loss(cuts_S[c], max_dyadic, rho);
1237 const double m = *std::max_element(Lc.begin(), Lc.end());
1238 std::vector<double> w(C, 0.0);
1240 for (
size_t c = 0; c < C; ++c) { w[c] = std::exp((Lc[c] - m)/tau); Z += w[c]; }
1241 for (
size_t c = 0; c < C; ++c) w[c] /= (Z > 0.0 ? Z : 1.0);
1244 std::vector<std::vector<double>>
G; G.reserve(C);
1245 for (
size_t c = 0; c < C; ++c) {
1247 for (
double& v : gc) v *= w[c];
1255 const std::vector<int>& A_qubits,
1256 double Fnorm,
double tol)
1260 std::vector<QGD_Complex16> M = build_osr_matrix<Matrix, QGD_Complex16>(U,
n, A_qubits, mr, mc);
1261 std::vector<double>
S = osr<QGD_Complex16, double>(M, mr, mc, Fnorm);
1263 return std::pair<int, double>(min_cnot,
1270 const std::vector<int>& A_qubits,
1271 double Fnorm,
double tol)
1275 std::vector<QGD_Complex8> M = build_osr_matrix<Matrix_float, QGD_Complex8>(U,
n, A_qubits, mr, mc);
1276 std::vector<double>
S = osr<QGD_Complex8, float>(M, mr, mc, Fnorm);
1278 return std::pair<int, double>(min_cnot,
1283 template<
class MatrixT,
class ComplexT,
class RealT>
1287 const auto& cuts = use_cuts.size() == 0 ?
unique_cuts(qbit_num) : use_cuts;
1288 double Fnorm = std::sqrt(matrix.rows);
1289 std::vector<std::vector<double>> allS;
1290 allS.reserve(cuts.size());
1291 for (
const auto& cut : cuts) {
1293 std::vector<ComplexT> M = build_osr_matrix<MatrixT, ComplexT>(
matrix,
qbit_num, cut, mr, mc);
1294 std::vector<double>
S = osr<ComplexT, RealT>(M, mr, mc, Fnorm);
1295 allS.emplace_back(S);
1309 return get_osr_entanglement_test_impl<Matrix, QGD_Complex16, double>(
matrix, use_cuts,
rank, use_softmax);
1313 return get_osr_entanglement_test_impl<Matrix_float, QGD_Complex8, float>(
matrix, use_cuts,
rank, use_softmax);
1316 template<
class ComplexT>
1325 std::vector<ComplexT> u,
1326 std::vector<ComplexT> vt)
1327 : singulars(
std::move(s)),
1328 left_factors(
std::move(u)),
1329 right_factors(
std::move(vt)) {}
1333 template<
class MatrixT,
class ComplexT,
class RealT>
1337 const std::vector<int>& A,
1339 int &m_rows,
int &m_cols
1343 std::vector<ComplexT> M = build_osr_matrix<MatrixT, ComplexT>(U, q, A, m_rows, m_cols);
1345 const int k = std::min(m_rows, m_cols);
1348 std::vector<RealT>
S(k);
1349 std::vector<ComplexT> Umat((
size_t)m_rows * (
size_t)k);
1350 std::vector<ComplexT> VTmat((
size_t)k * (
size_t)m_cols);
1356 const int lda = m_rows;
1357 const int ldu = m_rows;
1361 const int lda = m_cols;
1363 const int ldvt = m_cols;
1376 std::vector<RealT> superb(std::max(1, k - 1));
1377 int info = lapack_gesvd_dispatch(
1389 throw std::runtime_error(
"gesvd failed, info=" + std::to_string(info));
1391 std::vector<double> S_normalized;
1392 S_normalized.reserve(S.size());
1393 for (RealT s : S) S_normalized.push_back(static_cast<double>(s)/Fnorm);
1398 template<
class MatrixT,
class ComplexT,
class RealT>
1401 const auto& cuts = use_cuts.size() == 0 ?
unique_cuts(qbit_num) : use_cuts;
1402 double Fnorm = std::sqrt(matrix.rows);
1403 MatrixT deriv(matrix.rows, matrix.cols);
1404 std::fill(deriv.data, deriv.data+deriv.size(), ComplexT{0.0, 0.0});
1406 std::vector<OSRTriplet<ComplexT>> triplets;
1407 std::vector<std::vector<double>> allS;
1408 triplets.reserve(cuts.size());
1409 for (
const auto& cut : cuts) {
1411 int m_rows = 0, m_cols = 0;
1413 allS.emplace_back(std::move(triplet.
singulars));
1417 triplets.emplace_back(std::move(stored));
1426 for (
int i = 0; i < (
int)cuts.size(); ++i) {
1427 triplets[i].singulars = std::move(allS[i]);
1429 for (
int i = 0; i < (
int)cuts.size(); ++i) {
1431 accumulate_grad_for_cut<MatrixT, ComplexT>(deriv,
1442 return get_deriv_osr_entanglement_impl<Matrix, QGD_Complex16, double>(
matrix, use_cuts,
rank, use_softmax);
1446 return get_deriv_osr_entanglement_impl<Matrix_float, QGD_Complex8, float>(
matrix, use_cuts,
rank, use_softmax);
1454 for (
int r = 0; r < A.
rows; ++r) {
1456 for (
int c = 0; c < A.
cols; ++c) {
1457 acc += A[offs + c].real * B[offs + c].real + A[offs + c].imag * B[offs + c].imag;
1466 for (
int r = 0; r < A.
rows; ++r) {
1468 for (
int c = 0; c < A.
cols; ++c) {
1469 acc += A[offs + c].real * B[offs + c].real + A[offs + c].imag * B[offs + c].imag;
static std::vector< ComplexT > build_osr_matrix(const MatrixT &U, int n, const std::vector< int > &A, int &m_rows, int &m_cols)
double get_hilbert_schmidt_test(Matrix &matrix)
Call co calculate the cost function of the optimization process according to https://arxiv.org/pdf/2210.09191.pdf.
double avg_loss_for_rank(const std::vector< std::vector< double >> &cuts_S, int rank)
double cuts_softmax_tail_cost(const std::vector< std::vector< double >> &cuts_S, double rho=0.1, double tau=1e-2)
Class to store single-precision real arrays and properties.
int LAPACKE_zgesdd(int matrix_order, char jobz, int m, int n, QGD_Complex16 *a, int lda, double *s, QGD_Complex16 *u, int ldu, QGD_Complex16 *vt, int ldvt)
QGD_Complex16 * data
Pointer to the data stored in the matrix.
std::vector< ComplexT > left_factors
static int lapack_gesdd_dispatch(int lapack_layout, char jobz, int m, int n, QGD_Complex16 *a, int lda, double *s, QGD_Complex16 *u, int ldu, QGD_Complex16 *vt, int ldvt)
static int extract_bits(int x, const std::vector< int > &pos)
std::vector< double > singulars
static uint32_t lg_up(uint32_t x)
int stride
The column stride of the array. (The array elements in one row are a_0, a_1, ... a_{cols-1}, 0, 0, 0, 0. The number of zeros is stride-cols)
double get_infidelity(Matrix &matrix)
Call to calculate infidelity.
Structure type representing single-precision complex numbers.
std::vector< std::vector< double > > cuts_avg_rank_grad(const std::vector< std::vector< double >> &cuts_S, int rank, double Fnorm)
std::vector< ComplexT > right_factors
std::vector< std::vector< double > > cuts_softmax_tail_grad(const std::vector< std::vector< double >> &cuts_S, double Fnorm, double rho=0.1, double tau=1e-2)
std::vector< double > tail_loss_grad_diag(const std::vector< double > &S, int max_dyadic, double Fnorm, double rho=0.1, double tol=1e-4)
OSRTriplet(std::vector< double > s, std::vector< ComplexT > u, std::vector< ComplexT > vt)
static MatrixT get_deriv_osr_entanglement_impl(MatrixT &matrix, std::vector< std::vector< int >> &use_cuts, int rank, bool use_softmax)
static int numerical_rank_osr(std::vector< double > S, double tol)
scalar * get_data() const
Call to get the pointer to the stored data.
std::vector< std::vector< int > > unique_cuts(int n)
static void combinations_recursive(int n, int r, int start, std::vector< int > ¤t, std::vector< std::vector< int >> &out)
int rows
The number of rows.
int cols
The number of columns.
Matrix matrix
Array stroing the matrix.
static size_t mat_idx(int row, int col, int nrows, int ncols)
Custom types for the SQUANDER package.
functor_cost_fnc(Matrix matrix_in, tbb::combinable< double > *partial_cost_functions_in)
Constructor of the class.
std::vector< std::vector< double > > cuts_avg_tail_grad(const std::vector< std::vector< double >> &cuts_S, double Fnorm, double rho=0.1)
double tail_loss(const std::vector< double > &S, int max_dyadic, double rho=0.1, double tol=1e-4)
double logsumexp_smoothmax(const std::vector< double > &Lc, double tau=1e-2)
static uint32_t lg_down(uint32_t v)
void operator()(tbb::blocked_range< int > r) const
Operator to calculate the partial cost function derived from the row of the matrix labeled by row_idx...
double cuts_softmax_rank_cost(const std::vector< std::vector< double >> &cuts_S, int rank, double tau=1e-2)
Matrix get_trace_with_correction2(Matrix &matrix, int qbit_num)
Call co calculate the Hilbert Schmidt testof the optimization process, and the first correction to th...
Matrix_real get_cost_function_with_correction(const Matrix &matrix, int qbit_num, int trace_offset)
Call co calculate the cost function of the optimization process, and the first correction to the cost...
Structure type representing complex numbers in the SQUANDER package.
Double-precision complex matrix (float64).
double get_cost_function_sum_of_squares(Matrix &matrix)
double get_cost_function(const Matrix &matrix, int trace_offset)
Call co calculate the cost function during the final optimization process.
std::vector< std::vector< double > > cuts_softmax_rank_grad(const std::vector< std::vector< double >> &cuts_S, int rank, double Fnorm, double tau=1e-2)
Single-precision complex matrix (float32).
Matrix get_deriv_sum_of_squares(Matrix &matrix)
static double get_osr_entanglement_test_impl(MatrixT &matrix, std::vector< std::vector< int >> &use_cuts, int rank, bool use_softmax)
double avg_tail_loss(const std::vector< std::vector< double >> &cuts_S, double rho=0.1)
std::vector< double > loss_for_rank_grad_diag(const std::vector< double > &S, int rank, double Fnorm)
double weighted_loss_for_rank(const std::vector< double > &S, int rank, double rho=0.1, double tol=1e-4)
Header file for the paralleized calculation of the cost function of the final optimization problem (s...
static void accumulate_grad_for_cut(MatrixT &accum, const std::vector< double > &G, const std::vector< ComplexT > &Umat, const std::vector< ComplexT > &VTmat, int n, const std::vector< int > &A, int rank=-1)
static OSRTriplet< ComplexT > top_k_triplet_for_cut(const MatrixT &U, int q, const std::vector< int > &A, double Fnorm, int &m_rows, int &m_cols)
double loss_for_rank(const std::vector< double > &S, int rank)
double real
the real part of a complex number
Matrix get_trace_with_correction(Matrix &matrix, int qbit_num)
Call co calculate the Hilbert Schmidt testof the optimization process, and the first correction to th...
int LAPACKE_cgesdd(int matrix_order, char jobz, int m, int n, QGD_Complex8 *a, int lda, float *s, QGD_Complex8 *u, int ldu, QGD_Complex8 *vt, int ldvt)
int LAPACKE_cgesvd(int matrix_order, char jobu, char jobvt, int m, int n, QGD_Complex8 *a, int lda, float *s, QGD_Complex8 *u, int ldu, QGD_Complex8 *vt, int ldvt, float *superb)
int LAPACKE_zgesvd(int matrix_order, char jobu, char jobvt, int m, int n, QGD_Complex16 *a, int lda, double *s, QGD_Complex16 *u, int ldu, QGD_Complex16 *vt, int ldvt, double *superb)
std::pair< int, double > operator_schmidt_rank(const Matrix &U, int n, const std::vector< int > &A_qubits, double Fnorm, double tol)
static std::vector< double > osr(std::vector< ComplexT > &A, int m_rows, int m_cols, double Fnorm)
double real_trace_conj_dot(Matrix &A, Matrix &B)
Class to store data of complex arrays and its properties.
tbb::combinable< double > * partial_cost_functions
array storing the partial cost functions
double imag
the imaginary part of a complex number
double get_osr_entanglement_test(Matrix &matrix, std::vector< std::vector< int >> &use_cuts, int rank, bool use_softmax)
Matrix get_deriv_osr_entanglement(Matrix &matrix, std::vector< std::vector< int >> &use_cuts, int rank, bool use_softmax)
QGD_Complex16 get_trace(Matrix &matrix)
Call to calculate the real and imaginary parts of the trace.
Matrix_real get_cost_function_with_correction2(const Matrix &matrix, int qbit_num, int trace_offset)
Call co calculate the cost function of the optimization process, and the first correction to the cost...