diff --git a/README.md b/README.md index be934e68..531a5d29 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Options: -t Number of sequence terms (default: 8) -b Print result in b-file format from offset 0 -B Print result in b-file format from a custom offset - -o Export format (formula,loda,pari) + -o Export format (formula,loda,pari-function,pari-vector) -d Export with dependencies to other programs -s Evaluate program to number of execution steps -c Maximum number of interpreter cycles (no limit: -1) diff --git a/src/cmd/commands.cpp b/src/cmd/commands.cpp index 79b21fc5..b908e09e 100644 --- a/src/cmd/commands.cpp +++ b/src/cmd/commands.cpp @@ -100,7 +100,8 @@ void Commands::help() { std::cout << " -B Print result in b-file format from a " "custom offset" << std::endl; - std::cout << " -o Export format (formula,loda,pari)" + std::cout << " -o Export format " + "(formula,loda,pari-function,pari-vector)" << std::endl; std::cout << " -d Export with dependencies to other programs" @@ -218,7 +219,7 @@ void Commands::export_(const std::string& path) { throwConversionError(format); } std::cout << formula.toString() << std::endl; - } else if (format == "pari") { + } else if (format == "pari-function" || format == "pari") { if (!generator.generate(program, -1, formula, settings.with_deps) || !PariFormula::convert(formula, false, pari_formula)) { throwConversionError(format); diff --git a/src/cmd/test.cpp b/src/cmd/test.cpp index 699578da..75c1c5a5 100644 --- a/src/cmd/test.cpp +++ b/src/cmd/test.cpp @@ -61,7 +61,6 @@ void Test::all() { checkpoint(); knownPrograms(); formula(); - pariEval(); // slow tests number(); @@ -886,8 +885,14 @@ void Test::memUsage() { } void Test::formula() { + checkFormulas("formula.txt", FormulaType::FORMULA); + checkFormulas("pari-function.txt", FormulaType::PARI_FUNCTION); + checkFormulas("pari-vector.txt", FormulaType::PARI_VECTOR); +} + +void Test::checkFormulas(const std::string& testFile, FormulaType type) { std::string path = std::string("tests") + FILE_SEP + std::string("formula") + - FILE_SEP + std::string("program-formula.txt"); + FILE_SEP + testFile; std::map map; OeisList::loadMapWithComments(path, map); if (map.empty()) { @@ -895,7 +900,7 @@ void Test::formula() { } Parser parser; FormulaGenerator generator; - for (auto& e : map) { + for (const auto& e : map) { OeisSequence seq(e.first); Log::get().info("Testing formula for " + seq.id_str() + ": " + e.second); auto p = parser.parse(seq.getProgramPath()); @@ -903,75 +908,20 @@ void Test::formula() { if (!generator.generate(p, seq.id, f, true)) { Log::get().error("Cannot generate formula from program", true); } - if (f.toString() != e.second) { - Log::get().error("Unexpected formula: " + f.toString(), true); - } - } -} - -void Test::pariEval() { - auto base_path = - std::string("tests") + FILE_SEP + std::string("formula") + FILE_SEP; - testPariEval(base_path + "program-pari-recursive.txt", false); - testPariEval(base_path + "program-pari-vector.txt", true); -} - -void testPariEvalCode(const std::string& seq_id, - const std::string& expected_eval_code, bool asVector) { - Log::get().info("Testing PARI/GP " + - std::string((asVector ? "vector" : "recursive")) + - " code for " + seq_id); - Parser parser; - FormulaGenerator generator; - OeisSequence seq(seq_id); - auto program = parser.parse(seq.getProgramPath()); - Formula f; - PariFormula pari; - if (!generator.generate(program, seq.id, f, true)) { - Log::get().error("Cannot generate formula from program", true); - } - if (!PariFormula::convert(f, asVector, pari)) { - Log::get().error("Cannot convert formula to PARI/GP", true); - } - std::stringstream eval_code; - pari.printEvalCode(10, eval_code); - if (eval_code.str() != expected_eval_code) { - Log::get().error("Unexpected PARI/GP code: " + eval_code.str(), true); - } -} - -void Test::testPariEval(const std::string& testFile, bool asVector) { - std::ifstream file(testFile); - if (!file.is_open()) { - Log::get().error("Cannot open test file: " + testFile, true); - } - std::string line, seq_id, expected_eval_code; - Parser parser; - FormulaGenerator generator; - size_t num_tests = 0; - while (std::getline(file, line)) { - if (line.empty()) { - if (!seq_id.empty()) { - testPariEvalCode(seq_id, expected_eval_code, asVector); - seq_id.clear(); - expected_eval_code.clear(); - num_tests++; + if (type == FormulaType::FORMULA) { + if (f.toString() != e.second) { + Log::get().error("Unexpected formula: " + f.toString(), true); } - } else if (line.substr(0, 2) == "\\\\") { - seq_id = line.substr(2); - trimString(seq_id); - expected_eval_code.clear(); } else { - expected_eval_code += line + "\n"; + PariFormula pari; + if (!PariFormula::convert(f, type == FormulaType::PARI_VECTOR, pari)) { + Log::get().error("Cannot convert formula to PARI/GP", true); + } + if (pari.toString() != e.second) { + Log::get().error("Unexpected PARI/GP code: " + pari.toString(), true); + } } } - if (!seq_id.empty()) { - testPariEvalCode(seq_id, expected_eval_code, asVector); - num_tests++; - } - if (num_tests == 0) { - Log::get().error("No tests found in file: " + testFile, true); - } } void Test::stats() { diff --git a/src/cmd/test.hpp b/src/cmd/test.hpp index 6bb01ea6..08227477 100644 --- a/src/cmd/test.hpp +++ b/src/cmd/test.hpp @@ -68,7 +68,9 @@ class Test { void formula(); - void pariEval(); + enum class FormulaType { FORMULA, PARI_FUNCTION, PARI_VECTOR }; + + void checkFormulas(const std::string &testFile, FormulaType type); private: std::vector> loadInOutTests( diff --git a/src/form/pari.cpp b/src/form/pari.cpp index 48af8ac3..bb0ef668 100644 --- a/src/form/pari.cpp +++ b/src/form/pari.cpp @@ -113,8 +113,23 @@ bool PariFormula::convert(const Formula& formula, bool as_vector, std::string PariFormula::toString() const { if (as_vector) { - return main_formula.toString("; ", false) + "; " + - initial_terms.toString("; ", false); + std::stringstream buf; + auto sorted = main_formula.getDefinitions(Expression::Type::VECTOR, true); + for (size_t i = 0; i < sorted.size(); i++) { + const auto& f = sorted.at(i); + auto key = ExpressionUtil::newFunction(f); + key.type = Expression::Type::VECTOR; + if (i > 0) { + buf << "; "; + } + if (max_initial_terms.find(f) != max_initial_terms.end()) { + buf << "if(n>" << max_initial_terms.at(f) << ", "; + buf << f << "[n] = " << main_formula.entries.at(key).toString() << ")"; + } else { + buf << f << "[n] = " << main_formula.entries.at(key).toString() << ""; + } + } + return buf.str(); } else { return main_formula.toString("; ", true); } @@ -131,24 +146,13 @@ void PariFormula::printEvalCode(int64_t numTerms, std::ostream& out) const { out << initial_terms.toString("\n", false) << std::endl; } else { // main function - out << main_formula.toString("; ", true) << std::endl; + out << toString() << std::endl; } const int64_t start = as_vector ? 1 : 0; const int64_t end = numTerms + start - 1; out << "for(n=" << start << "," << end << ","; if (as_vector) { - auto sorted = main_formula.getDefinitions(Expression::Type::VECTOR, true); - for (const auto& f : sorted) { - auto key = ExpressionUtil::newFunction(f); - key.type = Expression::Type::VECTOR; - if (max_initial_terms.find(f) != max_initial_terms.end()) { - out << "if(n>" << max_initial_terms.at(f) << ", "; - out << f << "[n] = " << main_formula.entries.at(key).toString() - << "); "; - } else { - out << f << "[n] = " << main_formula.entries.at(key).toString() << "; "; - } - } + out << toString() << "; "; out << "print(a[n])"; } else { out << "print(a(n))"; diff --git a/tests/formula/program-formula.txt b/tests/formula/formula.txt similarity index 100% rename from tests/formula/program-formula.txt rename to tests/formula/formula.txt diff --git a/tests/formula/pari-function.txt b/tests/formula/pari-function.txt new file mode 100644 index 00000000..99498987 --- /dev/null +++ b/tests/formula/pari-function.txt @@ -0,0 +1 @@ +A000058: (a(n) = b(n)+1); (b(n) = if(n==0,1,local(l1=b(n-1)); l1*(l1+1))) diff --git a/tests/formula/pari-vector.txt b/tests/formula/pari-vector.txt new file mode 100644 index 00000000..b3613f93 --- /dev/null +++ b/tests/formula/pari-vector.txt @@ -0,0 +1 @@ +A000058: if(n>1, b[n] = b[n-1]*(b[n-1]+1)); a[n] = b[n]+1 diff --git a/tests/formula/program-pari-recursive.txt b/tests/formula/program-pari-recursive.txt deleted file mode 100644 index d321ad89..00000000 --- a/tests/formula/program-pari-recursive.txt +++ /dev/null @@ -1,4 +0,0 @@ -\\ A000058 -(a(n) = b(n)+1); (b(n) = if(n==0,1,local(l1=b(n-1)); l1*(l1+1))) -for(n=0,9,print(a(n))) -quit diff --git a/tests/formula/program-pari-vector.txt b/tests/formula/program-pari-vector.txt deleted file mode 100644 index 52686b0d..00000000 --- a/tests/formula/program-pari-vector.txt +++ /dev/null @@ -1,6 +0,0 @@ -\\ A000058 -a = vector(10) -b = vector(10) -b[1] = 1 -for(n=1,10,if(n>1, b[n] = b[n-1]*(b[n-1]+1)); a[n] = b[n]+1; print(a[n])) -quit