Skip to content

Commit 6e95b9e

Browse files
authored
use oeis offsets (#351)
1 parent 6443327 commit 6e95b9e

27 files changed

+235
-65
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ To install or update LODA, please follow the [installation instructions](https:/
22

33
## [Unreleased]
44

5+
## v24.11.29
6+
7+
### Features
8+
9+
* Support for sequence offsets (extracted from the OEIS)
10+
511
## v24.10.20
612

713
### Features

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ Targets:
4444
4545
Options:
4646
-t <number> Number of sequence terms (default: 8)
47-
-b Print result in b-file format from offset 0
48-
-B <number> Print result in b-file format from a custom offset
47+
-b Print result in the OEIS b-file format
4948
-o <string> Export format (formula,loda,pari-function,pari-vector)
5049
-d Export with dependencies to other programs
5150
-s Evaluate program to number of execution steps

src/cmd/commands.cpp

+3-6
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,7 @@ void Commands::help() {
9595
std::cout << std::endl << "Options:" << std::endl;
9696
std::cout << " -t <number> Number of sequence terms (default: "
9797
<< settings.num_terms << ")" << std::endl;
98-
std::cout
99-
<< " -b Print result in b-file format from offset 0"
100-
<< std::endl;
101-
std::cout << " -B <number> Print result in b-file format from a "
102-
"custom offset"
98+
std::cout << " -b Print result in the OEIS b-file format"
10399
<< std::endl;
104100
std::cout << " -o <string> Export format "
105101
"(formula,loda,pari-function,pari-vector)"
@@ -607,7 +603,8 @@ void Commands::testPari(const std::string& test_id) {
607603
}
608604

609605
// evaluate PARI program
610-
auto genSeq = pari_formula.eval(numTerms);
606+
auto offset = ProgramUtil::getOffset(program);
607+
auto genSeq = pari_formula.eval(offset, numTerms);
611608

612609
// compare results
613610
if (genSeq != expSeq) {

src/eval/evaluator.cpp

+11-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <sstream>
44

5+
#include "lang/program_util.hpp"
56
#include "sys/log.hpp"
67

78
steps_t::steps_t() : min(0), max(0), total(0), runs(0) {}
@@ -42,6 +43,7 @@ steps_t Evaluator::eval(const Program &p, Sequence &seq, int64_t num_terms,
4243
size_t s;
4344
const bool use_inc = use_inc_eval && inc_evaluator.init(p);
4445
std::pair<Number, size_t> inc_result;
46+
const int64_t offset = ProgramUtil::getOffset(p);
4547
for (int64_t i = 0; i < num_terms; i++) {
4648
try {
4749
if (use_inc) {
@@ -50,7 +52,7 @@ steps_t Evaluator::eval(const Program &p, Sequence &seq, int64_t num_terms,
5052
s = inc_result.second;
5153
} else {
5254
mem.clear();
53-
mem.set(Program::INPUT_CELL, i);
55+
mem.set(Program::INPUT_CELL, i + offset);
5456
s = interpreter.run(p, mem);
5557
seq[i] = mem.get(Program::OUTPUT_CELL);
5658
}
@@ -71,8 +73,7 @@ steps_t Evaluator::eval(const Program &p, Sequence &seq, int64_t num_terms,
7173
seq[i] = s;
7274
}
7375
if (settings.print_as_b_file) {
74-
std::cout << (settings.print_as_b_file_offset + i) << " " << seq[i]
75-
<< std::endl;
76+
std::cout << (offset + i) << " " << seq[i] << std::endl;
7677
}
7778
}
7879
if (is_debug) {
@@ -97,9 +98,10 @@ steps_t Evaluator::eval(const Program &p, std::vector<Sequence> &seqs,
9798
Memory mem;
9899
steps_t steps;
99100
// note: we can't use the incremental evaluator here
101+
const int64_t offset = ProgramUtil::getOffset(p);
100102
for (int64_t i = 0; i < num_terms; i++) {
101103
mem.clear();
102-
mem.set(Program::INPUT_CELL, i);
104+
mem.set(Program::INPUT_CELL, i + offset);
103105
steps.add(interpreter.run(p, mem));
104106
for (size_t s = 0; s < seqs.size(); s++) {
105107
seqs[s][i] = mem.get(s);
@@ -128,14 +130,15 @@ std::pair<status_t, steps_t> Evaluator::check(const Program &p,
128130
const bool use_inc = use_inc_eval && inc_evaluator.init(p);
129131
std::pair<Number, size_t> inc_result;
130132
Number out;
133+
const int64_t offset = ProgramUtil::getOffset(p);
131134
for (size_t i = 0; i < expected_seq.size(); i++) {
132135
try {
133136
if (use_inc) {
134137
inc_result = inc_evaluator.next();
135138
out = inc_result.first;
136139
} else {
137140
mem.clear();
138-
mem.set(Program::INPUT_CELL, i);
141+
mem.set(Program::INPUT_CELL, i + offset);
139142
result.second.add(interpreter.run(p, mem, id));
140143
out = mem.get(Program::OUTPUT_CELL);
141144
}
@@ -152,15 +155,14 @@ std::pair<status_t, steps_t> Evaluator::check(const Program &p,
152155
}
153156
if (out != expected_seq[i]) {
154157
if (settings.print_as_b_file) {
155-
std::cout << (settings.print_as_b_file_offset + i) << " " << out
156-
<< " -> expected " << expected_seq[i] << std::endl;
158+
std::cout << (offset + i) << " " << out << " -> expected "
159+
<< expected_seq[i] << std::endl;
157160
}
158161
result.first = status_t::ERROR;
159162
return result;
160163
}
161164
if (settings.print_as_b_file) {
162-
std::cout << (settings.print_as_b_file_offset + i) << " "
163-
<< expected_seq[i] << std::endl;
165+
std::cout << (offset + i) << " " << expected_seq[i] << std::endl;
164166
}
165167
}
166168
result.first = status_t::OK;

src/eval/evaluator_inc.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void IncrementalEvaluator::reset() {
2222
loop_counter_decrement = 0;
2323
loop_counter_lower_bound = 0;
2424
loop_counter_type = Operation::Type::NOP;
25+
offset = 0;
2526
initialized = false;
2627

2728
// runtime data
@@ -36,7 +37,7 @@ void IncrementalEvaluator::reset() {
3637
// ====== Initialization functions (static code analysis) =========
3738

3839
bool IncrementalEvaluator::init(const Program& program,
39-
bool skip_input_transform) {
40+
bool skip_input_transform, bool skip_offset) {
4041
reset();
4142
simple_loop = Analyzer::extractSimpleLoop(program);
4243
if (!simple_loop.is_simple_loop) {
@@ -65,6 +66,10 @@ bool IncrementalEvaluator::init(const Program& program,
6566
}
6667
return false;
6768
}
69+
// extract offset from program directive
70+
offset = skip_offset ? 0 : ProgramUtil::getOffset(program);
71+
72+
// initialue the runtime data
6873
initRuntimeData();
6974
initialized = true;
7075
if (is_debug) {
@@ -317,6 +322,7 @@ void IncrementalEvaluator::initRuntimeData() {
317322
loop_states.resize(loop_counter_decrement);
318323
previous_loop_counts.resize(loop_counter_decrement, 0);
319324
total_loop_steps.resize(loop_counter_decrement, 0);
325+
argument = offset;
320326
previous_slice = 0;
321327
}
322328

src/eval/evaluator_inc.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ class IncrementalEvaluator {
2727

2828
// Initialize the IE using a program. IE can be applied only if this function
2929
// returns true.
30-
bool init(const Program& program, bool skip_input_transform = false);
30+
bool init(const Program& program, bool skip_input_transform = false,
31+
bool skip_offset = false);
3132

3233
// Compute the next term and step count.
3334
std::pair<Number, size_t> next(bool skip_final_iter = false,
@@ -76,6 +77,7 @@ class IncrementalEvaluator {
7677
std::set<int64_t> loop_counter_dependent_cells;
7778
int64_t loop_counter_decrement;
7879
int64_t loop_counter_lower_bound;
80+
int64_t offset;
7981
Operation::Type loop_counter_type;
8082
bool initialized;
8183
const bool is_debug;

src/form/formula_gen.cpp

+16-8
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ bool FormulaGenerator::generateSingle(const Program& p) {
231231
return false;
232232
}
233233
const int64_t numCells = ProgramUtil::getLargestDirectMemoryCell(p) + 1;
234-
const bool useIncEval = incEval.init(p, true); // skip input transformations
234+
const bool useIncEval =
235+
incEval.init(p, true, true); // skip input transformations and offset
235236

236237
// initialize function names for memory cells
237238
cellNames.clear();
@@ -291,12 +292,13 @@ bool FormulaGenerator::generateSingle(const Program& p) {
291292
simplifyFormulaUsingVariants(formula, numTerms);
292293

293294
// evaluate program and add initial terms to formula
294-
if (!addInitialTerms(numCells, numTerms)) {
295+
const int64_t offset = ProgramUtil::getOffset(p);
296+
if (!addInitialTerms(numCells, offset, numTerms)) {
295297
return false;
296298
}
297299

298300
// prepare post-loop processing
299-
prepareForPostLoop(numCells, preloopExprs);
301+
prepareForPostLoop(numCells, offset, preloopExprs);
300302
Log::get().debug("Prepared post-loop: " + formula.toString());
301303

302304
// handle post-loop code
@@ -329,7 +331,8 @@ bool FormulaGenerator::generateSingle(const Program& p) {
329331
}
330332

331333
void FormulaGenerator::prepareForPostLoop(
332-
int64_t numCells, const std::map<int64_t, Expression>& preloopExprs) {
334+
int64_t numCells, int64_t offset,
335+
const std::map<int64_t, Expression>& preloopExprs) {
333336
// prepare post-loop processing
334337
auto preloopCounter = preloopExprs.at(incEval.getSimpleLoop().counter);
335338
for (int64_t cell = 0; cell < numCells; cell++) {
@@ -365,7 +368,8 @@ void FormulaGenerator::prepareForPostLoop(
365368
}
366369

367370
bool FormulaGenerator::addInitialTerms(
368-
int64_t numCells, const std::map<std::string, int64_t>& numTerms) {
371+
int64_t numCells, int64_t offset,
372+
const std::map<std::string, int64_t>& numTerms) {
369373
// calculate maximum offset
370374
int64_t maxNumTerms = 0;
371375
for (auto it : numTerms) {
@@ -374,7 +378,7 @@ bool FormulaGenerator::addInitialTerms(
374378
maxNumTerms = std::max(maxNumTerms, it.second);
375379
}
376380
// evaluate program and add initial terms to formula
377-
for (int64_t offset = 0; offset < maxNumTerms; offset++) {
381+
for (int64_t n = 0; n < maxNumTerms; n++) {
378382
try {
379383
incEval.next(true, true); // skip final iteration and post loop code
380384
} catch (const std::exception&) {
@@ -384,9 +388,13 @@ bool FormulaGenerator::addInitialTerms(
384388
const auto state = incEval.getLoopStates().at(incEval.getPreviousSlice());
385389
for (int64_t cell = 0; cell < numCells; cell++) {
386390
auto name = getCellName(cell);
387-
if (offset < numTerms.at(name)) {
391+
if (n < numTerms.at(name)) {
392+
auto arg = n;
393+
if (cell == Program::INPUT_CELL) {
394+
arg += offset;
395+
}
388396
Expression func(Expression::Type::FUNCTION, name,
389-
{ExpressionUtil::newConstant(offset)});
397+
{ExpressionUtil::newConstant(arg)});
390398
Expression val(Expression::Type::CONSTANT, "", state.get(cell));
391399
formula.entries[func] = val;
392400
Log::get().debug("Added intial term: " + func.toString() + " = " +

src/form/formula_gen.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ class FormulaGenerator {
3838

3939
bool update(const Program& p);
4040

41-
void prepareForPostLoop(int64_t numCells,
41+
void prepareForPostLoop(int64_t numCells, int64_t offset,
4242
const std::map<int64_t, Expression>& preloopExprs);
4343

44-
bool addInitialTerms(int64_t numCells,
44+
bool addInitialTerms(int64_t numCells, int64_t offset,
4545
const std::map<std::string, int64_t>& numTerms);
4646

4747
std::string newName();

src/form/pari.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ std::string PariFormula::toString() const {
129129
}
130130
}
131131

132-
void PariFormula::printEvalCode(int64_t numTerms, std::ostream& out) const {
132+
void PariFormula::printEvalCode(int64_t offset, int64_t numTerms,
133+
std::ostream& out) const {
133134
if (as_vector) {
134135
// declare vectors
135136
auto functions =
@@ -141,9 +142,8 @@ void PariFormula::printEvalCode(int64_t numTerms, std::ostream& out) const {
141142
// main function
142143
out << toString() << std::endl;
143144
}
144-
const int64_t start = 0;
145-
const int64_t end = numTerms - 1;
146-
out << "for(n=" << start << "," << end << ",";
145+
const int64_t end = offset + numTerms - 1;
146+
out << "for(n=" << offset << "," << end << ",";
147147
if (as_vector) {
148148
out << toString() << "; ";
149149
out << "print(a[n+1])";
@@ -153,15 +153,15 @@ void PariFormula::printEvalCode(int64_t numTerms, std::ostream& out) const {
153153
out << ")" << std::endl << "quit" << std::endl;
154154
}
155155

156-
Sequence PariFormula::eval(int64_t numTerms) const {
156+
Sequence PariFormula::eval(int64_t offset, int64_t numTerms) const {
157157
const std::string gpPath("pari-loda.gp");
158158
const std::string gpResult("pari-result.txt");
159159
const int64_t maxparisize = 256; // in MB
160160
std::ofstream gp(gpPath);
161161
if (!gp) {
162162
throw std::runtime_error("error generating gp file");
163163
}
164-
printEvalCode(numTerms, gp);
164+
printEvalCode(offset, numTerms, gp);
165165
gp.close();
166166
std::string cmd = "gp -s " + std::to_string(maxparisize) + "M -q " + gpPath +
167167
" > " + gpResult;

src/form/pari.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ class PariFormula {
2121
static bool convert(const Formula& formula, bool as_vector,
2222
PariFormula& pari_formula);
2323

24-
void printEvalCode(int64_t numTerms, std::ostream& out) const;
24+
void printEvalCode(int64_t offset, int64_t numTerms, std::ostream& out) const;
2525

2626
std::string toString() const;
2727

28-
Sequence eval(int64_t numTerms) const;
28+
Sequence eval(int64_t offset, int64_t numTerms) const;
2929

3030
private:
3131
Formula main_formula;

src/lang/parser.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ Program Parser::parse(const std::string &file) {
2020
}
2121

2222
Program Parser::parse(std::istream &in_) {
23-
const static std::set<std::string> valid_directives = {"inputs", "outputs"};
23+
const static std::set<std::string> valid_directives = {"inputs", "outputs",
24+
"offset"};
2425
in = &in_;
2526
Program p;
2627
Operation o;

src/lang/program_util.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,29 @@ std::string ProgramUtil::getProgramPath(int64_t id, const std::string &dir,
556556
return Setup::getProgramsHome() + dir + FILE_SEP + dirStr(id) + FILE_SEP +
557557
idStr(id, prefix) + ".asm";
558558
}
559+
560+
int64_t ProgramUtil::getOffset(const Program &p) {
561+
return p.getDirective("offset", 0);
562+
}
563+
564+
int64_t ProgramUtil::setOffset(Program &p, int64_t offset) {
565+
const int64_t current = p.getDirective("offset", 0);
566+
const int64_t delta = offset - current;
567+
if (delta > 0) {
568+
p.ops.insert(p.ops.begin(),
569+
Operation(Operation::Type::SUB,
570+
Operand(Operand::Type::DIRECT, Program::INPUT_CELL),
571+
Operand(Operand::Type::CONSTANT, delta)));
572+
} else if (delta < 0) {
573+
p.ops.insert(p.ops.begin(),
574+
Operation(Operation::Type::ADD,
575+
Operand(Operand::Type::DIRECT, Program::INPUT_CELL),
576+
Operand(Operand::Type::CONSTANT, -delta)));
577+
}
578+
if (offset != 0) {
579+
p.directives["offset"] = offset;
580+
} else {
581+
p.directives.erase("offset");
582+
}
583+
return delta;
584+
}

src/lang/program_util.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,8 @@ class ProgramUtil {
9090

9191
static std::string getProgramPath(int64_t id, const std::string &dir,
9292
const std::string &prefix);
93+
94+
static int64_t getOffset(const Program &p);
95+
96+
static int64_t setOffset(Program &p, int64_t offset);
9397
};

0 commit comments

Comments
 (0)