# ----------------------------------------------------------------------------- # Test Suite for sm.conjugate_gradient # ----------------------------------------------------------------------------- # Helper function for asserting tests test_case <- function(name, expr) { cat("--- Running Test: '", name, "' ---\n", sep = "") result <- try(expr, silent = TRUE) if (inherits(result, "try-error")) { cat("❌ FAILED: ", name, "\n Error: ", trimws(as.character(result)), "\n", sep = "") return(FALSE) } else if (is.logical(result) && !result) { cat("❌ FAILED: ", name, "\n Assertion returned FALSE.\n", sep = "") return(FALSE) } else { cat("✅ PASSED: ", name, "\n", sep = "") return(TRUE) } } # ----------------------------------------------------------------------------- # 1. Quadratic Function Test (Exact Alpha) # ----------------------------------------------------------------------------- test_case("Quadratic Function (Exact Alpha) - Convergence and Accuracy", { Theta <- matrix(c(4, 1, 1, 3), nrow = 2) b <- c(1, 2) f_quad <- function(x) 0.5 * t(x) %*% Theta %*% x - t(b) %*% x x_expected <- c(1/11, 7/11) res_quad <- sm.conjugate_gradient( f = f_quad, x0 = c(0, 0), Theta = Theta, alpha_method = "exact", alpha_values = NULL, tol = 1e-8, max_iter = 100, verbose = TRUE ) all( res_quad$converged, res_quad$iterations <= 2, # CG should converge in N steps all(abs(res_quad$x_min - x_expected) < 1e-6) ) }) # ----------------------------------------------------------------------------- # 2. General Function Test (Armijo Line Search) # ----------------------------------------------------------------------------- test_case("General Function (Armijo Alpha) - Convergence and Accuracy", { f_gen <- function(x) x[1]^2 + x[2]^2 + x[1] * x[2] x_expected <- c(0, 0) res_gen <- sm.conjugate_gradient( f = f_gen, x0 = c(5, -5), Theta = NULL, alpha_method = "armijo", alpha_values = NULL, tol = 1e-6, max_iter = 100 ) all( res_gen$converged, all(abs(res_gen$x_min - x_expected) < 1e-5), res_gen$f_min < 1e-10 ) }) # ----------------------------------------------------------------------------- # 3. Error Handling Test (Theta missing for Exact Alpha) # ----------------------------------------------------------------------------- test_case("Error Handling - Missing Theta for Exact Alpha", { f_dummy <- function(x) x[1]^2 error_occurred <- tryCatch({ sm.conjugate_gradient(f_dummy, x0 = c(1), Theta = NULL, alpha_method = "exact") FALSE }, error = function(e) { grepl("Theta must be provided for exact alpha calculation", conditionMessage(e)) }) error_occurred }) # ----------------------------------------------------------------------------- # 4. Max Iteration Limit Test (Non-Convergence) # ----------------------------------------------------------------------------- test_case("Max Iteration Limit - Non-Convergence", { Theta <- matrix(c(4, 1, 1, 3), nrow = 2) b <- c(1, 2) f_quad <- function(x) 0.5 * t(x) %*% Theta %*% x - t(b) %*% x res_limit <- sm.conjugate_gradient( f = f_quad, x0 = c(0, 0), Theta = Theta, alpha_method = "exact", alpha_values = NULL, tol = 1e-10, max_iter = 1 ) all( !res_limit$converged, res_limit$iterations == 1 ) }) # ----------------------------------------------------------------------------- # 5. Iteration Data Frame Structure Check # ----------------------------------------------------------------------------- test_case("Iteration Data Frame (iter_df) Structure Check", { Theta <- matrix(c(4, 1, 1, 3), nrow = 2) b <- c(1, 2) f_quad <- function(x) 0.5 * t(x) %*% Theta %*% x - t(b) %*% x res_quad <- sm.conjugate_gradient( f = f_quad, x0 = c(0, 0), Theta = Theta, alpha_method = "exact", alpha_values = NULL ) df <- res_quad$iter_df expected_cols <- c("iteration", "x1", "x2", "grad_norm", "alpha_k", "beta_k", "f_val", "d1", "d2") all( is.data.frame(df), ncol(df) == length(expected_cols), all(names(df) == expected_cols) ) }) # ----------------------------------------------------------------------------- # 6. Verbose Output Test (Code Path Execution) # ----------------------------------------------------------------------------- test_case("Verbose Output - Code Path Execution", { Theta <- matrix(c(4, 1, 1, 3), nrow = 2) b <- c(1, 2) f_quad <- function(x) 0.5 * t(x) %*% Theta %*% x - t(b) %*% x res_verbose <- suppressMessages( sm.conjugate_gradient( f = f_quad, x0 = c(0, 0), Theta = Theta, alpha_method = "exact", alpha_values = NULL, tol = 1e-10, max_iter = 1, verbose = TRUE ) ) !res_verbose$converged }) cat("\n--- All Tests Complete ---\n")