euler314 commited on
Commit
677c19d
Β·
verified Β·
1 Parent(s): 0d7cccf

Update app.cpp

Browse files
Files changed (1) hide show
  1. app.cpp +180 -32
app.cpp CHANGED
@@ -1,4 +1,4 @@
1
- // app.cpp - Modified version for command line arguments with improvements
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
- // Handle special case for a == 0 (quadratic)
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
- if (D > epsilon) { // One real root and two complex conjugate roots
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 if (D < -epsilon) { // Three distinct real roots
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
- roots.root1 = std::complex<double>(magnitude * std::cos(angle / 3.0) - p_over_3, 0.0);
98
- roots.root2 = std::complex<double>(magnitude * std::cos((angle + two_pi) / 3.0) - p_over_3, 0.0);
99
- roots.root3 = std::complex<double>(magnitude * std::cos((angle + 2.0 * two_pi) / 3.0) - p_over_3, 0.0);
100
- }
101
- else { // D β‰ˆ 0, at least two equal roots
102
- double u = std::cbrt(-q1 / 2.0);
103
 
104
- roots.root1 = std::complex<double>(2.0 * u - p_over_3, 0.0);
105
- roots.root2 = std::complex<double>(-u - p_over_3, 0.0);
106
- roots.root3 = roots.root2; // Duplicate root
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- // Generate z values from 0.01 to 10 (or adjust range as needed)
120
- double z_start = 0.01; // Avoid z=0 to prevent potential division issues
121
- double z_end = 10.0;
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 << std::endl;
 
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 != 7) {
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 7." << std::endl;
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
- std::string output_file = argv[6];
 
 
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