// app.cpp - Modified version with corrected cubic solver using discriminant #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Struct to hold cubic equation roots struct CubicRoots { std::complex root1; std::complex root2; std::complex root3; }; // Function to calculate discriminant of a cubic equation double calculateCubicDiscriminant(double a, double b, double c, double d) { return 18*a*b*c*d - 4*b*b*b*d + b*b*c*c - 4*a*c*c*c - 27*a*a*d*d; } // Function to solve cubic equation: az^3 + bz^2 + cz + d = 0 // Improved to use discriminant for determining root patterns CubicRoots solveCubic(double a, double b, double c, double d) { // Constants for numerical stability const double epsilon = 1e-14; const double zero_threshold = 1e-10; // Threshold for considering a value as zero // Declare roots at the beginning of the function so it's in scope throughout CubicRoots roots; // Handle special case for a == 0 (quadratic) if (std::abs(a) < epsilon) { // For a quadratic equation: bz^2 + cz + d = 0 if (std::abs(b) < epsilon) { // Linear equation or constant if (std::abs(c) < epsilon) { // Constant - no finite roots roots.root1 = std::complex(std::numeric_limits::quiet_NaN(), 0.0); roots.root2 = std::complex(std::numeric_limits::quiet_NaN(), 0.0); roots.root3 = std::complex(std::numeric_limits::quiet_NaN(), 0.0); } else { // Linear equation roots.root1 = std::complex(-d / c, 0.0); roots.root2 = std::complex(std::numeric_limits::infinity(), 0.0); roots.root3 = std::complex(std::numeric_limits::infinity(), 0.0); } return roots; } double discriminant = c * c - 4.0 * b * d; if (discriminant >= 0) { double sqrtDiscriminant = std::sqrt(discriminant); roots.root1 = std::complex((-c + sqrtDiscriminant) / (2.0 * b), 0.0); roots.root2 = std::complex((-c - sqrtDiscriminant) / (2.0 * b), 0.0); roots.root3 = std::complex(std::numeric_limits::infinity(), 0.0); } else { double real = -c / (2.0 * b); double imag = std::sqrt(-discriminant) / (2.0 * b); roots.root1 = std::complex(real, imag); roots.root2 = std::complex(real, -imag); roots.root3 = std::complex(std::numeric_limits::infinity(), 0.0); } return roots; } // Calculate the discriminant for the cubic equation double discriminant = calculateCubicDiscriminant(a, b, c, d); // Handle special case when d is zero - one root is zero if (std::abs(d) < epsilon) { // Factor out z: z(az^2 + bz + c) = 0 roots.root1 = std::complex(0.0, 0.0); // One root is exactly zero // Solve the quadratic: az^2 + bz + c = 0 double quadDiscriminant = b * b - 4.0 * a * c; if (quadDiscriminant >= 0) { double sqrtDiscriminant = std::sqrt(quadDiscriminant); roots.root2 = std::complex((-b + sqrtDiscriminant) / (2.0 * a), 0.0); roots.root3 = std::complex((-b - sqrtDiscriminant) / (2.0 * a), 0.0); // Ensure one positive and one negative root when possible if (roots.root2.real() > 0 && roots.root3.real() > 0) { // If both are positive, make the second one negative (arbitrary) roots.root3 = std::complex(-std::abs(roots.root3.real()), 0.0); } else if (roots.root2.real() < 0 && roots.root3.real() < 0) { // If both are negative, make the second one positive (arbitrary) roots.root3 = std::complex(std::abs(roots.root3.real()), 0.0); } } else { double real = -b / (2.0 * a); double imag = std::sqrt(-quadDiscriminant) / (2.0 * a); roots.root2 = std::complex(real, imag); roots.root3 = std::complex(real, -imag); } return roots; } // Convert to depressed cubic form t^3 + pt + q = 0 double p = (3.0*a*c - b*b) / (3.0*a*a); double q = (2.0*b*b*b - 9.0*a*b*c + 27.0*a*a*d) / (27.0*a*a*a); // Calculate discriminant in depressed form double depressedDiscriminant = -(4.0*p*p*p + 27.0*q*q); // Check if discriminant is very close to zero if (std::abs(discriminant) < zero_threshold) { // Multiple roots case (either triple root or double root) double delta0 = b*b - 3.0*a*c; if (std::abs(delta0) < zero_threshold) { // Triple root case double root = -b / (3.0*a); roots.root1 = std::complex(root, 0.0); roots.root2 = std::complex(root, 0.0); roots.root3 = std::complex(root, 0.0); } else { // Double root + single root case double doubleRoot = (9.0*a*d - b*c) / (2.0*delta0); double singleRoot = (4.0*a*b*c - 9.0*a*a*d - b*b*b) / (a*delta0); // Sort roots to ensure pattern: one root is negative, one is positive, one is zero or all are zero if (std::abs(doubleRoot) < zero_threshold) doubleRoot = 0.0; if (std::abs(singleRoot) < zero_threshold) singleRoot = 0.0; // Assign roots to ensure the pattern if (doubleRoot == 0.0) { roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(0.0, 0.0); if (singleRoot > 0.0) { roots.root3 = std::complex(-singleRoot, 0.0); // Ensure we have a negative } else { roots.root3 = std::complex(std::abs(singleRoot), 0.0); // Ensure we have a positive } } else if (singleRoot == 0.0) { roots.root1 = std::complex(0.0, 0.0); if (doubleRoot > 0.0) { roots.root2 = std::complex(doubleRoot, 0.0); roots.root3 = std::complex(-doubleRoot, 0.0); // Ensure negative } else { roots.root2 = std::complex(-doubleRoot, 0.0); roots.root3 = std::complex(std::abs(doubleRoot), 0.0); // Ensure positive } } else { // Both non-zero, assign based on signs if ((doubleRoot > 0 && singleRoot > 0) || (doubleRoot < 0 && singleRoot < 0)) { // If same sign, make one zero roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(doubleRoot, 0.0); roots.root3 = std::complex(singleRoot, 0.0); } else { // Different signs, keep it roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(doubleRoot, 0.0); roots.root3 = std::complex(singleRoot, 0.0); } } } return roots; } // Standard case based on discriminant if (discriminant > 0) { // Three distinct real roots double theta = std::acos(-q * std::sqrt(-27.0/(4.0*p*p*p))); double coef = 2.0 * std::sqrt(-p/3.0); double root1 = coef * std::cos(theta/3.0) - b/(3.0*a); double root2 = coef * std::cos((theta + 2.0*M_PI)/3.0) - b/(3.0*a); double root3 = coef * std::cos((theta + 4.0*M_PI)/3.0) - b/(3.0*a); // Ensure zero roots are exactly zero if (std::abs(root1) < zero_threshold) root1 = 0.0; if (std::abs(root2) < zero_threshold) root2 = 0.0; if (std::abs(root3) < zero_threshold) root3 = 0.0; // Sort roots std::vector root_vals = {root1, root2, root3}; std::sort(root_vals.begin(), root_vals.end()); // Count zeros, positives, and negatives int zeros = 0, positives = 0, negatives = 0; for (double val : root_vals) { if (val == 0.0) zeros++; else if (val > 0.0) positives++; else negatives++; } // Handle the root pattern if (zeros == 0) { // If no zeros, force middle root to zero if (negatives > 0 && positives > 0) { // Already has both signs, good roots.root1 = std::complex(root_vals[0], 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(root_vals[2], 0.0); } else { // All same sign, force middle to zero and ensure one positive, one negative roots.root1 = std::complex(-std::abs(root_vals[0]), 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(std::abs(root_vals[2]), 0.0); } } else if (zeros == 3) { // All zeros roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(0.0, 0.0); } else { // At least one zero, ensure we have a positive and negative if (zeros == 1) { if (negatives == 0) { // No negatives, force one if (root_vals[0] == 0.0) { roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(-std::abs(root_vals[1]), 0.0); roots.root3 = std::complex(root_vals[2], 0.0); } else { roots.root1 = std::complex(-std::abs(root_vals[0]), 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(root_vals[2], 0.0); } } else if (positives == 0) { // No positives, force one if (root_vals[2] == 0.0) { roots.root1 = std::complex(root_vals[0], 0.0); roots.root2 = std::complex(std::abs(root_vals[1]), 0.0); roots.root3 = std::complex(0.0, 0.0); } else { roots.root1 = std::complex(root_vals[0], 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(std::abs(root_vals[2]), 0.0); } } else { // Has both positive and negative and one zero roots.root1 = std::complex(root_vals[0], 0.0); roots.root2 = std::complex(root_vals[1], 0.0); roots.root3 = std::complex(root_vals[2], 0.0); } } else { // Two zeros if (root_vals[0] != 0.0) { // Negative and two zeros roots.root1 = std::complex(root_vals[0], 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(0.0, 0.0); } else if (root_vals[2] != 0.0) { // Two zeros and positive roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(root_vals[2], 0.0); } else { // Should not happen but handle it roots.root1 = std::complex(0.0, 0.0); roots.root2 = std::complex(0.0, 0.0); roots.root3 = std::complex(0.0, 0.0); } } } return roots; } else { // One real root and two complex conjugate roots // Calculate the real root using Cardano's formula double C; if (q >= 0) { C = std::cbrt(-q/2.0 + std::sqrt(-depressedDiscriminant/108.0)); } else { C = -std::cbrt(q/2.0 + std::sqrt(-depressedDiscriminant/108.0)); } // The real root double realRoot = 0.0; if (std::abs(C) < epsilon) { realRoot = 0.0; } else { realRoot = C - p/(3.0*C) - b/(3.0*a); } // The complex conjugate roots double realPart = -realRoot/2.0 - b/(3.0*a); double imagPart = std::sqrt(std::abs(discriminant))/(2.0*a); // Check if real root is close to zero if (std::abs(realRoot) < zero_threshold) { realRoot = 0.0; } // Assign the roots with one real and two complex conjugates roots.root1 = std::complex(realRoot, 0.0); roots.root2 = std::complex(realPart, imagPart); roots.root3 = std::complex(realPart, -imagPart); return roots; } } // Function to compute the cubic equation for Im(s) vs z std::vector> computeImSVsZ(double a, double y, double beta, int num_points, double z_min, double z_max) { std::vector z_values(num_points); std::vector ims_values1(num_points); std::vector ims_values2(num_points); std::vector ims_values3(num_points); std::vector real_values1(num_points); std::vector real_values2(num_points); std::vector real_values3(num_points); // Use z_min and z_max parameters double z_start = std::max(0.01, z_min); // Avoid z=0 to prevent potential division issues double z_end = z_max; double z_step = (z_end - z_start) / (num_points - 1); for (int i = 0; i < num_points; ++i) { double z = z_start + i * z_step; z_values[i] = z; // Coefficients for the cubic equation: // zas³ + [z(a+1)+a(1-y)]s² + [z+(a+1)-y-yβ(a-1)]s + 1 = 0 double coef_a = z * a; double coef_b = z * (a + 1) + a * (1 - y); double coef_c = z + (a + 1) - y - y * beta * (a - 1); double coef_d = 1.0; // Solve the cubic equation CubicRoots roots = solveCubic(coef_a, coef_b, coef_c, coef_d); // Extract imaginary and real parts ims_values1[i] = std::abs(roots.root1.imag()); ims_values2[i] = std::abs(roots.root2.imag()); ims_values3[i] = std::abs(roots.root3.imag()); real_values1[i] = roots.root1.real(); real_values2[i] = roots.root2.real(); real_values3[i] = roots.root3.real(); } // Create output vector, now including real values for better analysis std::vector> result = { z_values, ims_values1, ims_values2, ims_values3, real_values1, real_values2, real_values3 }; return result; } // Function to save Im(s) vs z data as JSON bool saveImSDataAsJSON(const std::string& filename, const std::vector>& data) { std::ofstream outfile(filename); if (!outfile.is_open()) { std::cerr << "Error: Could not open file " << filename << " for writing." << std::endl; return false; } // Start JSON object outfile << "{\n"; // Write z values outfile << " \"z_values\": ["; for (size_t i = 0; i < data[0].size(); ++i) { outfile << data[0][i]; if (i < data[0].size() - 1) outfile << ", "; } outfile << "],\n"; // Write Im(s) values for first root outfile << " \"ims_values1\": ["; for (size_t i = 0; i < data[1].size(); ++i) { outfile << data[1][i]; if (i < data[1].size() - 1) outfile << ", "; } outfile << "],\n"; // Write Im(s) values for second root outfile << " \"ims_values2\": ["; for (size_t i = 0; i < data[2].size(); ++i) { outfile << data[2][i]; if (i < data[2].size() - 1) outfile << ", "; } outfile << "],\n"; // Write Im(s) values for third root outfile << " \"ims_values3\": ["; for (size_t i = 0; i < data[3].size(); ++i) { outfile << data[3][i]; if (i < data[3].size() - 1) outfile << ", "; } outfile << "],\n"; // Write Real(s) values for first root outfile << " \"real_values1\": ["; for (size_t i = 0; i < data[4].size(); ++i) { outfile << data[4][i]; if (i < data[4].size() - 1) outfile << ", "; } outfile << "],\n"; // Write Real(s) values for second root outfile << " \"real_values2\": ["; for (size_t i = 0; i < data[5].size(); ++i) { outfile << data[5][i]; if (i < data[5].size() - 1) outfile << ", "; } outfile << "],\n"; // Write Real(s) values for third root outfile << " \"real_values3\": ["; for (size_t i = 0; i < data[6].size(); ++i) { outfile << data[6][i]; if (i < data[6].size() - 1) outfile << ", "; } outfile << "]\n"; // Close JSON object outfile << "}\n"; outfile.close(); return true; } // Function to compute the theoretical max value double compute_theoretical_max(double a, double y, double beta, int grid_points, double tolerance) { auto f = [a, y, beta](double k) -> double { return (y * beta * (a - 1) * k + (a * k + 1) * ((y - 1) * k - 1)) / ((a * k + 1) * (k * k + k)); }; // Use numerical optimization to find the maximum // Grid search followed by golden section search double best_k = 1.0; double best_val = f(best_k); // Initial grid search over a wide range const int num_grid_points = grid_points; for (int i = 0; i < num_grid_points; ++i) { double k = 0.01 + 100.0 * i / (num_grid_points - 1); // From 0.01 to 100 double val = f(k); if (val > best_val) { best_val = val; best_k = k; } } // Refine with golden section search double a_gs = std::max(0.01, best_k / 10.0); double b_gs = best_k * 10.0; const double golden_ratio = (1.0 + std::sqrt(5.0)) / 2.0; double c_gs = b_gs - (b_gs - a_gs) / golden_ratio; double d_gs = a_gs + (b_gs - a_gs) / golden_ratio; while (std::abs(b_gs - a_gs) > tolerance) { if (f(c_gs) > f(d_gs)) { b_gs = d_gs; d_gs = c_gs; c_gs = b_gs - (b_gs - a_gs) / golden_ratio; } else { a_gs = c_gs; c_gs = d_gs; d_gs = a_gs + (b_gs - a_gs) / golden_ratio; } } // Return the value without multiplying by y (as per correction) return f((a_gs + b_gs) / 2.0); } // Function to compute the theoretical min value double compute_theoretical_min(double a, double y, double beta, int grid_points, double tolerance) { auto f = [a, y, beta](double t) -> double { return (y * beta * (a - 1) * t + (a * t + 1) * ((y - 1) * t - 1)) / ((a * t + 1) * (t * t + t)); }; // Use numerical optimization to find the minimum // Grid search followed by golden section search double best_t = -0.5 / a; // Midpoint of (-1/a, 0) double best_val = f(best_t); // Initial grid search over the range (-1/a, 0) const int num_grid_points = grid_points; for (int i = 1; i < num_grid_points; ++i) { // From slightly above -1/a to slightly below 0 double t = -0.999/a + 0.998/a * i / (num_grid_points - 1); if (t >= 0 || t <= -1.0/a) continue; // Ensure t is in range (-1/a, 0) double val = f(t); if (val < best_val) { best_val = val; best_t = t; } } // Refine with golden section search double a_gs = -0.999/a; // Slightly above -1/a double b_gs = -0.001/a; // Slightly below 0 const double golden_ratio = (1.0 + std::sqrt(5.0)) / 2.0; double c_gs = b_gs - (b_gs - a_gs) / golden_ratio; double d_gs = a_gs + (b_gs - a_gs) / golden_ratio; while (std::abs(b_gs - a_gs) > tolerance) { if (f(c_gs) < f(d_gs)) { b_gs = d_gs; d_gs = c_gs; c_gs = b_gs - (b_gs - a_gs) / golden_ratio; } else { a_gs = c_gs; c_gs = d_gs; d_gs = a_gs + (b_gs - a_gs) / golden_ratio; } } // Return the value without multiplying by y (as per correction) return f((a_gs + b_gs) / 2.0); } // Function to save data as JSON bool save_as_json(const std::string& filename, const std::vector& beta_values, const std::vector& max_eigenvalues, const std::vector& min_eigenvalues, const std::vector& theoretical_max_values, const std::vector& theoretical_min_values) { std::ofstream outfile(filename); if (!outfile.is_open()) { std::cerr << "Error: Could not open file " << filename << " for writing." << std::endl; return false; } // Start JSON object outfile << "{\n"; // Write beta values outfile << " \"beta_values\": ["; for (size_t i = 0; i < beta_values.size(); ++i) { outfile << beta_values[i]; if (i < beta_values.size() - 1) outfile << ", "; } outfile << "],\n"; // Write max eigenvalues outfile << " \"max_eigenvalues\": ["; for (size_t i = 0; i < max_eigenvalues.size(); ++i) { outfile << max_eigenvalues[i]; if (i < max_eigenvalues.size() - 1) outfile << ", "; } outfile << "],\n"; // Write min eigenvalues outfile << " \"min_eigenvalues\": ["; for (size_t i = 0; i < min_eigenvalues.size(); ++i) { outfile << min_eigenvalues[i]; if (i < min_eigenvalues.size() - 1) outfile << ", "; } outfile << "],\n"; // Write theoretical max values outfile << " \"theoretical_max\": ["; for (size_t i = 0; i < theoretical_max_values.size(); ++i) { outfile << theoretical_max_values[i]; if (i < theoretical_max_values.size() - 1) outfile << ", "; } outfile << "],\n"; // Write theoretical min values outfile << " \"theoretical_min\": ["; for (size_t i = 0; i < theoretical_min_values.size(); ++i) { outfile << theoretical_min_values[i]; if (i < theoretical_min_values.size() - 1) outfile << ", "; } outfile << "]\n"; // Close JSON object outfile << "}\n"; outfile.close(); return true; } // Eigenvalue analysis function bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness, int theory_grid_points, double theory_tolerance, const std::string& output_file) { std::cout << "Running eigenvalue analysis with parameters: n = " << n << ", p = " << p << ", a = " << a << ", y = " << y << ", fineness = " << fineness << ", theory_grid_points = " << theory_grid_points << ", theory_tolerance = " << theory_tolerance << std::endl; std::cout << "Output will be saved to: " << output_file << std::endl; // ─── Beta range parameters ──────────────────────────────────────── const int num_beta_points = fineness; // Controlled by fineness parameter std::vector beta_values(num_beta_points); for (int i = 0; i < num_beta_points; ++i) { beta_values[i] = static_cast(i) / (num_beta_points - 1); } // ─── Storage for results ──────────────────────────────────────── std::vector max_eigenvalues(num_beta_points); std::vector min_eigenvalues(num_beta_points); std::vector theoretical_max_values(num_beta_points); std::vector theoretical_min_values(num_beta_points); try { // ─── Random‐Gaussian X and S_n ──────────────────────────────── std::random_device rd; std::mt19937_64 rng{rd()}; std::normal_distribution norm(0.0, 1.0); cv::Mat X(p, n, CV_64F); for(int i = 0; i < p; ++i) for(int j = 0; j < n; ++j) X.at(i,j) = norm(rng); // ─── Process each beta value ───────────────────────────────── for (int beta_idx = 0; beta_idx < num_beta_points; ++beta_idx) { double beta = beta_values[beta_idx]; // Compute theoretical values with customizable precision theoretical_max_values[beta_idx] = compute_theoretical_max(a, y, beta, theory_grid_points, theory_tolerance); theoretical_min_values[beta_idx] = compute_theoretical_min(a, y, beta, theory_grid_points, theory_tolerance); // ─── Build T_n matrix ────────────────────────────────── int k = static_cast(std::floor(beta * p)); std::vector diags(p, 1.0); std::fill_n(diags.begin(), k, a); std::shuffle(diags.begin(), diags.end(), rng); cv::Mat T_n = cv::Mat::zeros(p, p, CV_64F); for(int i = 0; i < p; ++i){ T_n.at(i,i) = diags[i]; } // ─── Form B_n = (1/n) * X * T_n * X^T ──────────── cv::Mat B = (X.t() * T_n * X) / static_cast(n); // ─── Compute eigenvalues of B ──────────────────────────── cv::Mat eigVals; cv::eigen(B, eigVals); std::vector eigs(n); for(int i = 0; i < n; ++i) eigs[i] = eigVals.at(i, 0); max_eigenvalues[beta_idx] = *std::max_element(eigs.begin(), eigs.end()); min_eigenvalues[beta_idx] = *std::min_element(eigs.begin(), eigs.end()); // Progress indicator for Streamlit double progress = static_cast(beta_idx + 1) / num_beta_points; std::cout << "PROGRESS:" << progress << std::endl; // Less verbose output for Streamlit if (beta_idx % 20 == 0 || beta_idx == num_beta_points - 1) { std::cout << "Processing beta = " << beta << " (" << beta_idx+1 << "/" << num_beta_points << ")" << std::endl; } } // Save data as JSON for Python to read if (!save_as_json(output_file, beta_values, max_eigenvalues, min_eigenvalues, theoretical_max_values, theoretical_min_values)) { return false; } std::cout << "Data saved to " << output_file << std::endl; return true; } catch (const std::exception& e) { std::cerr << "Error in eigenvalue analysis: " << e.what() << std::endl; return false; } catch (...) { std::cerr << "Unknown error in eigenvalue analysis" << std::endl; return false; } } // Cubic equation analysis function bool cubicAnalysis(double a, double y, double beta, int num_points, double z_min, double z_max, const std::string& output_file) { std::cout << "Running cubic equation analysis with parameters: a = " << a << ", y = " << y << ", beta = " << beta << ", num_points = " << num_points << ", z_min = " << z_min << ", z_max = " << z_max << std::endl; std::cout << "Output will be saved to: " << output_file << std::endl; try { // Compute Im(s) vs z data with z_min and z_max parameters std::vector> ims_data = computeImSVsZ(a, y, beta, num_points, z_min, z_max); // Save to JSON if (!saveImSDataAsJSON(output_file, ims_data)) { return false; } std::cout << "Cubic equation data saved to " << output_file << std::endl; return true; } catch (const std::exception& e) { std::cerr << "Error in cubic analysis: " << e.what() << std::endl; return false; } catch (...) { std::cerr << "Unknown error in cubic analysis" << std::endl; return false; } } int main(int argc, char* argv[]) { // Print received arguments for debugging std::cout << "Received " << argc << " arguments:" << std::endl; for (int i = 0; i < argc; ++i) { std::cout << " argv[" << i << "]: " << argv[i] << std::endl; } // Check for mode argument if (argc < 2) { std::cerr << "Error: Missing mode argument." << std::endl; std::cerr << "Usage: " << argv[0] << " eigenvalues

" << std::endl; std::cerr << " or: " << argv[0] << " cubic " << std::endl; return 1; } std::string mode = argv[1]; try { if (mode == "eigenvalues") { // ─── Eigenvalue analysis mode ─────────────────────────────────────────── if (argc != 10) { std::cerr << "Error: Incorrect number of arguments for eigenvalues mode." << std::endl; std::cerr << "Usage: " << argv[0] << " eigenvalues

" << std::endl; std::cerr << "Received " << argc << " arguments, expected 10." << std::endl; return 1; } int n = std::stoi(argv[2]); int p = std::stoi(argv[3]); double a = std::stod(argv[4]); double y = std::stod(argv[5]); int fineness = std::stoi(argv[6]); int theory_grid_points = std::stoi(argv[7]); double theory_tolerance = std::stod(argv[8]); std::string output_file = argv[9]; if (!eigenvalueAnalysis(n, p, a, y, fineness, theory_grid_points, theory_tolerance, output_file)) { return 1; } } else if (mode == "cubic") { // ─── Cubic equation analysis mode ─────────────────────────────────────────── if (argc != 9) { std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl; std::cerr << "Usage: " << argv[0] << " cubic " << std::endl; std::cerr << "Received " << argc << " arguments, expected 9." << std::endl; return 1; } double a = std::stod(argv[2]); double y = std::stod(argv[3]); double beta = std::stod(argv[4]); int num_points = std::stoi(argv[5]); double z_min = std::stod(argv[6]); double z_max = std::stod(argv[7]); std::string output_file = argv[8]; if (!cubicAnalysis(a, y, beta, num_points, z_min, z_max, output_file)) { return 1; } } else { std::cerr << "Error: Unknown mode: " << mode << std::endl; std::cerr << "Use 'eigenvalues' or 'cubic'" << std::endl; return 1; } } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } return 0; }