Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
singular_value_decomposition.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * SingularValueDecomposition — A = U S V^dagger through zgesvd, the economy
5 * form: U has as many columns as there are singular values, and V^dagger as
6 * many rows.
7 *
8 * The economy form is the one a projection gauge needs -- U V^dagger is the
9 * unitary nearest A, and the singular values are the direct measure of how
10 * well A's columns span its rows -- and the full one costs a rows x rows U
11 * that nothing reads.
12 */
13
14#include <algorithm>
15#include <stdexcept>
16#include <string>
17#include <utility>
18#include <vector>
19
24
25namespace q3 {
26
28 public:
29 /// `context` opens every error this decomposition raises.
30 explicit SingularValueDecomposition(std::string context) : context_(std::move(context)) {}
31
32 /// The decomposition of `matrix`, taken by value because zgesvd destroys its input.
34 int rows = matrix.rows();
35 int columns = matrix.columns();
36 if (rows == 0 || columns == 0) {
37 throw std::invalid_argument(context_ +
38 ": a singular value decomposition needs a matrix with "
39 "rows and columns, got " +
40 std::to_string(rows) + " x " + std::to_string(columns));
41 }
42 int count = std::min(rows, columns);
43
45 result.singular_values.assign(static_cast<std::size_t>(count), 0.0);
46 result.left_vectors = DenseMatrix<Complex>(rows, count, Complex(0.0, 0.0));
47 result.right_vectors_adjoint = DenseMatrix<Complex>(count, columns, Complex(0.0, 0.0));
48 std::vector<Real> real_workspace(5 * static_cast<std::size_t>(count));
49
50 int info = 0;
51 int workspace_size = -1;
52 Complex workspace_query;
54 "S",
55 &rows,
56 &columns,
57 matrix.data(),
58 &rows,
59 result.singular_values.data(),
60 result.left_vectors.data(),
61 &rows,
63 &count,
64 &workspace_query,
65 &workspace_size,
66 real_workspace.data(),
67 &info);
68 if (info != 0) {
69 throw std::runtime_error(
70 context_ + ": zgesvd workspace query failed with info = " + std::to_string(info));
71 }
72 workspace_size = std::max(1, static_cast<int>(workspace_query.real()));
73 std::vector<Complex> workspace(static_cast<std::size_t>(workspace_size));
75 "S",
76 &rows,
77 &columns,
78 matrix.data(),
79 &rows,
80 result.singular_values.data(),
81 result.left_vectors.data(),
82 &rows,
84 &count,
85 workspace.data(),
86 &workspace_size,
87 real_workspace.data(),
88 &info);
89 if (info != 0) {
90 throw std::runtime_error(context_ +
91 ": zgesvd failed with info = " + std::to_string(info));
92 }
93 return result;
94 }
95
96 private:
97 std::string context_;
98};
99
100} // namespace q3
int rows() const
T * data()
The column-major buffer: with rows() it is the (pointer, leading dimension) BLAS takes.
int columns() const
SingularValueDecompositionResult compute(DenseMatrix< Complex > matrix) const
The decomposition of matrix, taken by value because zgesvd destroys its input.
SingularValueDecomposition(std::string context)
context opens every error this decomposition raises.
void zgesvd_(const char *jobu, const char *jobvt, const int *m, const int *n, std::complex< double > *a, const int *lda, double *s, std::complex< double > *u, const int *ldu, std::complex< double > *vt, const int *ldvt, std::complex< double > *work, const int *lwork, double *rwork, int *info)
std::complex< double > Complex