From 72df4ee31dc32ea0f07fc63136af8bef1e90fe98 Mon Sep 17 00:00:00 2001 From: Rayan Syed Date: Sat, 28 Mar 2026 22:52:11 -0400 Subject: [PATCH] more_tests --- ci_cd/.gitlab-ci.yml | 2 + ci_cd/problem3.yml | 71 ++++++++++- tests/Makefile | 20 ++- tests/impl/RefFullInteger.cpp | 36 ++++++ tests/include/RefFullInteger.h | 20 +++ tests/testEfficiencyFullInteger.cpp | 126 +++++++++++++++++++ tests/testMoreFullInteger.cpp | 189 ++++++++++++++++++++++++++++ 7 files changed, 458 insertions(+), 6 deletions(-) create mode 100644 tests/impl/RefFullInteger.cpp create mode 100644 tests/include/RefFullInteger.h create mode 100644 tests/testEfficiencyFullInteger.cpp create mode 100644 tests/testMoreFullInteger.cpp diff --git a/ci_cd/.gitlab-ci.yml b/ci_cd/.gitlab-ci.yml index 7782acc..17d66ea 100644 --- a/ci_cd/.gitlab-ci.yml +++ b/ci_cd/.gitlab-ci.yml @@ -2,7 +2,9 @@ stages: - prebuild - compile - test + - more - efficiency + - benchmark include: - local: 'ci_cd/problem3.yml' # FullInteger diff --git a/ci_cd/problem3.yml b/ci_cd/problem3.yml index c703015..aa7d10c 100644 --- a/ci_cd/problem3.yml +++ b/ci_cd/problem3.yml @@ -47,11 +47,78 @@ exec_problem_3: - if: '$CI_COMMIT_REF_NAME == "problem3"' tags: [c++-17] -benchmark: - stage: efficiency +more_problem_3: + stage: more needs: - job: exec_problem_3 artifacts: true + script: + - cd hw3/tests + - make more3 + - ./more3 > more3.txt + - score="$(tail -n 1 more3.txt | tr -d '[:space:]')" + - echo "$(cat more3.txt)" + - echo "More-test score is $score" + - STUDENT="$(echo "$CI_PROJECT_PATH" | sed -E 's#.*/HomeworkThree##')" + - curl "https://agile.bu.edu/ec330_scripts/saveScores.pl?key=${MAGIC_KEY}&file=hw3_more3&name=${STUDENT}&score=${score}" + artifacts: + paths: + - hw3/ + rules: + - if: '$CI_COMMIT_REF_NAME == "problem3"' + tags: [c++-17] + +efficiency_problem_3: + stage: efficiency + needs: + - job: more_problem_3 + artifacts: true + script: + - cd hw3/tests + - make efficiency3 + - set -o pipefail + - | + set +e + timeout 180s stdbuf -oL ./efficiency3 > efficiency3.out + STATUS=$? + set -e + + context="$(tail -n 20 efficiency3.out | tail -c 500)" + + if [ "$STATUS" -eq 124 ]; then + echo "Timeout!" + exit 1 + fi + if [ "$STATUS" -eq 134 ] || [ "$STATUS" -eq 137 ]; then + echo "Out of memory (status $STATUS) — aborted (134) or killed (137)" + echo "Context: $context" + exit 1 + fi + if [ "$STATUS" -ge 128 ] && [ "$STATUS" -le 192 ]; then + sig=$((STATUS - 128)) + echo "Crashed / terminated by signal $sig (exit $STATUS)" + echo "Context: $context" + exit 1 + fi + + score="$(tail -n 1 efficiency3.out | tr -d '[:space:]')" + - echo "$(cat efficiency3.out)" + - echo "Efficiency score is $score" + - STUDENT="$(echo "$CI_PROJECT_PATH" | sed -E 's#.*/HomeworkThree##')" + - curl "https://agile.bu.edu/ec330_scripts/saveScores.pl?key=${MAGIC_KEY}&file=hw3_eff3&name=${STUDENT}&score=${score}" + artifacts: + paths: + - hw3/ + rules: + - if: '$CI_COMMIT_REF_NAME == "problem3"' + timeout: 5m + tags: [c++-17] + +benchmark: + stage: benchmark + needs: + - job: efficiency_problem_3 + artifacts: true script: - git clone https://trachten-gitlab:${HW_INTERNAL}@agile.bu.edu/gitlab/ec330/ec330_staff/homeworks_internal/hw3_ec.git hw3_ec - cp impl/FullInteger.cpp hw3_ec/impl diff --git a/tests/Makefile b/tests/Makefile index b02d546..2657f95 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,23 +6,35 @@ CXXFLAGS = -std=c++17 # Source files PROBLEM3_SRCS = testFullInteger.cpp impl/FullInteger.cpp impl/IntegerPP.cpp impl/IntegerP.cpp impl/BigNum.cpp -SRCS = $(PROBLEM3_SRCS) +MORE3_SRCS = testMoreFullInteger.cpp impl/FullInteger.cpp impl/IntegerPP.cpp impl/IntegerP.cpp impl/BigNum.cpp +EFFICIENCY3_SRCS = testEfficiencyFullInteger.cpp impl/RefFullInteger.cpp impl/FullInteger.cpp impl/IntegerPP.cpp impl/IntegerP.cpp impl/BigNum.cpp +SRCS = $(PROBLEM3_SRCS) $(MORE3_SRCS) $(EFFICIENCY3_SRCS) # Object files PROBLEM3_OBJS = testFullInteger.o impl/FullInteger.o impl/IntegerPP.o impl/IntegerP.o impl/BigNum.o -OBJS = $(PROBLEM3_OBJS) +MORE3_OBJS = testMoreFullInteger.o impl/FullInteger.o impl/IntegerPP.o impl/IntegerP.o impl/BigNum.o +EFFICIENCY3_OBJS = testEfficiencyFullInteger.o impl/RefFullInteger.o impl/FullInteger.o impl/IntegerPP.o impl/IntegerP.o impl/BigNum.o +OBJS = $(PROBLEM3_OBJS) $(MORE3_OBJS) $(EFFICIENCY3_OBJS) # Executable name PROBLEM3_EXEC = problem3 -EXECS = $(PROBLEM3_EXEC) +MORE3_EXEC = more3 +EFFICIENCY3_EXEC = efficiency3 +EXECS = $(PROBLEM3_EXEC) $(MORE3_EXEC) $(EFFICIENCY3_EXEC) # Default target to build the executable -all: $(PROBLEM3_EXEC) +all: $(PROBLEM3_EXEC) $(MORE3_EXEC) $(EFFICIENCY3_EXEC) # Rule to build the executable from object files $(PROBLEM3_EXEC): $(PROBLEM3_OBJS) Makefile $(CXX) $(CXXFLAGS) -o $(PROBLEM3_EXEC) $(PROBLEM3_OBJS) +$(MORE3_EXEC): $(MORE3_OBJS) Makefile + $(CXX) $(CXXFLAGS) -o $(MORE3_EXEC) $(MORE3_OBJS) + +$(EFFICIENCY3_EXEC): $(EFFICIENCY3_OBJS) Makefile + $(CXX) $(CXXFLAGS) -o $(EFFICIENCY3_EXEC) $(EFFICIENCY3_OBJS) + # Rules to build object files from source files %.o: %.cpp Makefile $(CXX) $(CXXFLAGS) -c $< -o $@ diff --git a/tests/impl/RefFullInteger.cpp b/tests/impl/RefFullInteger.cpp new file mode 100644 index 0000000..ac53832 --- /dev/null +++ b/tests/impl/RefFullInteger.cpp @@ -0,0 +1,36 @@ +// +// Created by Ari on 2/22/26. +// + +#include +#include +#include +#include "../include/BigNum.h" +#include "../include/RefFullInteger.h" + +using namespace std; + +// forward declaration +unsigned int ithPrime(const size_t ii); + +bool RefFullInteger::operator<=(const FullInteger &other) const { + double myLog = 0.0; + auto myPrimes = primePowers(); + for (int ii=0; ii& nums, int largestPrimeFactor) { + std::sort(nums.begin(), nums.end()); +} \ No newline at end of file diff --git a/tests/include/RefFullInteger.h b/tests/include/RefFullInteger.h new file mode 100644 index 0000000..881f4c9 --- /dev/null +++ b/tests/include/RefFullInteger.h @@ -0,0 +1,20 @@ +// +// Created by Ari on 2/28/26. +// + +#ifndef HW3_EC_REFFULLINTEGER_H +#define HW3_EC_REFFULLINTEGER_H +#include "FullInteger.h" + +class RefFullInteger:public FullInteger { + public: + RefFullInteger() = default; + RefFullInteger(unsigned long n) : FullInteger(n) {} + RefFullInteger(std::initializer_list pBasis) : FullInteger(pBasis) {} + RefFullInteger(vector pBasis) { _primePowers = pBasis; } + RefFullInteger(const IntegerP& other) : FullInteger(other) {} + explicit RefFullInteger(const BigNum& num) : FullInteger(num) {} + bool operator<=(const FullInteger &other) const; + static void limitedSort(vector &nums, int largestPrimeFactor); +}; +#endif //HW3_EC_REFFULLINTEGER_H \ No newline at end of file diff --git a/tests/testEfficiencyFullInteger.cpp b/tests/testEfficiencyFullInteger.cpp new file mode 100644 index 0000000..460894b --- /dev/null +++ b/tests/testEfficiencyFullInteger.cpp @@ -0,0 +1,126 @@ +// Developed by Rayan 3/28/2026 + help from AI +// Speed-focused efficiency test for FullInteger + +#include +#include +#include +#include +#include +#include + +#include "include/FullInteger.h" + +using namespace std; + +using clock_type = chrono::steady_clock; +long totalMS = 0; + +int randInt(int low, int high) { + return rand() % (high - low) + low; +} + +bool isSorted(const vector& nums) { + for (size_t i = 1; i < nums.size(); i++) { + if (!(nums[i - 1] <= nums[i])) { + return false; + } + } + return true; +} + +vector make_two_powers(int n) { + vector result; + result.reserve(n); + for (int i = 0; i < n; i++) { + result.push_back(FullInteger({randInt(1, 250)})); + } + return result; +} + +vector make_bound5(int n) { + vector result; + result.reserve(n); + for (int i = 0; i < n; i++) { + result.push_back(FullInteger({ + randInt(0, 8), // exponent of 2 + randInt(0, 8), // exponent of 3 + randInt(0, 6) // exponent of 5 + })); + } + return result; +} + +vector make_duplicates(int n) { + vector pool; + pool.reserve(20); + + for (int i = 0; i < 20; i++) { + pool.push_back(FullInteger({ + randInt(0, 6), + randInt(0, 6), + randInt(0, 4) + })); + } + + vector result; + result.reserve(n); + for (int i = 0; i < n; i++) { + result.push_back(pool[randInt(0, (int)pool.size())]); + } + return result; +} + +bool run_test(const string& name, vector nums, int largestPrimeFactor) { + cout << "Starting " << name << "..." << endl; + + auto start = clock_type::now(); + FullInteger::limitedSort(nums, largestPrimeFactor); + auto end = clock_type::now(); + + long ms = chrono::duration_cast(end - start).count(); + totalMS += ms; + + if (!isSorted(nums)) { + cout << name << ": incorrect result!" << endl; + return false; + } + + cout << name << ": " << ms << " ms" << endl; + return true; +} + +int computeScore(long totalTimeMS) { + double adjusted = max(100.0, (double)totalMS); + double raw = 10.0 - 2.25 * log10(adjusted / 100.0); + int score = (int) llround(max(0.0, min(10.0, raw))); + return score; +} + +int main() { + srand(time(NULL)); + + cout << "Generating Powers of two (10k)..." << endl; + auto a = make_two_powers(10000); + if (!run_test("Powers of two (10k)", a, 2)) return -1; + + cout << "Generating Bound 5 random (10k)..." << endl; + auto b = make_bound5(10000); + if (!run_test("Bound 5 random (10k)", b, 5)) return -1; + + cout << "Generating Duplicate-heavy (10k)..." << endl; + auto c = make_duplicates(10000); + if (!run_test("Duplicate-heavy (10k)", c, 5)) return -1; + + cout << "Generating Bound 5 random (25k)..." << endl; + auto d = make_bound5(25000); + if (!run_test("Bound 5 random (25k)", d, 5)) return -1; + + int score = computeScore(totalMS); + + cout << "-------------------------------------" << endl; + cout << "Total time (ms): " << totalMS << endl; + cout << "Efficiency score: " << score << endl; + cout << score << endl; + + return 0; +} \ No newline at end of file diff --git a/tests/testMoreFullInteger.cpp b/tests/testMoreFullInteger.cpp new file mode 100644 index 0000000..af7aecc --- /dev/null +++ b/tests/testMoreFullInteger.cpp @@ -0,0 +1,189 @@ +// Developed by Rayan 3/28/2026 +// Harder "more" tests for FullInteger, using several 20-element sort cases + +#include +#include +#include + +#include "include/FullInteger.h" + +using namespace std; + +const float PTS = 1.0f; +float total = 0.0f; + +/** + * If expected == actual, increments the total by points. Prints information about what happened. + * @param category The category of test + * @param test The specific test + * @param expected Expected outcome + * @param actual Actual outcome + * @param points Points for a correct response. + */ +template +void scoreExample(string category, string test, T expected, T actual, float points) { + string score; + if (expected == actual) { + score = "CORRECT! +" + to_string(points); + total += points; + } else { + score = "incorrect: +0"; + } + cout << category << " - " << test << ": " << score << endl; +} + +static bool sameValues(const vector& a, const vector& b) { + if (a.size() != b.size()) return false; + for (size_t i = 0; i < a.size(); i++) { + if (!(a[i] == b[i])) return false; + } + return true; +} + +// 1) Equality +void test_a() { + const string CAT = "operator<= equality"; + scoreExample(CAT, "360 <= 360", true, (FullInteger(360) <= FullInteger(360)), PTS); +} + +// 2) Structural trap: powers with different bases +void test_b() { + const string CAT = "operator<= structural trap"; + scoreExample(CAT, "64 <= 81", true, (FullInteger(64) <= FullInteger(81)), PTS); +} + +// 3) Exponent-pattern trap +void test_c() { + const string CAT = "operator<= exponent-pattern trap"; + scoreExample(CAT, "72 <= 75", true, (FullInteger(72) <= FullInteger(75)), PTS); +} + +// 4) Nontrivial false +void test_d() { + const string CAT = "operator<= nontrivial false"; + scoreExample(CAT, "45 <= 32", false, (FullInteger(45) <= FullInteger(32)), PTS); +} + +// 5) Spec example +void test_e() { + const string CAT = "limitedSort spec example"; + + vector nums = {3,1,4,1,5,9}; + vector expected = {1,1,3,4,5,9}; + + FullInteger::limitedSort(nums, 5); + + scoreExample(CAT, "{3,1,4,1,5,9} -> {1,1,3,4,5,9}", true, sameValues(nums, expected), PTS); +} + +// 6) 20-element mixed case under bound 5 +void test_f() { + const string CAT = "limitedSort 20 mixed case"; + + vector nums = { + 45, 8, 27, 25, 18, 1, 12, 75, 64, 48, + 50, 54, 40, 81, 24, 125, 60, 72, 16, 96 + }; + + vector expected = { + 1, 8, 12, 16, 18, 24, 25, 27, 40, 45, + 48, 50, 54, 60, 64, 72, 75, 81, 96, 125 + }; + + FullInteger::limitedSort(nums, 5); + + scoreExample(CAT, "20 varied powers/composites", true, sameValues(nums, expected), PTS); +} + +// 7) Same 20 values in rough reverse order +void test_g() { + const string CAT = "limitedSort 20 reverse mixed"; + + vector nums = { + 125, 96, 81, 75, 72, 64, 60, 54, 50, 48, + 45, 40, 27, 25, 24, 18, 16, 12, 8, 1 + }; + + vector expected = { + 1, 8, 12, 16, 18, 24, 25, 27, 40, 45, + 48, 50, 54, 60, 64, 72, 75, 81, 96, 125 + }; + + FullInteger::limitedSort(nums, 5); + + scoreExample(CAT, "same 20 values reverse-ish", true, sameValues(nums, expected), PTS); +} + +// 8) 20-element duplicates and many 1s under bound 3 +void test_h() { + const string CAT = "limitedSort 20 duplicates/ones"; + + vector nums = { + 1, 12, 1, 8, 12, 1, 18, 8, 18, 1, + 24, 2, 3, 24, 6, 2, 3, 6, 9, 9 + }; + + vector expected = { + 1, 1, 1, 1, 2, 2, 3, 3, 6, 6, + 8, 8, 9, 9, 12, 12, 18, 18, 24, 24 + }; + + FullInteger::limitedSort(nums, 3); + + scoreExample(CAT, "20 elements with repeats and 1s", true, sameValues(nums, expected), PTS); +} + +// 9) 20-element exact-bound case with many 7-containing values +void test_i() { + const string CAT = "limitedSort 20 exact bound 7"; + + vector nums = { + 98, 49, 14, 63, 21, 7, 28, 42, 56, 70, + 84, 112, 126, 140, 147, 168, 175, 189, 196, 210 + }; + + vector expected = { + 7, 14, 21, 28, 42, 49, 56, 63, 70, 84, + 98, 112, 126, 140, 147, 168, 175, 189, 196, 210 + }; + + FullInteger::limitedSort(nums, 7); + + scoreExample(CAT, "20 values all within bound 7", true, sameValues(nums, expected), PTS); +} + +// 10) 20-element adversarial mixed structures under bound 5 +void test_j() { + const string CAT = "limitedSort 20 adversarial"; + + vector nums = { + 100, 32, 54, 20, 108, 125, 16, 45, 80, 24, + 90, 40, 75, 50, 12, 27, 60, 18, 72, 30 + }; + + vector expected = { + 12, 16, 18, 20, 24, 27, 30, 32, 40, 45, + 50, 54, 60, 72, 75, 80, 90, 100, 108, 125 + }; + + FullInteger::limitedSort(nums, 5); + + scoreExample(CAT, "20 adversarial varied factorizations", true, sameValues(nums, expected), PTS); +} + +int main() { + test_a(); + test_b(); + test_c(); + test_d(); + test_e(); + test_f(); + test_g(); + test_h(); + test_i(); + test_j(); + + cout << "Total points: " << total << endl; + cout << total << endl; // for CI score recorder + return 0; +} \ No newline at end of file -- GitLab