Skip to content

Commit babe3a3

Browse files
authored
support recursive formulas (#191)
1 parent c1e22d5 commit babe3a3

18 files changed

+496
-188
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ To install or update LODA, please follow the [installation instructions](https:/
55
### Enhancements
66

77
* Support `mod`, `min` and `max` in formulas
8+
* Support recursive formulas for a small subset of IE programs
89
* Use `floor` instead of `truncate` in PARI if possible
910
* Add insecure fall-back option for `curl`
1011

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ifdef LODA_PLATFORM
88
CXXFLAGS += -DLODA_PLATFORM=$(LODA_PLATFORM)
99
endif
1010

11-
OBJS = api_client.o benchmark.o big_number.o blocks.o boinc.o commands.o config.o distribution.o evaluator.o evaluator_inc.o expression.o expression_util.o extender.o external/jute.o file.o finder.o formula.o generator.o generator_v1.o generator_v2.o generator_v3.o generator_v4.o generator_v5.o generator_v6.o generator_v7.o interpreter.o iterator.o log.o main.o matcher.o memory.o metrics.o miner.o minimizer.o mutator.o number.o oeis_list.o oeis_manager.o oeis_sequence.o optimizer.o pari.o parser.o process.o program.o program_util.o reducer.o semantics.o setup.o sequence.o stats.o test.o util.o web_client.o
11+
OBJS = api_client.o benchmark.o big_number.o blocks.o boinc.o commands.o config.o distribution.o evaluator.o evaluator_inc.o expression.o expression_util.o extender.o external/jute.o file.o finder.o formula.o formula_gen.o generator.o generator_v1.o generator_v2.o generator_v3.o generator_v4.o generator_v5.o generator_v6.o generator_v7.o interpreter.o iterator.o log.o main.o matcher.o memory.o metrics.o miner.o minimizer.o mutator.o number.o oeis_list.o oeis_manager.o oeis_sequence.o optimizer.o pari.o parser.o process.o program.o program_util.o reducer.o semantics.o setup.o sequence.o stats.o test.o util.o web_client.o
1212

1313
loda: external/jute.h external/jute.cpp $(OBJS)
1414
$(CXX) $(LDFLAGS) -o loda $(OBJS)

src/Makefile.windows.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ CXXFLAGS = $(CXXFLAGS) /Z7
1010
CXXFLAGS = $(CXXFLAGS) /DLODA_PLATFORM=$(LODA_PLATFORM)
1111
!ENDIF
1212

13-
SRCS = api_client.cpp benchmark.cpp big_number.cpp blocks.cpp boinc.cpp commands.cpp config.cpp distribution.cpp evaluator.cpp evaluator_inc.cpp expression.cpp expression_util.cpp extender.cpp external/jute.cpp file.cpp finder.cpp formula.cpp generator.cpp generator_v1.cpp generator_v2.cpp generator_v3.cpp generator_v4.cpp generator_v5.cpp generator_v6.cpp generator_v7.cpp interpreter.cpp iterator.cpp log.cpp main.cpp matcher.cpp memory.cpp metrics.cpp miner.cpp minimizer.cpp mutator.cpp number.cpp oeis_list.cpp oeis_manager.cpp oeis_sequence.cpp optimizer.cpp pari.cpp parser.cpp process.cpp program.cpp program_util.cpp reducer.cpp semantics.cpp sequence.cpp setup.cpp stats.cpp test.cpp util.cpp web_client.cpp
13+
SRCS = api_client.cpp benchmark.cpp big_number.cpp blocks.cpp boinc.cpp commands.cpp config.cpp distribution.cpp evaluator.cpp evaluator_inc.cpp expression.cpp expression_util.cpp extender.cpp external/jute.cpp file.cpp finder.cpp formula.cpp formula_gen.cpp generator.cpp generator_v1.cpp generator_v2.cpp generator_v3.cpp generator_v4.cpp generator_v5.cpp generator_v6.cpp generator_v7.cpp interpreter.cpp iterator.cpp log.cpp main.cpp matcher.cpp memory.cpp metrics.cpp miner.cpp minimizer.cpp mutator.cpp number.cpp oeis_list.cpp oeis_manager.cpp oeis_sequence.cpp optimizer.cpp pari.cpp parser.cpp process.cpp program.cpp program_util.cpp reducer.cpp semantics.cpp sequence.cpp setup.cpp stats.cpp test.cpp util.cpp web_client.cpp
1414

1515
loda: external/jute.h external/jute.cpp $(SRCS)
1616
cl /EHsc /Feloda.exe $(CXXFLAGS) $(SRCS)

src/commands.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "benchmark.hpp"
66
#include "boinc.hpp"
77
#include "evaluator.hpp"
8+
#include "evaluator_inc.hpp"
9+
#include "formula_gen.hpp"
810
#include "iterator.hpp"
911
#include "log.hpp"
1012
#include "miner.hpp"
@@ -192,17 +194,17 @@ void Commands::export_(const std::string& path) {
192194
Program program = parser.parse(getProgramPathAndSeqId(path).first);
193195
const auto& format = settings.export_format;
194196
if (format.empty() || format == "formula") {
195-
auto formula = Formula::fromProgram(program, false);
197+
auto formula = FormulaGenerator::generate(program, false);
196198
if (!formula.first) {
197199
throw std::runtime_error("program cannot be converted to formula");
198200
}
199-
std::cout << Pari::generate(formula.second) << std::endl;
201+
std::cout << formula.second.toString(false) << std::endl;
200202
} else if (format == "pari") {
201-
auto formula = Formula::fromProgram(program, true);
203+
auto formula = FormulaGenerator::generate(program, true);
202204
if (!formula.first) {
203205
throw std::runtime_error("program cannot be converted to pari");
204206
}
205-
std::cout << Pari::generate(formula.second) << std::endl;
207+
std::cout << formula.second.toString(true) << std::endl;
206208
} else if (format == "loda") {
207209
ProgramUtil::print(program, std::cout);
208210
} else {
@@ -299,7 +301,9 @@ void Commands::testPari() {
299301
initLog(false);
300302
Parser parser;
301303
Settings settings;
304+
Interpreter interpreter(settings);
302305
Evaluator evaluator(settings);
306+
IncrementalEvaluator inceval(interpreter);
303307
OeisManager manager(settings);
304308
manager.load();
305309
auto& stats = manager.getStats();
@@ -310,14 +314,18 @@ void Commands::testPari() {
310314
}
311315
auto seq = manager.getSequences().at(id);
312316
auto program = parser.parse(seq.getProgramPath());
313-
auto formula = Formula::fromProgram(program, true);
317+
auto formula = FormulaGenerator::generate(program, true);
314318
if (!formula.first) {
315319
continue;
316320
}
317-
Log::get().info(seq.id_str() + ": " + formula.second.toString());
321+
Log::get().info(seq.id_str() + ": " + formula.second.toString(true));
318322
Sequence expSeq;
319-
evaluator.eval(program, expSeq, seq.existingNumTerms());
320-
auto genSeq = Pari::eval(formula.second, 0, seq.existingNumTerms() - 1);
323+
size_t numTerms = seq.existingNumTerms();
324+
if (inceval.init(program)) {
325+
numTerms = std::min<size_t>(numTerms, 10);
326+
}
327+
evaluator.eval(program, expSeq, numTerms);
328+
auto genSeq = Pari::eval(formula.second, 0, numTerms - 1);
321329
if (genSeq != expSeq) {
322330
Log::get().info("Generated sequence: " + genSeq.to_string());
323331
Log::get().info("Expected sequence: " + expSeq.to_string());

src/expression.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ bool Expression::operator==(const Expression& e) const {
7777
case Expression::Type::FRACTION:
7878
case Expression::Type::POWER:
7979
case Expression::Type::MODULUS:
80+
case Expression::Type::IF:
8081
return equalChildren(e);
8182
}
8283
throw std::runtime_error("internal error"); // unreachable
@@ -106,12 +107,13 @@ bool Expression::operator<(const Expression& e) const {
106107
case Expression::Type::FRACTION:
107108
case Expression::Type::POWER:
108109
case Expression::Type::MODULUS:
110+
case Expression::Type::IF:
109111
return lessChildren(e);
110112
}
111113
throw std::runtime_error("internal error"); // unreachable
112114
}
113115

114-
bool Expression::contains(const Expression& e) {
116+
bool Expression::contains(const Expression& e) const {
115117
if (*this == e) {
116118
return true;
117119
}
@@ -123,6 +125,12 @@ bool Expression::contains(const Expression& e) {
123125
return false;
124126
}
125127

128+
void Expression::assertNumChildren(size_t num) const {
129+
if (children.size() != num) {
130+
throw std::runtime_error("unexpected number of children: " + toString());
131+
}
132+
}
133+
126134
bool Expression::equalChildren(const Expression& e) const {
127135
if (children.size() != e.children.size()) {
128136
return false;
@@ -207,6 +215,7 @@ void Expression::print(std::ostream& out, size_t index, bool isRoot,
207215
break;
208216
case Expression::Type::NEGATION:
209217
out << "-";
218+
assertNumChildren(1);
210219
children.front()->print(out, index, false, type);
211220
break;
212221
case Expression::Type::FUNCTION:
@@ -232,6 +241,12 @@ void Expression::print(std::ostream& out, size_t index, bool isRoot,
232241
case Expression::Type::MODULUS:
233242
printChildren(out, "%", isRoot, parentType);
234243
break;
244+
case Expression::Type::IF:
245+
assertNumChildren(3);
246+
out << name << "if(n==";
247+
printChildren(out, ",", isRoot, parentType);
248+
out << ")";
249+
break;
235250
}
236251
if (brackets) {
237252
out << ")";
@@ -253,6 +268,9 @@ bool Expression::needsBrackets(size_t index, bool isRoot,
253268
parentType == Expression::Type::FUNCTION) {
254269
return false;
255270
}
271+
if (type == Expression::Type::IF || parentType == Expression::Type::IF) {
272+
return false;
273+
}
256274
if (type == Expression::Type::NEGATION &&
257275
(parentType == Expression::Type::SUM ||
258276
parentType == Expression::Type::DIFFERENCE) &&

src/expression_util.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,6 @@ bool ExpressionUtil::normalize(Expression& e) {
178178
normalize(*c);
179179
}
180180
switch (e.type) {
181-
case Expression::Type::CONSTANT:
182-
case Expression::Type::PARAMETER:
183-
case Expression::Type::FUNCTION:
184-
case Expression::Type::NEGATION:
185-
case Expression::Type::POWER:
186-
case Expression::Type::MODULUS:
187-
break;
188181
case Expression::Type::SUM:
189182
if (e.children.size() > 1) { // at least two elements
190183
std::sort(e.children.rbegin(), e.children.rend(), compareExprPtr);
@@ -204,6 +197,8 @@ bool ExpressionUtil::normalize(Expression& e) {
204197
mergeAllChildren(e);
205198
}
206199
break;
200+
default:
201+
break;
207202
}
208203
if (pullUpChildren(e)) {
209204
normalize(e);
@@ -230,6 +225,7 @@ bool ExpressionUtil::canBeNegative(const Expression& e) {
230225
case Expression::Type::FRACTION:
231226
case Expression::Type::POWER:
232227
case Expression::Type::MODULUS:
228+
case Expression::Type::IF:
233229
for (auto c : e.children) {
234230
if (canBeNegative(*c)) {
235231
return true;

0 commit comments

Comments
 (0)