@@ -42,7 +42,7 @@ static inline double closeness_like_bits(BigInteger perm, size_t n_rows, size_t
4242}
4343
4444static inline double expected_closeness_weight (size_t n_rows, size_t n_cols, size_t hamming_weight) {
45- size_t L = n_rows * n_cols;
45+ const size_t L = n_rows * n_cols;
4646 auto comb = [](size_t n, size_t k) {
4747 if ((k < 0 ) || (k > n)) {
4848 return 0ULL ;
@@ -56,46 +56,30 @@ static inline double expected_closeness_weight(size_t n_rows, size_t n_cols, siz
5656 }
5757 return res;
5858 };
59- double same_pairs = comb (hamming_weight, 2U ) + comb (L - hamming_weight, 2U );
60- double total_pairs = comb (L, 2U );
61- double mu_k = same_pairs / total_pairs;
59+ const double same_pairs = comb (hamming_weight, 2U ) + comb (L - hamming_weight, 2U );
60+ const double total_pairs = comb (L, 2U );
61+ const double mu_k = same_pairs / total_pairs;
62+
6263 return 2.0 * mu_k - 1.0 ;
6364}
6465
65- std::vector<std::string> generate_tfim_samples_cpp (double J, double h, double theta, double t, size_t n_qubits, size_t shots) {
66- // lattice dimensions
67- size_t n_rows = 1U ;
68- size_t n_cols = n_qubits;
69- for (size_t c = std::floor (std::sqrt (n_qubits)); c >= 1 ; --c) {
70- if ((n_qubits % c) == 0U ) {
71- n_rows = n_qubits / c;
72- n_cols = c;
73- break ;
74- }
75- }
76-
66+ static inline std::vector<double > probability_by_hamming_weight (double J, double h, double theta, double t, size_t n_qubits)
67+ {
7768 // critical angle
78- size_t z = 4U ;
79- double theta_c = std::asin (h / (z * J));
80- double delta_theta = theta - theta_c;
81-
82- // compute bias vector
69+ const size_t z = 4U ;
70+ const double theta_c = std::asin (h / (z * J));
71+ const double delta_theta = theta - theta_c;
8372 std::vector<double > bias;
8473 if (std::abs (h) < 1e-12 ) {
8574 bias.assign (n_qubits + 1 , 0.0 );
8675 bias[0 ] = 1.0 ;
8776 } else if (std::abs (J) < 1e-12 ) {
8877 bias.assign (n_qubits + 1 , 1.0 / (n_qubits + 1 ));
8978 } else {
90- double sin_delta = std::sin (delta_theta);
91- double omega = 1.5 * M_PI;
92- double t2 = 1.0 ;
93- double p = ((std::pow (2.0 , std::abs (J / h) - 1.0 )) *
94- (1.0 + sin_delta * std::cos (J * omega * t + theta) /
95- ((1.0 + std::sqrt (t / t2))))) - 0.5 ;
96- if (t2 <= 0 ) {
97- p = std::pow (2.0 , std::abs (J / h));
98- }
79+ const double sin_delta = std::sin (delta_theta);
80+ const double omega = 1.5 * M_PI;
81+ const double t2 = 1.0 ;
82+ const double p = std::pow (2.0 , std::abs (J / h) - 1.0 ) * (1.0 + sin_delta * std::cos (J * omega * t + theta) / (1.0 + std::sqrt (t / t2))) - 0.5 ;
9983 if (p >= 1024 ) {
10084 bias.assign (n_qubits + 1U , 0.0 );
10185 bias[0 ] = 1.0 ;
@@ -116,6 +100,23 @@ std::vector<std::string> generate_tfim_samples_cpp(double J, double h, double th
116100 std::reverse (bias.begin (), bias.end ());
117101 }
118102
103+ return bias;
104+ }
105+
106+ std::vector<std::string> generate_tfim_samples_cpp (double J, double h, double theta, double t, size_t n_qubits, size_t shots) {
107+ // lattice dimensions
108+ size_t n_rows = 1U ;
109+ size_t n_cols = n_qubits;
110+ for (size_t c = std::floor (std::sqrt (n_qubits)); c >= 1 ; --c) {
111+ if ((n_qubits % c) == 0U ) {
112+ n_rows = n_qubits / c;
113+ n_cols = c;
114+ break ;
115+ }
116+ }
117+
118+ const std::vector<double > bias = probability_by_hamming_weight (J, h, theta, t, n_qubits);
119+
119120 // thresholds
120121 std::vector<double > thresholds (n_qubits + 1 );
121122 double tot_prob = 0.0 ;
@@ -188,10 +189,38 @@ std::vector<std::string> generate_tfim_samples_cpp(double J, double h, double th
188189 return output;
189190}
190191
192+ double tfim_magnetization (double J, double h, double theta, double t, size_t n_qubits) {
193+ const std::vector<double > bias = probability_by_hamming_weight (J, h, theta, t, n_qubits);
194+ double magnetization = 0.0 ;
195+ for (size_t q = 0U ; q < bias.size (); ++q) {
196+ const double mag = (n_qubits - 2.0 * q) / n_qubits;
197+ magnetization += bias[q] * mag;
198+ }
199+
200+ return magnetization;
201+ }
202+
203+ double tfim_square_magnetization (double J, double h, double theta, double t, size_t n_qubits) {
204+ const std::vector<double > bias = probability_by_hamming_weight (J, h, theta, t, n_qubits);
205+ double square_magnetization = 0.0 ;
206+ for (size_t q = 0U ; q < bias.size (); ++q) {
207+ const double mag = (n_qubits - 2.0 * q) / n_qubits;
208+ square_magnetization += bias[q] * mag * mag;
209+ }
210+
211+ return square_magnetization;
212+ }
213+
191214PYBIND11_MODULE (tfim_sampler, m) {
192215 m.doc () = " PyQrackIsing TFIM sample generator" ;
193216 m.def (" _generate_tfim_samples" , &generate_tfim_samples_cpp,
194217 py::arg (" J" ), py::arg (" h" ), py::arg (" theta" ), py::arg (" t" ),
195218 py::arg (" n_qubits" ), py::arg (" shots" ));
219+ m.def (" _tfim_magnetization" , &tfim_magnetization,
220+ py::arg (" J" ), py::arg (" h" ), py::arg (" theta" ), py::arg (" t" ),
221+ py::arg (" n_qubits" ));
222+ m.def (" _tfim_square_magnetization" , &tfim_square_magnetization,
223+ py::arg (" J" ), py::arg (" h" ), py::arg (" theta" ), py::arg (" t" ),
224+ py::arg (" n_qubits" ));
196225}
197226
0 commit comments