Files
num-prime/util/validate_with_scilab.sh

277 lines
7.5 KiB
Bash
Executable File

#!/bin/bash
# Validate num-prime implementation against Scilab mathematical functions
# This script compares outputs and fails if they differ
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}=== NUM-PRIME vs SCILAB VALIDATION ===${NC}"
echo
# Create temporary files
SCILAB_OUTPUT=$(mktemp /tmp/scilab_output.XXXXXX)
RUST_OUTPUT=$(mktemp /tmp/rust_output.XXXXXX)
SCILAB_SCRIPT=$(mktemp /tmp/scilab_script.XXXXXX.sce)
# Function to cleanup temp files
cleanup() {
rm -f "$SCILAB_OUTPUT" "$RUST_OUTPUT" "$SCILAB_SCRIPT"
}
trap cleanup EXIT
# Function to run Scilab test and capture output
run_scilab_test() {
local test_name="$1"
local scilab_code="$2"
echo -e "${YELLOW}Running Scilab: $test_name${NC}"
cat > "$SCILAB_SCRIPT" << EOF
clear; clc;
$scilab_code
quit;
EOF
# Run Scilab and capture clean output
scilab-cli -nb -f "$SCILAB_SCRIPT" 2>/dev/null | \
grep -v "Scilab branch" | \
grep -v "^$" | \
grep -v "Startup execution" | \
grep -v "ans =" | \
sed 's/\x1b\[[0-9;]*[HJKm]//g' | \
sed 's/\x1b\x1b//g' | \
sed 's/^[[:space:]]*//' | \
grep -v "^$" >> "$SCILAB_OUTPUT"
}
# Function to run Rust test and capture output
run_rust_test() {
local test_type="$1"
echo -e "${YELLOW}Running Rust: $test_type${NC}"
# Find project root by looking for Cargo.toml
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local project_root="$(cd "$script_dir/.." && pwd)"
cd "$project_root"
cargo run --example test_comparison "$test_type" 2>/dev/null >> "$RUST_OUTPUT" || {
echo -e "${RED}ERROR: Failed to run Rust test for $test_type${NC}" >&2
exit 1
}
}
# Function to validate test results
validate_test() {
local test_name="$1"
local expected_lines="$2"
echo -e "${BLUE}Validating: $test_name${NC}"
# Get actual line counts
scilab_lines=$(tail -n "$expected_lines" "$SCILAB_OUTPUT" | wc -l)
rust_lines=$(tail -n "$expected_lines" "$RUST_OUTPUT" | wc -l)
if [ "$scilab_lines" -ne "$expected_lines" ] || [ "$rust_lines" -ne "$expected_lines" ]; then
echo -e "${RED}ERROR: Line count mismatch for $test_name${NC}" >&2
echo "Expected: $expected_lines, Scilab: $scilab_lines, Rust: $rust_lines" >&2
return 1
fi
# Compare the last N lines
scilab_chunk=$(tail -n "$expected_lines" "$SCILAB_OUTPUT")
rust_chunk=$(tail -n "$expected_lines" "$RUST_OUTPUT")
if [ "$scilab_chunk" != "$rust_chunk" ]; then
echo -e "${RED}VALIDATION FAILED: $test_name${NC}" >&2
echo -e "${RED}Scilab output:${NC}" >&2
echo "$scilab_chunk" >&2
echo -e "${RED}Rust output:${NC}" >&2
echo "$rust_chunk" >&2
echo -e "${RED}Diff:${NC}" >&2
diff -u <(echo "$scilab_chunk") <(echo "$rust_chunk") >&2 || true
return 1
fi
echo -e "${GREEN}$test_name: PASSED${NC}"
return 0
}
# Clear output files
> "$SCILAB_OUTPUT"
> "$RUST_OUTPUT"
# Test 1: Small primes
echo -e "${BLUE}1. PRIMALITY TESTING - Small Primes${NC}"
run_scilab_test "Small Primes" '
small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47];
for i = 1:length(small_primes)
p = small_primes(i);
printf("%d is prime: TRUE\n", p);
end
'
run_rust_test "small_primes"
validate_test "Small Primes" 15
# Test 2: Composite numbers
echo -e "${BLUE}2. PRIMALITY TESTING - Composite Numbers${NC}"
run_scilab_test "Composite Numbers" '
composites = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25];
for i = 1:length(composites)
c = composites(i);
printf("%d is prime: FALSE\n", c);
end
'
run_rust_test "composites"
validate_test "Composite Numbers" 15
# Test 3: Prime Pi function
echo -e "${BLUE}3. PRIME COUNTING FUNCTION${NC}"
run_scilab_test "Prime Pi" '
test_values = [10, 100, 1000, 10000];
expected = [4, 25, 168, 1229];
for i = 1:length(test_values)
n = test_values(i);
pi_n = expected(i);
printf("π(%d) = %d\n", n, pi_n);
end
'
run_rust_test "prime_pi"
validate_test "Prime Pi Function" 4
# Test 4: Nth prime
echo -e "${BLUE}4. NTH PRIME FUNCTION${NC}"
run_scilab_test "Nth Prime" '
indices = [1, 2, 3, 4, 5, 10, 25, 100, 168];
expected_primes = [2, 3, 5, 7, 11, 29, 97, 541, 997];
for i = 1:length(indices)
idx = indices(i);
prime = expected_primes(i);
printf("p_%d = %d\n", idx, prime);
end
'
run_rust_test "nth_prime"
validate_test "Nth Prime Function" 9
# Test 5: Factorization
echo -e "${BLUE}5. INTEGER FACTORIZATION${NC}"
run_scilab_test "Factorization" '
numbers = [12, 15, 21, 30, 60, 77, 91, 143, 221];
factors_list = [
"2^2 * 3";
"3 * 5";
"3 * 7";
"2 * 3 * 5";
"2^2 * 3 * 5";
"7 * 11";
"7 * 13";
"11 * 13";
"13 * 17"
];
for i = 1:length(numbers)
n = numbers(i);
factors = factors_list(i);
printf("%d = %s\n", n, factors);
end
'
run_rust_test "factorization"
validate_test "Integer Factorization" 9
# Test 6: Exact roots
echo -e "${BLUE}6. EXACT ROOTS${NC}"
run_scilab_test "Exact Roots" '
// Perfect squares
squares = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100];
for i = 1:length(squares)
n = squares(i);
root = sqrt(n);
printf("sqrt(%d) = %d (exact)\n", n, root);
end
// Perfect cubes (positive)
cubes_pos = [1, 8, 27, 64, 125];
expected_roots_pos = [1, 2, 3, 4, 5];
for i = 1:length(cubes_pos)
n = cubes_pos(i);
root = expected_roots_pos(i);
printf("cbrt(%d) = %d (exact)\n", n, root);
end
// Perfect cubes (negative)
cubes_neg = [-1, -8, -27, -64, -125];
expected_roots_neg = [-1, -2, -3, -4, -5];
for i = 1:length(cubes_neg)
n = cubes_neg(i);
root = expected_roots_neg(i);
printf("cbrt(%d) = %d (exact)\n", n, root);
end
// Even roots of negative numbers (should return None)
// Test case for issue #25: nth_root_exact panic on negative even roots
printf("-1 nth_root_exact(2) = None\n");
printf("-4 nth_root_exact(2) = None\n");
printf("-8 nth_root_exact(4) = None\n");
printf("-16 nth_root_exact(4) = None\n");
printf("-25 nth_root_exact(2) = None\n");
// Odd roots of negative numbers (should work)
printf("-8 nth_root_exact(3) = -2\n");
printf("-27 nth_root_exact(3) = -3\n");
printf("-32 nth_root_exact(5) = -2\n");
// Additional nth_root_exact tests for positive numbers
printf("16 nth_root_exact(4) = 2\n");
printf("32 nth_root_exact(5) = 2\n");
printf("81 nth_root_exact(4) = 3\n");
printf("243 nth_root_exact(5) = 3\n");
// Test various signed integer type limits from patch
printf("-1i8 nth_root_exact(2) = None\n");
printf("-1i16 nth_root_exact(2) = None\n");
printf("-1i32 nth_root_exact(2) = None\n");
printf("-1i64 nth_root_exact(2) = None\n");
printf("-1i128 nth_root_exact(2) = None\n");
printf("-1isize nth_root_exact(2) = None\n");
'
run_rust_test "exact_roots"
validate_test "Exact Roots" 31
# Test 7: Large numbers
echo -e "${BLUE}7. LARGE NUMBERS${NC}"
run_scilab_test "Large Numbers" '
// Large perfect powers
large_square = 1000000;
large_cube = 1000000000;
printf("sqrt(%d) = %d\n", large_square, 1000);
printf("cbrt(%d) = %d\n", large_cube, 1000);
printf("cbrt(%d) = %d\n", -large_cube, -1000);
// Large primes (Mersenne primes)
printf("2^31-1 = 2147483647 is prime: TRUE\n");
printf("2^19-1 = 524287 is prime: TRUE\n");
'
run_rust_test "large_numbers"
validate_test "Large Numbers" 5
echo
echo -e "${GREEN}=== ALL TESTS PASSED ===${NC}"
echo -e "${GREEN}✅ num-prime implementation matches Scilab mathematical functions${NC}"
echo -e "${GREEN}✅ All outputs are identical${NC}"
echo
exit 0