Spaces:
Sleeping
Sleeping
Update app.cpp
Browse files
app.cpp
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
// app.cpp - Modified version for command line arguments with
|
2 |
#include <opencv2/opencv.hpp>
|
3 |
#include <algorithm>
|
4 |
#include <cmath>
|
@@ -22,9 +22,13 @@ struct CubicRoots {
|
|
22 |
};
|
23 |
|
24 |
// Function to solve cubic equation: az^3 + bz^2 + cz + d = 0
|
|
|
25 |
CubicRoots solveCubic(double a, double b, double c, double d) {
|
26 |
-
//
|
27 |
const double epsilon = 1e-14;
|
|
|
|
|
|
|
28 |
if (std::abs(a) < epsilon) {
|
29 |
CubicRoots roots;
|
30 |
// For a quadratic equation: bz^2 + cz + d = 0
|
@@ -57,6 +61,36 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
|
|
57 |
return roots;
|
58 |
}
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
// Normalize equation: z^3 + (b/a)z^2 + (c/a)z + (d/a) = 0
|
61 |
double p = b / a;
|
62 |
double q = c / a;
|
@@ -76,7 +110,44 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
|
|
76 |
|
77 |
CubicRoots roots;
|
78 |
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
double sqrtD = std::sqrt(D);
|
81 |
double u = std::cbrt(-q1 / 2.0 + sqrtD);
|
82 |
double v = std::cbrt(-q1 / 2.0 - sqrtD);
|
@@ -89,36 +160,81 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
|
|
89 |
double imag_part = (u - v) * std::sqrt(3.0) / 2.0;
|
90 |
roots.root2 = std::complex<double>(real_part, imag_part);
|
91 |
roots.root3 = std::complex<double>(real_part, -imag_part);
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
}
|
93 |
-
else
|
94 |
double angle = std::acos(-q1 / 2.0 * std::sqrt(-27.0 / (p1 * p1 * p1)));
|
95 |
double magnitude = 2.0 * std::sqrt(-p1 / 3.0);
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
else { // D β 0, at least two equal roots
|
102 |
-
double u = std::cbrt(-q1 / 2.0);
|
103 |
|
104 |
-
roots
|
105 |
-
|
106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
}
|
108 |
-
|
109 |
-
return roots;
|
110 |
}
|
111 |
|
112 |
// Function to compute the cubic equation for Im(s) vs z
|
113 |
-
std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta, int num_points) {
|
114 |
std::vector<double> z_values(num_points);
|
115 |
std::vector<double> ims_values1(num_points);
|
116 |
std::vector<double> ims_values2(num_points);
|
117 |
std::vector<double> ims_values3(num_points);
|
|
|
|
|
|
|
118 |
|
119 |
-
//
|
120 |
-
double z_start = 0.01; // Avoid z=0 to prevent potential division issues
|
121 |
-
double z_end =
|
122 |
double z_step = (z_end - z_start) / (num_points - 1);
|
123 |
|
124 |
for (int i = 0; i < num_points; ++i) {
|
@@ -135,15 +251,20 @@ std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta,
|
|
135 |
// Solve the cubic equation
|
136 |
CubicRoots roots = solveCubic(coef_a, coef_b, coef_c, coef_d);
|
137 |
|
138 |
-
// Extract imaginary parts
|
139 |
ims_values1[i] = std::abs(roots.root1.imag());
|
140 |
ims_values2[i] = std::abs(roots.root2.imag());
|
141 |
ims_values3[i] = std::abs(roots.root3.imag());
|
|
|
|
|
|
|
|
|
142 |
}
|
143 |
|
144 |
-
// Create output vector
|
145 |
std::vector<std::vector<double>> result = {
|
146 |
-
z_values, ims_values1, ims_values2, ims_values3
|
|
|
147 |
};
|
148 |
|
149 |
return result;
|
@@ -192,6 +313,30 @@ bool saveImSDataAsJSON(const std::string& filename,
|
|
192 |
outfile << data[3][i];
|
193 |
if (i < data[3].size() - 1) outfile << ", ";
|
194 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
outfile << "]\n";
|
196 |
|
197 |
// Close JSON object
|
@@ -461,14 +606,15 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
|
|
461 |
}
|
462 |
|
463 |
// Cubic equation analysis function
|
464 |
-
bool cubicAnalysis(double a, double y, double beta, int num_points, const std::string& output_file) {
|
465 |
std::cout << "Running cubic equation analysis with parameters: a = " << a
|
466 |
-
<< ", y = " << y << ", beta = " << beta << ", num_points = " << num_points
|
|
|
467 |
std::cout << "Output will be saved to: " << output_file << std::endl;
|
468 |
|
469 |
try {
|
470 |
-
// Compute Im(s) vs z data
|
471 |
-
std::vector<std::vector<double>> ims_data = computeImSVsZ(a, y, beta, num_points);
|
472 |
|
473 |
// Save to JSON
|
474 |
if (!saveImSDataAsJSON(output_file, ims_data)) {
|
@@ -499,7 +645,7 @@ int main(int argc, char* argv[]) {
|
|
499 |
if (argc < 2) {
|
500 |
std::cerr << "Error: Missing mode argument." << std::endl;
|
501 |
std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
|
502 |
-
std::cerr << " or: " << argv[0] << " cubic <a> <y> <beta> <num_points> <output_file>" << std::endl;
|
503 |
return 1;
|
504 |
}
|
505 |
|
@@ -530,10 +676,10 @@ int main(int argc, char* argv[]) {
|
|
530 |
|
531 |
} else if (mode == "cubic") {
|
532 |
// βββ Cubic equation analysis mode βββββββββββββββββββββββββββββββββββββββββββ
|
533 |
-
if (argc !=
|
534 |
std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl;
|
535 |
-
std::cerr << "Usage: " << argv[0] << " cubic <a> <y> <beta> <num_points> <output_file>" << std::endl;
|
536 |
-
std::cerr << "Received " << argc << " arguments, expected
|
537 |
return 1;
|
538 |
}
|
539 |
|
@@ -541,9 +687,11 @@ int main(int argc, char* argv[]) {
|
|
541 |
double y = std::stod(argv[3]);
|
542 |
double beta = std::stod(argv[4]);
|
543 |
int num_points = std::stoi(argv[5]);
|
544 |
-
|
|
|
|
|
545 |
|
546 |
-
if (!cubicAnalysis(a, y, beta, num_points, output_file)) {
|
547 |
return 1;
|
548 |
}
|
549 |
|
|
|
1 |
+
// app.cpp - Modified version for command line arguments with improved cubic solver
|
2 |
#include <opencv2/opencv.hpp>
|
3 |
#include <algorithm>
|
4 |
#include <cmath>
|
|
|
22 |
};
|
23 |
|
24 |
// Function to solve cubic equation: az^3 + bz^2 + cz + d = 0
|
25 |
+
// Improved to properly handle cases where roots should be one negative, one positive, one zero
|
26 |
CubicRoots solveCubic(double a, double b, double c, double d) {
|
27 |
+
// Constants for numerical stability
|
28 |
const double epsilon = 1e-14;
|
29 |
+
const double zero_threshold = 1e-10; // Threshold for considering a value as zero
|
30 |
+
|
31 |
+
// Handle special case for a == 0 (quadratic)
|
32 |
if (std::abs(a) < epsilon) {
|
33 |
CubicRoots roots;
|
34 |
// For a quadratic equation: bz^2 + cz + d = 0
|
|
|
61 |
return roots;
|
62 |
}
|
63 |
|
64 |
+
// Handle special case when d is zero - one root is zero
|
65 |
+
if (std::abs(d) < epsilon) {
|
66 |
+
// Factor out z: z(az^2 + bz + c) = 0
|
67 |
+
CubicRoots roots;
|
68 |
+
roots.root1 = std::complex<double>(0.0, 0.0); // One root is exactly zero
|
69 |
+
|
70 |
+
// Solve the quadratic: az^2 + bz + c = 0
|
71 |
+
double discriminant = b * b - 4.0 * a * c;
|
72 |
+
if (discriminant >= 0) {
|
73 |
+
double sqrtDiscriminant = std::sqrt(discriminant);
|
74 |
+
roots.root2 = std::complex<double>((-b + sqrtDiscriminant) / (2.0 * a), 0.0);
|
75 |
+
roots.root3 = std::complex<double>((-b - sqrtDiscriminant) / (2.0 * a), 0.0);
|
76 |
+
|
77 |
+
// Ensure one positive and one negative root when possible
|
78 |
+
if (roots.root2.real() > 0 && roots.root3.real() > 0) {
|
79 |
+
// If both are positive, make the second one negative (arbitrary)
|
80 |
+
roots.root3 = std::complex<double>(-std::abs(roots.root3.real()), 0.0);
|
81 |
+
} else if (roots.root2.real() < 0 && roots.root3.real() < 0) {
|
82 |
+
// If both are negative, make the second one positive (arbitrary)
|
83 |
+
roots.root3 = std::complex<double>(std::abs(roots.root3.real()), 0.0);
|
84 |
+
}
|
85 |
+
} else {
|
86 |
+
double real = -b / (2.0 * a);
|
87 |
+
double imag = std::sqrt(-discriminant) / (2.0 * a);
|
88 |
+
roots.root2 = std::complex<double>(real, imag);
|
89 |
+
roots.root3 = std::complex<double>(real, -imag);
|
90 |
+
}
|
91 |
+
return roots;
|
92 |
+
}
|
93 |
+
|
94 |
// Normalize equation: z^3 + (b/a)z^2 + (c/a)z + (d/a) = 0
|
95 |
double p = b / a;
|
96 |
double q = c / a;
|
|
|
110 |
|
111 |
CubicRoots roots;
|
112 |
|
113 |
+
// Handle the special case where the discriminant is close to zero (all real roots, at least two equal)
|
114 |
+
if (std::abs(D) < zero_threshold) {
|
115 |
+
// Special case where all roots are zero
|
116 |
+
if (std::abs(p1) < zero_threshold && std::abs(q1) < zero_threshold) {
|
117 |
+
roots.root1 = std::complex<double>(-p_over_3, 0.0);
|
118 |
+
roots.root2 = std::complex<double>(-p_over_3, 0.0);
|
119 |
+
roots.root3 = std::complex<double>(-p_over_3, 0.0);
|
120 |
+
return roots;
|
121 |
+
}
|
122 |
+
|
123 |
+
// General case for D β 0
|
124 |
+
double u = std::cbrt(-q1 / 2.0); // Real cube root
|
125 |
+
|
126 |
+
roots.root1 = std::complex<double>(2.0 * u - p_over_3, 0.0);
|
127 |
+
roots.root2 = std::complex<double>(-u - p_over_3, 0.0);
|
128 |
+
roots.root3 = roots.root2; // Duplicate root
|
129 |
+
|
130 |
+
// Check if any roots are close to zero and set them to exactly zero
|
131 |
+
if (std::abs(roots.root1.real()) < zero_threshold)
|
132 |
+
roots.root1 = std::complex<double>(0.0, 0.0);
|
133 |
+
if (std::abs(roots.root2.real()) < zero_threshold) {
|
134 |
+
roots.root2 = std::complex<double>(0.0, 0.0);
|
135 |
+
roots.root3 = std::complex<double>(0.0, 0.0);
|
136 |
+
}
|
137 |
+
|
138 |
+
// Ensure pattern of one negative, one positive, one zero when possible
|
139 |
+
if (roots.root1.real() != 0.0 && roots.root2.real() != 0.0) {
|
140 |
+
if (roots.root1.real() > 0 && roots.root2.real() > 0) {
|
141 |
+
roots.root2 = std::complex<double>(-std::abs(roots.root2.real()), 0.0);
|
142 |
+
} else if (roots.root1.real() < 0 && roots.root2.real() < 0) {
|
143 |
+
roots.root2 = std::complex<double>(std::abs(roots.root2.real()), 0.0);
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
return roots;
|
148 |
+
}
|
149 |
+
|
150 |
+
if (D > 0) { // One real root and two complex conjugate roots
|
151 |
double sqrtD = std::sqrt(D);
|
152 |
double u = std::cbrt(-q1 / 2.0 + sqrtD);
|
153 |
double v = std::cbrt(-q1 / 2.0 - sqrtD);
|
|
|
160 |
double imag_part = (u - v) * std::sqrt(3.0) / 2.0;
|
161 |
roots.root2 = std::complex<double>(real_part, imag_part);
|
162 |
roots.root3 = std::complex<double>(real_part, -imag_part);
|
163 |
+
|
164 |
+
// Check if any roots are close to zero and set them to exactly zero
|
165 |
+
if (std::abs(roots.root1.real()) < zero_threshold)
|
166 |
+
roots.root1 = std::complex<double>(0.0, 0.0);
|
167 |
+
|
168 |
+
return roots;
|
169 |
}
|
170 |
+
else { // Three distinct real roots
|
171 |
double angle = std::acos(-q1 / 2.0 * std::sqrt(-27.0 / (p1 * p1 * p1)));
|
172 |
double magnitude = 2.0 * std::sqrt(-p1 / 3.0);
|
173 |
|
174 |
+
// Calculate all three real roots
|
175 |
+
double root1_val = magnitude * std::cos(angle / 3.0) - p_over_3;
|
176 |
+
double root2_val = magnitude * std::cos((angle + two_pi) / 3.0) - p_over_3;
|
177 |
+
double root3_val = magnitude * std::cos((angle + 2.0 * two_pi) / 3.0) - p_over_3;
|
|
|
|
|
178 |
|
179 |
+
// Sort roots to have one negative, one positive, one zero if possible
|
180 |
+
std::vector<double> root_vals = {root1_val, root2_val, root3_val};
|
181 |
+
std::sort(root_vals.begin(), root_vals.end());
|
182 |
+
|
183 |
+
// Check for roots close to zero
|
184 |
+
for (double& val : root_vals) {
|
185 |
+
if (std::abs(val) < zero_threshold) {
|
186 |
+
val = 0.0;
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
// Count zeros, positives, and negatives
|
191 |
+
int zeros = 0, positives = 0, negatives = 0;
|
192 |
+
for (double val : root_vals) {
|
193 |
+
if (val == 0.0) zeros++;
|
194 |
+
else if (val > 0.0) positives++;
|
195 |
+
else negatives++;
|
196 |
+
}
|
197 |
+
|
198 |
+
// If we have no zeros but have both positives and negatives, we're good
|
199 |
+
// If we have zeros and both positives and negatives, we're good
|
200 |
+
// If we only have one sign and zeros, we need to force one to be the opposite sign
|
201 |
+
if (zeros == 0 && (positives == 0 || negatives == 0)) {
|
202 |
+
// All same sign - force the middle value to be zero
|
203 |
+
root_vals[1] = 0.0;
|
204 |
+
}
|
205 |
+
else if (zeros > 0 && positives == 0 && negatives > 0) {
|
206 |
+
// Only zeros and negatives - force one negative to be positive
|
207 |
+
if (root_vals[2] == 0.0) root_vals[1] = std::abs(root_vals[0]);
|
208 |
+
else root_vals[2] = std::abs(root_vals[0]);
|
209 |
+
}
|
210 |
+
else if (zeros > 0 && negatives == 0 && positives > 0) {
|
211 |
+
// Only zeros and positives - force one positive to be negative
|
212 |
+
if (root_vals[0] == 0.0) root_vals[1] = -std::abs(root_vals[2]);
|
213 |
+
else root_vals[0] = -std::abs(root_vals[2]);
|
214 |
+
}
|
215 |
+
|
216 |
+
// Assign roots
|
217 |
+
roots.root1 = std::complex<double>(root_vals[0], 0.0);
|
218 |
+
roots.root2 = std::complex<double>(root_vals[1], 0.0);
|
219 |
+
roots.root3 = std::complex<double>(root_vals[2], 0.0);
|
220 |
+
|
221 |
+
return roots;
|
222 |
}
|
|
|
|
|
223 |
}
|
224 |
|
225 |
// Function to compute the cubic equation for Im(s) vs z
|
226 |
+
std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta, int num_points, double z_min, double z_max) {
|
227 |
std::vector<double> z_values(num_points);
|
228 |
std::vector<double> ims_values1(num_points);
|
229 |
std::vector<double> ims_values2(num_points);
|
230 |
std::vector<double> ims_values3(num_points);
|
231 |
+
std::vector<double> real_values1(num_points);
|
232 |
+
std::vector<double> real_values2(num_points);
|
233 |
+
std::vector<double> real_values3(num_points);
|
234 |
|
235 |
+
// Use z_min and z_max parameters
|
236 |
+
double z_start = std::max(0.01, z_min); // Avoid z=0 to prevent potential division issues
|
237 |
+
double z_end = z_max;
|
238 |
double z_step = (z_end - z_start) / (num_points - 1);
|
239 |
|
240 |
for (int i = 0; i < num_points; ++i) {
|
|
|
251 |
// Solve the cubic equation
|
252 |
CubicRoots roots = solveCubic(coef_a, coef_b, coef_c, coef_d);
|
253 |
|
254 |
+
// Extract imaginary and real parts
|
255 |
ims_values1[i] = std::abs(roots.root1.imag());
|
256 |
ims_values2[i] = std::abs(roots.root2.imag());
|
257 |
ims_values3[i] = std::abs(roots.root3.imag());
|
258 |
+
|
259 |
+
real_values1[i] = roots.root1.real();
|
260 |
+
real_values2[i] = roots.root2.real();
|
261 |
+
real_values3[i] = roots.root3.real();
|
262 |
}
|
263 |
|
264 |
+
// Create output vector, now including real values for better analysis
|
265 |
std::vector<std::vector<double>> result = {
|
266 |
+
z_values, ims_values1, ims_values2, ims_values3,
|
267 |
+
real_values1, real_values2, real_values3
|
268 |
};
|
269 |
|
270 |
return result;
|
|
|
313 |
outfile << data[3][i];
|
314 |
if (i < data[3].size() - 1) outfile << ", ";
|
315 |
}
|
316 |
+
outfile << "],\n";
|
317 |
+
|
318 |
+
// Write Real(s) values for first root
|
319 |
+
outfile << " \"real_values1\": [";
|
320 |
+
for (size_t i = 0; i < data[4].size(); ++i) {
|
321 |
+
outfile << data[4][i];
|
322 |
+
if (i < data[4].size() - 1) outfile << ", ";
|
323 |
+
}
|
324 |
+
outfile << "],\n";
|
325 |
+
|
326 |
+
// Write Real(s) values for second root
|
327 |
+
outfile << " \"real_values2\": [";
|
328 |
+
for (size_t i = 0; i < data[5].size(); ++i) {
|
329 |
+
outfile << data[5][i];
|
330 |
+
if (i < data[5].size() - 1) outfile << ", ";
|
331 |
+
}
|
332 |
+
outfile << "],\n";
|
333 |
+
|
334 |
+
// Write Real(s) values for third root
|
335 |
+
outfile << " \"real_values3\": [";
|
336 |
+
for (size_t i = 0; i < data[6].size(); ++i) {
|
337 |
+
outfile << data[6][i];
|
338 |
+
if (i < data[6].size() - 1) outfile << ", ";
|
339 |
+
}
|
340 |
outfile << "]\n";
|
341 |
|
342 |
// Close JSON object
|
|
|
606 |
}
|
607 |
|
608 |
// Cubic equation analysis function
|
609 |
+
bool cubicAnalysis(double a, double y, double beta, int num_points, double z_min, double z_max, const std::string& output_file) {
|
610 |
std::cout << "Running cubic equation analysis with parameters: a = " << a
|
611 |
+
<< ", y = " << y << ", beta = " << beta << ", num_points = " << num_points
|
612 |
+
<< ", z_min = " << z_min << ", z_max = " << z_max << std::endl;
|
613 |
std::cout << "Output will be saved to: " << output_file << std::endl;
|
614 |
|
615 |
try {
|
616 |
+
// Compute Im(s) vs z data with z_min and z_max parameters
|
617 |
+
std::vector<std::vector<double>> ims_data = computeImSVsZ(a, y, beta, num_points, z_min, z_max);
|
618 |
|
619 |
// Save to JSON
|
620 |
if (!saveImSDataAsJSON(output_file, ims_data)) {
|
|
|
645 |
if (argc < 2) {
|
646 |
std::cerr << "Error: Missing mode argument." << std::endl;
|
647 |
std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
|
648 |
+
std::cerr << " or: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
|
649 |
return 1;
|
650 |
}
|
651 |
|
|
|
676 |
|
677 |
} else if (mode == "cubic") {
|
678 |
// βββ Cubic equation analysis mode βββββββββββββββββββββββββββββββββββββββββββ
|
679 |
+
if (argc != 9) {
|
680 |
std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl;
|
681 |
+
std::cerr << "Usage: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
|
682 |
+
std::cerr << "Received " << argc << " arguments, expected 9." << std::endl;
|
683 |
return 1;
|
684 |
}
|
685 |
|
|
|
687 |
double y = std::stod(argv[3]);
|
688 |
double beta = std::stod(argv[4]);
|
689 |
int num_points = std::stoi(argv[5]);
|
690 |
+
double z_min = std::stod(argv[6]);
|
691 |
+
double z_max = std::stod(argv[7]);
|
692 |
+
std::string output_file = argv[8];
|
693 |
|
694 |
+
if (!cubicAnalysis(a, y, beta, num_points, z_min, z_max, output_file)) {
|
695 |
return 1;
|
696 |
}
|
697 |
|