euler314 commited on
Commit
564e80e
Β·
verified Β·
1 Parent(s): d7db5ca

Update app.cpp

Browse files
Files changed (1) hide show
  1. app.cpp +344 -153
app.cpp CHANGED
@@ -1,4 +1,4 @@
1
- // app.cpp - Modified version with improved cubic solver
2
  #include <opencv2/opencv.hpp>
3
  #include <algorithm>
4
  #include <cmath>
@@ -281,148 +281,6 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
281
  return roots;
282
  }
283
 
284
- // Function to compute the cubic equation for Im(s) vs z
285
- std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta, int num_points, double z_min, double z_max) {
286
- std::vector<double> z_values(num_points);
287
- std::vector<double> ims_values1(num_points);
288
- std::vector<double> ims_values2(num_points);
289
- std::vector<double> ims_values3(num_points);
290
- std::vector<double> real_values1(num_points);
291
- std::vector<double> real_values2(num_points);
292
- std::vector<double> real_values3(num_points);
293
-
294
- // Use z_min and z_max parameters
295
- double z_start = std::max(0.01, z_min); // Avoid z=0 to prevent potential division issues
296
- double z_end = z_max;
297
- double z_step = (z_end - z_start) / (num_points - 1);
298
-
299
- for (int i = 0; i < num_points; ++i) {
300
- double z = z_start + i * z_step;
301
- z_values[i] = z;
302
-
303
- // Coefficients for the cubic equation:
304
- // zasΒ³ + [z(a+1)+a(1-y)]sΒ² + [z+(a+1)-y-yΞ²(a-1)]s + 1 = 0
305
- double coef_a = z * a;
306
- double coef_b = z * (a + 1) + a * (1 - y);
307
- double coef_c = z + (a + 1) - y - y * beta * (a - 1);
308
- double coef_d = 1.0;
309
-
310
- // Solve the cubic equation
311
- CubicRoots roots = solveCubic(coef_a, coef_b, coef_c, coef_d);
312
-
313
- // Extract imaginary and real parts
314
- ims_values1[i] = std::abs(roots.root1.imag());
315
- ims_values2[i] = std::abs(roots.root2.imag());
316
- ims_values3[i] = std::abs(roots.root3.imag());
317
-
318
- real_values1[i] = roots.root1.real();
319
- real_values2[i] = roots.root2.real();
320
- real_values3[i] = roots.root3.real();
321
- }
322
-
323
- // Create output vector, now including real values for better analysis
324
- std::vector<std::vector<double>> result = {
325
- z_values, ims_values1, ims_values2, ims_values3,
326
- real_values1, real_values2, real_values3
327
- };
328
-
329
- return result;
330
- }
331
-
332
- // Function to save Im(s) vs z data as JSON
333
- bool saveImSDataAsJSON(const std::string& filename,
334
- const std::vector<std::vector<double>>& data) {
335
- std::ofstream outfile(filename);
336
-
337
- if (!outfile.is_open()) {
338
- std::cerr << "Error: Could not open file " << filename << " for writing." << std::endl;
339
- return false;
340
- }
341
-
342
- // Helper function to format floating point values safely for JSON
343
- auto formatJsonValue = [](double value) -> std::string {
344
- if (std::isnan(value)) {
345
- return "\"NaN\""; // JSON doesn't support NaN, so use string
346
- } else if (std::isinf(value)) {
347
- if (value > 0) {
348
- return "\"Infinity\""; // JSON doesn't support Infinity, so use string
349
- } else {
350
- return "\"-Infinity\""; // JSON doesn't support -Infinity, so use string
351
- }
352
- } else {
353
- // Use a fixed precision to avoid excessively long numbers
354
- std::ostringstream oss;
355
- oss << std::setprecision(15) << value;
356
- return oss.str();
357
- }
358
- };
359
-
360
- // Start JSON object
361
- outfile << "{\n";
362
-
363
- // Write z values
364
- outfile << " \"z_values\": [";
365
- for (size_t i = 0; i < data[0].size(); ++i) {
366
- outfile << formatJsonValue(data[0][i]);
367
- if (i < data[0].size() - 1) outfile << ", ";
368
- }
369
- outfile << "],\n";
370
-
371
- // Write Im(s) values for first root
372
- outfile << " \"ims_values1\": [";
373
- for (size_t i = 0; i < data[1].size(); ++i) {
374
- outfile << formatJsonValue(data[1][i]);
375
- if (i < data[1].size() - 1) outfile << ", ";
376
- }
377
- outfile << "],\n";
378
-
379
- // Write Im(s) values for second root
380
- outfile << " \"ims_values2\": [";
381
- for (size_t i = 0; i < data[2].size(); ++i) {
382
- outfile << formatJsonValue(data[2][i]);
383
- if (i < data[2].size() - 1) outfile << ", ";
384
- }
385
- outfile << "],\n";
386
-
387
- // Write Im(s) values for third root
388
- outfile << " \"ims_values3\": [";
389
- for (size_t i = 0; i < data[3].size(); ++i) {
390
- outfile << formatJsonValue(data[3][i]);
391
- if (i < data[3].size() - 1) outfile << ", ";
392
- }
393
- outfile << "],\n";
394
-
395
- // Write Real(s) values for first root
396
- outfile << " \"real_values1\": [";
397
- for (size_t i = 0; i < data[4].size(); ++i) {
398
- outfile << formatJsonValue(data[4][i]);
399
- if (i < data[4].size() - 1) outfile << ", ";
400
- }
401
- outfile << "],\n";
402
-
403
- // Write Real(s) values for second root
404
- outfile << " \"real_values2\": [";
405
- for (size_t i = 0; i < data[5].size(); ++i) {
406
- outfile << formatJsonValue(data[5][i]);
407
- if (i < data[5].size() - 1) outfile << ", ";
408
- }
409
- outfile << "],\n";
410
-
411
- // Write Real(s) values for third root
412
- outfile << " \"real_values3\": [";
413
- for (size_t i = 0; i < data[6].size(); ++i) {
414
- outfile << formatJsonValue(data[6][i]);
415
- if (i < data[6].size() - 1) outfile << ", ";
416
- }
417
- outfile << "]\n";
418
-
419
- // Close JSON object
420
- outfile << "}\n";
421
-
422
- outfile.close();
423
- return true;
424
- }
425
-
426
  // Function to compute the theoretical max value
427
  double compute_theoretical_max(double a, double y, double beta, int grid_points, double tolerance) {
428
  auto f = [a, y, beta](double k) -> double {
@@ -614,21 +472,21 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
614
  << ", theory_tolerance = " << theory_tolerance << std::endl;
615
  std::cout << "Output will be saved to: " << output_file << std::endl;
616
 
617
- // ─── Beta range parameters ────────────────────────────────────────
618
  const int num_beta_points = fineness; // Controlled by fineness parameter
619
  std::vector<double> beta_values(num_beta_points);
620
  for (int i = 0; i < num_beta_points; ++i) {
621
  beta_values[i] = static_cast<double>(i) / (num_beta_points - 1);
622
  }
623
 
624
- // ─── Storage for results ────────────────────────────────────────
625
  std::vector<double> max_eigenvalues(num_beta_points);
626
  std::vector<double> min_eigenvalues(num_beta_points);
627
  std::vector<double> theoretical_max_values(num_beta_points);
628
  std::vector<double> theoretical_min_values(num_beta_points);
629
 
630
  try {
631
- // ─── Random‐Gaussian X and S_n ────────────────────────────────
632
  std::random_device rd;
633
  std::mt19937_64 rng{rd()};
634
  std::normal_distribution<double> norm(0.0, 1.0);
@@ -638,7 +496,7 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
638
  for(int j = 0; j < n; ++j)
639
  X.at<double>(i,j) = norm(rng);
640
 
641
- // ─── Process each beta value ─────────────────────────────────
642
  for (int beta_idx = 0; beta_idx < num_beta_points; ++beta_idx) {
643
  double beta = beta_values[beta_idx];
644
 
@@ -646,7 +504,7 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
646
  theoretical_max_values[beta_idx] = compute_theoretical_max(a, y, beta, theory_grid_points, theory_tolerance);
647
  theoretical_min_values[beta_idx] = compute_theoretical_min(a, y, beta, theory_grid_points, theory_tolerance);
648
 
649
- // ─── Build T_n matrix ──────────────────────────────────
650
  int k = static_cast<int>(std::floor(beta * p));
651
  std::vector<double> diags(p, 1.0);
652
  std::fill_n(diags.begin(), k, a);
@@ -657,10 +515,10 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
657
  T_n.at<double>(i,i) = diags[i];
658
  }
659
 
660
- // ─── Form B_n = (1/n) * X * T_n * X^T ────────────
661
  cv::Mat B = (X.t() * T_n * X) / static_cast<double>(n);
662
 
663
- // ─── Compute eigenvalues of B ────────────────────────────
664
  cv::Mat eigVals;
665
  cv::eigen(B, eigVals);
666
  std::vector<double> eigs(n);
@@ -700,6 +558,314 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
700
  }
701
  }
702
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
703
  // Cubic equation analysis function
704
  bool cubicAnalysis(double a, double y, double beta, int num_points, double z_min, double z_max, const std::string& output_file) {
705
  std::cout << "Running cubic equation analysis with parameters: a = " << a
@@ -740,6 +906,7 @@ int main(int argc, char* argv[]) {
740
  if (argc < 2) {
741
  std::cerr << "Error: Missing mode argument." << std::endl;
742
  std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
 
743
  std::cerr << " or: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
744
  return 1;
745
  }
@@ -748,7 +915,7 @@ int main(int argc, char* argv[]) {
748
 
749
  try {
750
  if (mode == "eigenvalues") {
751
- // ─── Eigenvalue analysis mode ───────────────────────────────────────────
752
  if (argc != 10) {
753
  std::cerr << "Error: Incorrect number of arguments for eigenvalues mode." << std::endl;
754
  std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
@@ -769,8 +936,32 @@ int main(int argc, char* argv[]) {
769
  return 1;
770
  }
771
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
772
  } else if (mode == "cubic") {
773
- // ─── Cubic equation analysis mode ───────────────────────────────────────────
774
  if (argc != 9) {
775
  std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl;
776
  std::cerr << "Usage: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
@@ -792,7 +983,7 @@ int main(int argc, char* argv[]) {
792
 
793
  } else {
794
  std::cerr << "Error: Unknown mode: " << mode << std::endl;
795
- std::cerr << "Use 'eigenvalues' or 'cubic'" << std::endl;
796
  return 1;
797
  }
798
  }
 
1
+ // app.cpp - Modified version with improved cubic solver and fixed beta analysis
2
  #include <opencv2/opencv.hpp>
3
  #include <algorithm>
4
  #include <cmath>
 
281
  return roots;
282
  }
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  // Function to compute the theoretical max value
285
  double compute_theoretical_max(double a, double y, double beta, int grid_points, double tolerance) {
286
  auto f = [a, y, beta](double k) -> double {
 
472
  << ", theory_tolerance = " << theory_tolerance << std::endl;
473
  std::cout << "Output will be saved to: " << output_file << std::endl;
474
 
475
+ // ─── Beta range parameters ────────────────────────────────────────────────────────
476
  const int num_beta_points = fineness; // Controlled by fineness parameter
477
  std::vector<double> beta_values(num_beta_points);
478
  for (int i = 0; i < num_beta_points; ++i) {
479
  beta_values[i] = static_cast<double>(i) / (num_beta_points - 1);
480
  }
481
 
482
+ // ─── Storage for results ─────────────────────────────────────────────────────────
483
  std::vector<double> max_eigenvalues(num_beta_points);
484
  std::vector<double> min_eigenvalues(num_beta_points);
485
  std::vector<double> theoretical_max_values(num_beta_points);
486
  std::vector<double> theoretical_min_values(num_beta_points);
487
 
488
  try {
489
+ // ─── Random Gaussian X and S_n ─────────────────────────────────────────────
490
  std::random_device rd;
491
  std::mt19937_64 rng{rd()};
492
  std::normal_distribution<double> norm(0.0, 1.0);
 
496
  for(int j = 0; j < n; ++j)
497
  X.at<double>(i,j) = norm(rng);
498
 
499
+ // ─── Process each beta value ──────────────────────────────────────────────────
500
  for (int beta_idx = 0; beta_idx < num_beta_points; ++beta_idx) {
501
  double beta = beta_values[beta_idx];
502
 
 
504
  theoretical_max_values[beta_idx] = compute_theoretical_max(a, y, beta, theory_grid_points, theory_tolerance);
505
  theoretical_min_values[beta_idx] = compute_theoretical_min(a, y, beta, theory_grid_points, theory_tolerance);
506
 
507
+ // ─── Build T_n matrix ──────────────────────────────────────────────────
508
  int k = static_cast<int>(std::floor(beta * p));
509
  std::vector<double> diags(p, 1.0);
510
  std::fill_n(diags.begin(), k, a);
 
515
  T_n.at<double>(i,i) = diags[i];
516
  }
517
 
518
+ // ─── Form B_n = (1/n) * X * T_n * X^T ──────────────────────────
519
  cv::Mat B = (X.t() * T_n * X) / static_cast<double>(n);
520
 
521
+ // ─── Compute eigenvalues of B ─────────────────────────────────────
522
  cv::Mat eigVals;
523
  cv::eigen(B, eigVals);
524
  std::vector<double> eigs(n);
 
558
  }
559
  }
560
 
561
+ // Fixed beta eigenvalue analysis function
562
+ bool fixedBetaEigenvalueAnalysis(int n, int p, double y, double beta, double a_min, double a_max, int fineness,
563
+ int theory_grid_points, double theory_tolerance,
564
+ const std::string& output_file) {
565
+
566
+ std::cout << "Running fixed beta eigenvalue analysis with parameters: n = " << n << ", p = " << p
567
+ << ", y = " << y << ", beta = " << beta << ", a_min = " << a_min << ", a_max = " << a_max
568
+ << ", fineness = " << fineness
569
+ << ", theory_grid_points = " << theory_grid_points
570
+ << ", theory_tolerance = " << theory_tolerance << std::endl;
571
+ std::cout << "Output will be saved to: " << output_file << std::endl;
572
+
573
+ // ─── a range parameters ────────────────────────────────────────────────────────────
574
+ const int num_a_points = fineness; // Controlled by fineness parameter
575
+ std::vector<double> a_values(num_a_points);
576
+ for (int i = 0; i < num_a_points; ++i) {
577
+ a_values[i] = a_min + (a_max - a_min) * static_cast<double>(i) / (num_a_points - 1);
578
+ }
579
+
580
+ // ─── Storage for results ─────────────────────────────────────────────────────────
581
+ std::vector<double> max_eigenvalues(num_a_points);
582
+ std::vector<double> min_eigenvalues(num_a_points);
583
+ std::vector<double> theoretical_max_values(num_a_points);
584
+ std::vector<double> theoretical_min_values(num_a_points);
585
+
586
+ try {
587
+ // ─── Random Gaussian X and S_n ─────────────────────────────────────────────
588
+ std::random_device rd;
589
+ std::mt19937_64 rng{rd()};
590
+ std::normal_distribution<double> norm(0.0, 1.0);
591
+
592
+ cv::Mat X(p, n, CV_64F);
593
+ for(int i = 0; i < p; ++i)
594
+ for(int j = 0; j < n; ++j)
595
+ X.at<double>(i,j) = norm(rng);
596
+
597
+ // ─── Process each a value ──────────────────────────────────────────────────
598
+ for (int a_idx = 0; a_idx < num_a_points; ++a_idx) {
599
+ double a = a_values[a_idx];
600
+
601
+ // Compute theoretical values with customizable precision
602
+ theoretical_max_values[a_idx] = compute_theoretical_max(a, y, beta, theory_grid_points, theory_tolerance);
603
+ theoretical_min_values[a_idx] = compute_theoretical_min(a, y, beta, theory_grid_points, theory_tolerance);
604
+
605
+ // ─── Build T_n matrix ──────────────────────────────────────────────────
606
+ int k = static_cast<int>(std::floor(beta * p));
607
+ std::vector<double> diags(p, 1.0);
608
+ std::fill_n(diags.begin(), k, a);
609
+ std::shuffle(diags.begin(), diags.end(), rng);
610
+
611
+ cv::Mat T_n = cv::Mat::zeros(p, p, CV_64F);
612
+ for(int i = 0; i < p; ++i){
613
+ T_n.at<double>(i,i) = diags[i];
614
+ }
615
+
616
+ // ─── Form B_n = (1/n) * X * T_n * X^T ──────────────────────────
617
+ cv::Mat B = (X.t() * T_n * X) / static_cast<double>(n);
618
+
619
+ // ─── Compute eigenvalues of B ─────────────────────────────────────
620
+ cv::Mat eigVals;
621
+ cv::eigen(B, eigVals);
622
+ std::vector<double> eigs(n);
623
+ for(int i = 0; i < n; ++i)
624
+ eigs[i] = eigVals.at<double>(i, 0);
625
+
626
+ max_eigenvalues[a_idx] = *std::max_element(eigs.begin(), eigs.end());
627
+ min_eigenvalues[a_idx] = *std::min_element(eigs.begin(), eigs.end());
628
+
629
+ // Progress indicator for Streamlit
630
+ double progress = static_cast<double>(a_idx + 1) / num_a_points;
631
+ std::cout << "PROGRESS:" << progress << std::endl;
632
+
633
+ // Less verbose output for Streamlit
634
+ if (a_idx % 20 == 0 || a_idx == num_a_points - 1) {
635
+ std::cout << "Processing a = " << a
636
+ << " (" << a_idx+1 << "/" << num_a_points << ")" << std::endl;
637
+ }
638
+ }
639
+
640
+ // Save data as JSON for Python to read - use same format but with a_values instead of beta_values
641
+ std::ofstream outfile(output_file);
642
+
643
+ if (!outfile.is_open()) {
644
+ std::cerr << "Error: Could not open file " << output_file << " for writing." << std::endl;
645
+ return false;
646
+ }
647
+
648
+ // Helper function to format floating point values safely for JSON
649
+ auto formatJsonValue = [](double value) -> std::string {
650
+ if (std::isnan(value)) {
651
+ return "\"NaN\""; // JSON doesn't support NaN, so use string
652
+ } else if (std::isinf(value)) {
653
+ if (value > 0) {
654
+ return "\"Infinity\""; // JSON doesn't support Infinity, so use string
655
+ } else {
656
+ return "\"-Infinity\""; // JSON doesn't support -Infinity, so use string
657
+ }
658
+ } else {
659
+ // Use a fixed precision to avoid excessively long numbers
660
+ std::ostringstream oss;
661
+ oss << std::setprecision(15) << value;
662
+ return oss.str();
663
+ }
664
+ };
665
+
666
+ // Start JSON object
667
+ outfile << "{\n";
668
+
669
+ // Write a values (instead of beta values)
670
+ outfile << " \"a_values\": [";
671
+ for (size_t i = 0; i < a_values.size(); ++i) {
672
+ outfile << formatJsonValue(a_values[i]);
673
+ if (i < a_values.size() - 1) outfile << ", ";
674
+ }
675
+ outfile << "],\n";
676
+
677
+ // Write max eigenvalues
678
+ outfile << " \"max_eigenvalues\": [";
679
+ for (size_t i = 0; i < max_eigenvalues.size(); ++i) {
680
+ outfile << formatJsonValue(max_eigenvalues[i]);
681
+ if (i < max_eigenvalues.size() - 1) outfile << ", ";
682
+ }
683
+ outfile << "],\n";
684
+
685
+ // Write min eigenvalues
686
+ outfile << " \"min_eigenvalues\": [";
687
+ for (size_t i = 0; i < min_eigenvalues.size(); ++i) {
688
+ outfile << formatJsonValue(min_eigenvalues[i]);
689
+ if (i < min_eigenvalues.size() - 1) outfile << ", ";
690
+ }
691
+ outfile << "],\n";
692
+
693
+ // Write theoretical max values
694
+ outfile << " \"theoretical_max\": [";
695
+ for (size_t i = 0; i < theoretical_max_values.size(); ++i) {
696
+ outfile << formatJsonValue(theoretical_max_values[i]);
697
+ if (i < theoretical_max_values.size() - 1) outfile << ", ";
698
+ }
699
+ outfile << "],\n";
700
+
701
+ // Write theoretical min values
702
+ outfile << " \"theoretical_min\": [";
703
+ for (size_t i = 0; i < theoretical_min_values.size(); ++i) {
704
+ outfile << formatJsonValue(theoretical_min_values[i]);
705
+ if (i < theoretical_min_values.size() - 1) outfile << ", ";
706
+ }
707
+ outfile << "]\n";
708
+
709
+ // Close JSON object
710
+ outfile << "}\n";
711
+
712
+ outfile.close();
713
+
714
+ std::cout << "Data saved to " << output_file << std::endl;
715
+ return true;
716
+ }
717
+ catch (const std::exception& e) {
718
+ std::cerr << "Error in fixed beta eigenvalue analysis: " << e.what() << std::endl;
719
+ return false;
720
+ }
721
+ catch (...) {
722
+ std::cerr << "Unknown error in fixed beta eigenvalue analysis" << std::endl;
723
+ return false;
724
+ }
725
+ }
726
+
727
+ // Function to compute the cubic equation for Im(s) vs z
728
+ std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta, int num_points, double z_min, double z_max) {
729
+ std::vector<double> z_values(num_points);
730
+ std::vector<double> ims_values1(num_points);
731
+ std::vector<double> ims_values2(num_points);
732
+ std::vector<double> ims_values3(num_points);
733
+ std::vector<double> real_values1(num_points);
734
+ std::vector<double> real_values2(num_points);
735
+ std::vector<double> real_values3(num_points);
736
+
737
+ // Use z_min and z_max parameters
738
+ double z_start = std::max(0.01, z_min); // Avoid z=0 to prevent potential division issues
739
+ double z_end = z_max;
740
+ double z_step = (z_end - z_start) / (num_points - 1);
741
+
742
+ for (int i = 0; i < num_points; ++i) {
743
+ double z = z_start + i * z_step;
744
+ z_values[i] = z;
745
+
746
+ // Coefficients for the cubic equation:
747
+ // zas³ + [z(a+1)+a(1-y)]s² + [z+(a+1)-y-yβ(a-1)]s + 1 = 0
748
+ double coef_a = z * a;
749
+ double coef_b = z * (a + 1) + a * (1 - y);
750
+ double coef_c = z + (a + 1) - y - y * beta * (a - 1);
751
+ double coef_d = 1.0;
752
+
753
+ // Solve the cubic equation
754
+ CubicRoots roots = solveCubic(coef_a, coef_b, coef_c, coef_d);
755
+
756
+ // Extract imaginary and real parts
757
+ ims_values1[i] = std::abs(roots.root1.imag());
758
+ ims_values2[i] = std::abs(roots.root2.imag());
759
+ ims_values3[i] = std::abs(roots.root3.imag());
760
+
761
+ real_values1[i] = roots.root1.real();
762
+ real_values2[i] = roots.root2.real();
763
+ real_values3[i] = roots.root3.real();
764
+ }
765
+
766
+ // Create output vector, now including real values for better analysis
767
+ std::vector<std::vector<double>> result = {
768
+ z_values, ims_values1, ims_values2, ims_values3,
769
+ real_values1, real_values2, real_values3
770
+ };
771
+
772
+ return result;
773
+ }
774
+
775
+ // Function to save Im(s) vs z data as JSON
776
+ bool saveImSDataAsJSON(const std::string& filename,
777
+ const std::vector<std::vector<double>>& data) {
778
+ std::ofstream outfile(filename);
779
+
780
+ if (!outfile.is_open()) {
781
+ std::cerr << "Error: Could not open file " << filename << " for writing." << std::endl;
782
+ return false;
783
+ }
784
+
785
+ // Helper function to format floating point values safely for JSON
786
+ auto formatJsonValue = [](double value) -> std::string {
787
+ if (std::isnan(value)) {
788
+ return "\"NaN\""; // JSON doesn't support NaN, so use string
789
+ } else if (std::isinf(value)) {
790
+ if (value > 0) {
791
+ return "\"Infinity\""; // JSON doesn't support Infinity, so use string
792
+ } else {
793
+ return "\"-Infinity\""; // JSON doesn't support -Infinity, so use string
794
+ }
795
+ } else {
796
+ // Use a fixed precision to avoid excessively long numbers
797
+ std::ostringstream oss;
798
+ oss << std::setprecision(15) << value;
799
+ return oss.str();
800
+ }
801
+ };
802
+
803
+ // Start JSON object
804
+ outfile << "{\n";
805
+
806
+ // Write z values
807
+ outfile << " \"z_values\": [";
808
+ for (size_t i = 0; i < data[0].size(); ++i) {
809
+ outfile << formatJsonValue(data[0][i]);
810
+ if (i < data[0].size() - 1) outfile << ", ";
811
+ }
812
+ outfile << "],\n";
813
+
814
+ // Write Im(s) values for first root
815
+ outfile << " \"ims_values1\": [";
816
+ for (size_t i = 0; i < data[1].size(); ++i) {
817
+ outfile << formatJsonValue(data[1][i]);
818
+ if (i < data[1].size() - 1) outfile << ", ";
819
+ }
820
+ outfile << "],\n";
821
+
822
+ // Write Im(s) values for second root
823
+ outfile << " \"ims_values2\": [";
824
+ for (size_t i = 0; i < data[2].size(); ++i) {
825
+ outfile << formatJsonValue(data[2][i]);
826
+ if (i < data[2].size() - 1) outfile << ", ";
827
+ }
828
+ outfile << "],\n";
829
+
830
+ // Write Im(s) values for third root
831
+ outfile << " \"ims_values3\": [";
832
+ for (size_t i = 0; i < data[3].size(); ++i) {
833
+ outfile << formatJsonValue(data[3][i]);
834
+ if (i < data[3].size() - 1) outfile << ", ";
835
+ }
836
+ outfile << "],\n";
837
+
838
+ // Write Real(s) values for first root
839
+ outfile << " \"real_values1\": [";
840
+ for (size_t i = 0; i < data[4].size(); ++i) {
841
+ outfile << formatJsonValue(data[4][i]);
842
+ if (i < data[4].size() - 1) outfile << ", ";
843
+ }
844
+ outfile << "],\n";
845
+
846
+ // Write Real(s) values for second root
847
+ outfile << " \"real_values2\": [";
848
+ for (size_t i = 0; i < data[5].size(); ++i) {
849
+ outfile << formatJsonValue(data[5][i]);
850
+ if (i < data[5].size() - 1) outfile << ", ";
851
+ }
852
+ outfile << "],\n";
853
+
854
+ // Write Real(s) values for third root
855
+ outfile << " \"real_values3\": [";
856
+ for (size_t i = 0; i < data[6].size(); ++i) {
857
+ outfile << formatJsonValue(data[6][i]);
858
+ if (i < data[6].size() - 1) outfile << ", ";
859
+ }
860
+ outfile << "]\n";
861
+
862
+ // Close JSON object
863
+ outfile << "}\n";
864
+
865
+ outfile.close();
866
+ return true;
867
+ }
868
+
869
  // Cubic equation analysis function
870
  bool cubicAnalysis(double a, double y, double beta, int num_points, double z_min, double z_max, const std::string& output_file) {
871
  std::cout << "Running cubic equation analysis with parameters: a = " << a
 
906
  if (argc < 2) {
907
  std::cerr << "Error: Missing mode argument." << std::endl;
908
  std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
909
+ std::cerr << " or: " << argv[0] << " eigenvalues_fixed_beta <n> <p> <y> <beta> <a_min> <a_max> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
910
  std::cerr << " or: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
911
  return 1;
912
  }
 
915
 
916
  try {
917
  if (mode == "eigenvalues") {
918
+ // ─── Eigenvalue analysis mode ───────────────────────────────────────────────────────
919
  if (argc != 10) {
920
  std::cerr << "Error: Incorrect number of arguments for eigenvalues mode." << std::endl;
921
  std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
 
936
  return 1;
937
  }
938
 
939
+ } else if (mode == "eigenvalues_fixed_beta") {
940
+ // ─── Fixed beta eigenvalue analysis mode ────────────────────────────────────────────
941
+ if (argc != 12) {
942
+ std::cerr << "Error: Incorrect number of arguments for eigenvalues_fixed_beta mode." << std::endl;
943
+ std::cerr << "Usage: " << argv[0] << " eigenvalues_fixed_beta <n> <p> <y> <beta> <a_min> <a_max> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
944
+ std::cerr << "Received " << argc << " arguments, expected 12." << std::endl;
945
+ return 1;
946
+ }
947
+
948
+ int n = std::stoi(argv[2]);
949
+ int p = std::stoi(argv[3]);
950
+ double y = std::stod(argv[4]);
951
+ double beta = std::stod(argv[5]);
952
+ double a_min = std::stod(argv[6]);
953
+ double a_max = std::stod(argv[7]);
954
+ int fineness = std::stoi(argv[8]);
955
+ int theory_grid_points = std::stoi(argv[9]);
956
+ double theory_tolerance = std::stod(argv[10]);
957
+ std::string output_file = argv[11];
958
+
959
+ if (!fixedBetaEigenvalueAnalysis(n, p, y, beta, a_min, a_max, fineness, theory_grid_points, theory_tolerance, output_file)) {
960
+ return 1;
961
+ }
962
+
963
  } else if (mode == "cubic") {
964
+ // ─── Cubic equation analysis mode ──────────────────────────────────────────────────
965
  if (argc != 9) {
966
  std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl;
967
  std::cerr << "Usage: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
 
983
 
984
  } else {
985
  std::cerr << "Error: Unknown mode: " << mode << std::endl;
986
+ std::cerr << "Use 'eigenvalues', 'eigenvalues_fixed_beta', or 'cubic'" << std::endl;
987
  return 1;
988
  }
989
  }