Skip to content

Commit 930e6c2

Browse files
authored
support fac in formula generation (#460)
1 parent 6ad50ba commit 930e6c2

File tree

9 files changed

+69
-17
lines changed

9 files changed

+69
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ To install or update LODA, please follow the [installation instructions](https:/
22

33
## [Unreleased]
44

5+
### Enhancements
6+
7+
* Support `fac` in formula generation
8+
59
### v25.9.26
610

711
### Enhancements

src/cmd/test.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -771,12 +771,12 @@ void Test::incEval() {
771771
i++;
772772
}
773773
// OEIS sequence test cases
774-
std::vector<size_t> ids = {
775-
8, 45, 142, 165, 178, 204, 246, 253, 278,
776-
280, 407, 542, 933, 1075, 1091, 1117, 1304, 1353,
777-
1360, 1519, 1541, 1542, 1609, 2081, 3411, 7661, 7981,
778-
8581, 10362, 11218, 12866, 14979, 22564, 25774, 49349, 57552,
779-
79309, 80493, 122593, 130487, 247309, 302643};
774+
std::vector<size_t> ids = {8, 45, 142, 178, 204, 246, 253,
775+
278, 280, 407, 542, 933, 1075, 1091,
776+
1117, 1304, 1353, 1360, 1519, 1541, 1542,
777+
1609, 2081, 3411, 7661, 7981, 8581, 10362,
778+
11218, 12866, 14979, 22564, 25774, 49349, 57552,
779+
79309, 80493, 122593, 130487, 247309, 302643};
780780
for (auto id : ids) {
781781
checkEvaluator(settings, id, "", EVAL_INCREMENTAL, true);
782782
}

src/form/expression.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,9 @@ bool Expression::needsBrackets(bool isRoot, Expression::Type parentType) const {
370370
return false;
371371
}
372372
if (type == Expression::Type::FACTORIAL &&
373-
parentType == Expression::Type::FACTORIAL) {
373+
(parentType == Expression::Type::FACTORIAL ||
374+
parentType == Expression::Type::PRODUCT ||
375+
parentType == Expression::Type::SUM)) {
374376
return false;
375377
}
376378
if (parentType == Expression::Type::FACTORIAL && !isRoot) {

src/form/formula_gen.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,43 @@ bool FormulaGenerator::bitfunc(Operation::Type type, const Expression& a,
113113
return true;
114114
}
115115

116+
// Express falling/rising factorial using standard factorial
117+
bool FormulaGenerator::facToExpression(const Expression& a,
118+
const Expression& b, Expression& res) const {
119+
120+
if (ExpressionUtil::canBeNegative(a, offset) ||
121+
ExpressionUtil::canBeNegative(b, offset)) {
122+
return false;
123+
}
124+
125+
Expression num(Expression::Type::FACTORIAL);
126+
Expression denom(Expression::Type::FACTORIAL);
127+
// Falling factorial: a!/(a+b)!
128+
// If b <= 0: (a)!/(a+b)!
129+
// If b > 0: rising factorial: (a+b-1)!/(a-1)!
130+
if (b.type == Expression::Type::CONSTANT && b.value <= 0) {
131+
// falling factorial
132+
num.children = {a};
133+
denom.children = {sum({a, b})};
134+
} else {
135+
// rising factorial
136+
// (a+b-1)!/(a-1)!
137+
num.children = {sum({a, sum({b, constant(-1)})})};
138+
denom.children = {sum({a, constant(-1)})};
139+
}
140+
// simplify immediately
141+
auto& d = denom.children.front();
142+
ExpressionUtil::normalize(d);
143+
if (d.type == Expression::Type::CONSTANT &&
144+
(d.value == Number::ZERO || d.value == Number::ONE)) {
145+
res = num;
146+
} else {
147+
res = divToFraction(num, denom);
148+
}
149+
150+
return true;
151+
}
152+
116153
bool FormulaGenerator::update(const Operation& op) {
117154
auto source = operandToExpression(op.source);
118155
auto target = operandToExpression(op.target);
@@ -168,6 +205,10 @@ bool FormulaGenerator::update(const Operation& op) {
168205
res = func("binomial", {prevTarget, source});
169206
break;
170207
}
208+
case Operation::Type::FAC: {
209+
okay = facToExpression(prevTarget, source, res);
210+
break;
211+
}
171212
case Operation::Type::LOG: {
172213
res = func("logint", {prevTarget, source});
173214
break;

src/form/formula_gen.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class FormulaGenerator {
4040
bool bitfunc(Operation::Type type, const Expression& a, const Expression& b,
4141
Expression& res) const;
4242

43+
bool facToExpression(const Expression& a, const Expression& b,
44+
Expression& res) const;
45+
4346
bool update(const Operation& op);
4447

4548
bool update(const Program& p);

tests/formula/formula.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ A000071: a(n) = b(n)-1, b(n) = b(n-1)+b(n-2), b(1) = 1, b(0) = 0
1111
A000073: a(n) = a(n-1)+a(n-2)+a(n-3), a(2) = 1, a(1) = 0, a(0) = 0
1212
A000096: a(n) = binomial(n+2,2)-1
1313
A000142: a(n) = n*a(n-1), a(0) = 1
14-
A000165: a(n) = b(2*n), b(n) = n*b(n-2), b(1) = 1, b(0) = 1
14+
A000165: a(n) = 2^n*n!
1515
A000168: a(n) = truncate((2*A151383(n))/(n+2)), A151383(n) = floor((floor(binomial(2*n,n)/(n+1))*3^(n+1))/3)
1616
A000212: a(n) = floor((n^2)/3)
1717
A000247: a(n) = 2^n-n-2
@@ -57,6 +57,7 @@ A001911: a(n) = b(n)-2, b(n) = b(n-1)+b(n-2), b(1) = 3, b(0) = 2
5757
A001923: a(n) = n^n+a(n-1), a(0) = 0
5858
A002015: a(n) = (n^2)%100
5959
A002309: a(n) = (2*n-1)^4+a(n-1), a(2) = 82, a(1) = 1, a(0) = 0
60+
A002378: a(n) = floor(((n+1)!)/((n-1)!))
6061
A002489: a(n) = n^(n^2)
6162
A002535: a(n) = 9*a(n-2)+2*a(n-1), a(2) = 11, a(1) = 1, a(0) = 1
6263
A004273: a(n) = max(2*n-1,0)
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
; A000165: Double factorial of even numbers: (2n)!! = 2^n*n!.
22
; 1,2,8,48,384,3840,46080,645120,10321920,185794560,3715891200,81749606400,1961990553600,51011754393600,1428329123020800,42849873690624000,1371195958099968000,46620662575398912000,1678343852714360832000,63777066403145711616000,2551082656125828464640000,107145471557284795514880000,4714400748520531002654720000,216862434431944426122117120000,10409396852733332453861621760000,520469842636666622693081088000000,27064431817106664380040216576000000,1461479318123759876522171695104000000
33

4-
mov $1,1
5-
mul $0,2
6-
lpb $0
7-
mul $1,$0
8-
sub $0,2
9-
lpe
4+
mov $2,1
5+
fac $2,$0
6+
mov $1,2
7+
pow $1,$0
8+
mul $1,$2
109
mov $0,$1
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
; A002378: Oblong (or promic, pronic, or heteromecic) numbers: a(n) = n*(n+1).
22
; 0,2,6,12,20,30,42,56,72,90,110,132,156,182,210,240,272,306,342,380,420,462,506,552,600,650,702,756,812,870,930,992,1056,1122,1190,1260,1332,1406,1482,1560,1640,1722,1806,1892,1980,2070,2162,2256,2352,2450,2550,2652,2756,2862,2970,3080,3192,3306,3422,3540,3660,3782,3906,4032,4160,4290,4422,4556,4692,4830,4970,5112,5256,5402,5550,5700,5852,6006,6162,6320
33

4-
mov $1,$0
5-
add $0,1
6-
mul $0,$1
4+
fac $0,2
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
; A007531: a(n) = n*(n-1)*(n-2) (or n!/(n-3)!).
2+
; 0,0,0,6,24,60,120,210,336,504,720,990,1320,1716,2184,2730,3360,4080,4896,5814,6840,7980,9240,10626,12144,13800,15600,17550,19656,21924,24360,26970,29760,32736,35904,39270,42840,46620,50616,54834,59280,63960,68880,74046,79464,85140,91080,97290,103776,110544,117600,124950,132600,140556,148824,157410,166320,175560,185136,195054,205320,215940,226920,238266,249984,262080,274560,287430,300696,314364,328440,342930,357840,373176,388944,405150,421800,438900,456456,474474
3+
4+
fac $0,-3

0 commit comments

Comments
 (0)