renormalization_group/
lib.rs1pub mod block_spin;
18pub mod critical_surface;
19pub mod fixed_point;
20pub mod flow;
21pub mod scaling;
22pub mod universality;
23
24pub use block_spin::*;
25pub use critical_surface::*;
26pub use fixed_point::*;
27pub use flow::*;
28pub use scaling::{
29 scaling_collapse, finite_size_order_parameter, finite_size_susceptibility,
30 finite_size_correlation_length, binder_cumulant, verify_hyperscaling,
31 find_tc_from_crossing, correlation_function, extract_correlation_length,
32 ScalingResult,
33};
34pub use universality::*;
35
36pub mod linalg {
39 pub fn solve(a: &[Vec<f64>], b: &[f64]) -> Option<Vec<f64>> {
42 let n = b.len();
43 if a.len() != n {
44 return None;
45 }
46 for row in a {
47 if row.len() != n {
48 return None;
49 }
50 }
51
52 let mut aug: Vec<Vec<f64>> = Vec::with_capacity(n);
54 for i in 0..n {
55 let mut row = a[i].clone();
56 row.push(b[i]);
57 aug.push(row);
58 }
59
60 for col in 0..n {
62 let mut max_row = col;
64 let mut max_val = aug[col][col].abs();
65 for row in (col + 1)..n {
66 let val = aug[row][col].abs();
67 if val > max_val {
68 max_val = val;
69 max_row = row;
70 }
71 }
72 if max_val < 1e-14 {
73 return None; }
75 aug.swap(col, max_row);
77
78 let pivot = aug[col][col];
80 for row in (col + 1)..n {
81 let factor = aug[row][col] / pivot;
82 for j in col..=(n) {
83 aug[row][j] -= factor * aug[col][j];
84 }
85 }
86 }
87
88 let mut x = vec![0.0; n];
90 for i in (0..n).rev() {
91 if aug[i][i].abs() < 1e-14 {
92 return None;
93 }
94 let mut sum = aug[i][n];
95 for j in (i + 1)..n {
96 sum -= aug[i][j] * x[j];
97 }
98 x[i] = sum / aug[i][i];
99 }
100 Some(x)
101 }
102
103 pub fn eigenvalues_symmetric(mat: &[Vec<f64>]) -> Vec<f64> {
106 let n = mat.len();
107 if n == 0 {
108 return vec![];
109 }
110 if n == 1 {
111 return vec![mat[0][0]];
112 }
113
114 let mut a: Vec<Vec<f64>> = mat.to_vec();
116 let max_iter = 100 * n * n;
117 let tol = 1e-12;
118
119 for _ in 0..max_iter {
120 let mut max_val = 0.0;
122 let mut p = 0;
123 let mut q = 1;
124 for i in 0..n {
125 for j in (i + 1)..n {
126 if a[i][j].abs() > max_val {
127 max_val = a[i][j].abs();
128 p = i;
129 q = j;
130 }
131 }
132 }
133 if max_val < tol {
134 break;
135 }
136
137 let app = a[p][p];
139 let aqq = a[q][q];
140 let apq = a[p][q];
141
142 let theta = if (app - aqq).abs() < 1e-15 {
143 std::f64::consts::FRAC_PI_4
144 } else {
145 0.5 * (2.0 * apq / (app - aqq)).atan()
146 };
147 let c = theta.cos();
148 let s = theta.sin();
149
150 let mut new_ap = vec![0.0; n];
153 let mut new_aq = vec![0.0; n];
154 for i in 0..n {
155 if i != p && i != q {
156 new_ap[i] = c * a[i][p] + s * a[i][q];
157 new_aq[i] = -s * a[i][p] + c * a[i][q];
158 }
159 }
160 new_ap[p] = c * c * app + 2.0 * s * c * apq + s * s * aqq;
161 new_aq[q] = s * s * app - 2.0 * s * c * apq + c * c * aqq;
162 new_ap[q] = 0.0;
163 new_aq[p] = 0.0;
164
165 for i in 0..n {
166 a[i][p] = new_ap[i];
167 a[p][i] = new_ap[i];
168 a[i][q] = new_aq[i];
169 a[q][i] = new_aq[i];
170 }
171 a[p][q] = 0.0;
172 a[q][p] = 0.0;
173 }
174
175 let mut eigenvals: Vec<f64> = (0..n).map(|i| a[i][i]).collect();
176 eigenvals.sort_by(|a, b| b.abs().partial_cmp(&a.abs()).unwrap_or(std::cmp::Ordering::Equal));
177 eigenvals
178 }
179
180 pub fn jacobian(
184 f: &dyn Fn(&[f64]) -> Vec<f64>,
185 x: &[f64],
186 h: f64,
187 ) -> Vec<Vec<f64>> {
188 let n = x.len();
189 let fx = f(x);
190 let m = fx.len();
191 let mut jac = vec![vec![0.0; n]; m];
192
193 for j in 0..n {
194 let mut xp = x.to_vec();
195 let mut xm = x.to_vec();
196 xp[j] += h;
197 xm[j] -= h;
198 let fp = f(&xp);
199 let fm = f(&xm);
200 for i in 0..m {
201 jac[i][j] = (fp[i] - fm[i]) / (2.0 * h);
202 }
203 }
204 jac
205 }
206
207 pub fn mat_vec_mul(a: &[Vec<f64>], x: &[f64]) -> Vec<f64> {
209 a.iter()
210 .map(|row| row.iter().zip(x.iter()).map(|(a, b)| a * b).sum())
211 .collect()
212 }
213
214 pub fn transpose(a: &[Vec<f64>]) -> Vec<Vec<f64>> {
216 if a.is_empty() {
217 return vec![];
218 }
219 let m = a.len();
220 let n = a[0].len();
221 (0..n)
222 .map(|j| (0..m).map(|i| a[i][j]).collect())
223 .collect()
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::linalg::*;
230
231 #[test]
232 fn test_gaussian_solve_identity() {
233 let a = vec![vec![1.0, 0.0], vec![0.0, 1.0]];
234 let b = vec![3.0, 4.0];
235 let x = solve(&a, &b).unwrap();
236 assert!((x[0] - 3.0).abs() < 1e-10);
237 assert!((x[1] - 4.0).abs() < 1e-10);
238 }
239
240 #[test]
241 fn test_gaussian_solve_3x3() {
242 let a = vec![vec![2.0, 1.0, -1.0], vec![-3.0, -1.0, 2.0], vec![-2.0, 1.0, 2.0]];
243 let b = vec![8.0, -11.0, -3.0];
244 let x = solve(&a, &b).unwrap();
245 assert!((x[0] - 2.0).abs() < 1e-10);
246 assert!((x[1] - 3.0).abs() < 1e-10);
247 assert!((x[2] - (-1.0)).abs() < 1e-10);
248 }
249
250 #[test]
251 fn test_gaussian_singular() {
252 let a = vec![vec![1.0, 2.0], vec![2.0, 4.0]];
253 let b = vec![1.0, 2.0];
254 assert!(solve(&a, &b).is_none());
255 }
256
257 #[test]
258 fn test_eigenvalues_2x2() {
259 let mat = vec![vec![4.0, 1.0], vec![1.0, 3.0]];
260 let eigs = eigenvalues_symmetric(&mat);
261 let e1 = (7.0 + 5.0_f64.sqrt()) / 2.0;
263 let e2 = (7.0 - 5.0_f64.sqrt()) / 2.0;
264 assert!((eigs[0] - e1).abs() < 0.01 || (eigs[0] - e2).abs() < 0.01);
265 assert!((eigs[1] - e1).abs() < 0.01 || (eigs[1] - e2).abs() < 0.01);
266 }
267}