Skip to content

Commit 1aa7822

Browse files
committed
list: Implement sum and product
Implement sum and product on lists and array. Fixes: #616 Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
1 parent d72ddb2 commit 1aa7822

File tree

4 files changed

+118
-2
lines changed

4 files changed

+118
-2
lines changed

src/ids.tbl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ CMD(Tail)
523523
CMD(Map)
524524
CMD(Reduce) ALIAS(Reduce, "Stream")
525525
CMD(Filter)
526+
OP(Sum, "Σ")
527+
OP(Product, "∏")
526528

527529
// Characters
528530
NAMED(CharToUnicode, "Char→Code") ALIAS(CharToUnicode, "Codepoint")

src/list.cc

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "program.h"
4040
#include "renderer.h"
4141
#include "runtime.h"
42+
#include "symbol.h"
4243
#include "utf8.h"
4344
#include "variables.h"
4445

@@ -811,6 +812,116 @@ COMMAND_BODY(Filter)
811812
}
812813

813814

815+
algebraic_p sum_product(symbol_g name,
816+
large a,
817+
large b,
818+
program_g expr,
819+
bool product)
820+
// ----------------------------------------------------------------------------
821+
// Perform a sum or product
822+
// ----------------------------------------------------------------------------
823+
{
824+
algebraic_g result = integer::make(uint(product));
825+
algebraic_g value;
826+
save<symbol_g *> iref(expression::independent, &name);
827+
828+
for (large i = a; i <= b; i++)
829+
{
830+
value = integer::make(i);
831+
value = algebraic::evaluate_function(expr, value);
832+
if (!value)
833+
return nullptr;
834+
result = product ? result * value : result + value;
835+
}
836+
837+
return result;
838+
}
839+
840+
841+
static object::result pair_map(object::id cmd)
842+
// ----------------------------------------------------------------------------
843+
// Shared code for map, reduce and filter
844+
// ----------------------------------------------------------------------------
845+
{
846+
size_t depth = rt.depth();
847+
if (rt.args(1))
848+
{
849+
object_p obj = rt.stack(0);
850+
object::id ty = obj->type();
851+
if (ty == object::ID_list || ty == object::ID_array)
852+
{
853+
object_p result = list_p(obj)->reduce(command::static_object(cmd));
854+
if (result && rt.top(result))
855+
return object::OK;
856+
}
857+
else if (rt.args(4))
858+
{
859+
symbol_g name = rt.stack(3)->as_quoted<symbol>();
860+
if (!name)
861+
goto error;
862+
object_g init = rt.stack(2);
863+
object_g last = rt.stack(1);
864+
object_g expr = rt.stack(0);
865+
if (!expr->is_program())
866+
{
867+
rt.type_error();
868+
goto error;
869+
}
870+
871+
if (init->is_symbolic() || last->is_symbolic())
872+
{
873+
object_g prg = command::static_object(cmd);
874+
expr = rt.make<list>(object::ID_expression,
875+
name, init, last, expr, prg);
876+
if (expr && rt.drop(3) && rt.top(expr))
877+
return object::OK;
878+
goto error;
879+
}
880+
else if (init->is_integer() && last->is_integer())
881+
{
882+
bool prod = cmd == object::ID_Product;
883+
program_g prg = program_p(expr.Safe());
884+
large a = init->as_int64();
885+
large b = last->as_int64();
886+
expr = sum_product(name, a, b, prg, prod);
887+
if (expr && rt.drop(3) && rt.top(expr))
888+
return object::OK;
889+
}
890+
else
891+
{
892+
rt.type_error();
893+
}
894+
}
895+
else
896+
{
897+
rt.type_error();
898+
}
899+
}
900+
error:
901+
if (rt.depth() > depth)
902+
rt.drop(rt.depth() - depth);
903+
return object::ERROR;
904+
}
905+
906+
907+
COMMAND_BODY(Sum)
908+
// ----------------------------------------------------------------------------
909+
// Return the sum of a list or array
910+
// ----------------------------------------------------------------------------
911+
{
912+
return pair_map(ID_add);
913+
}
914+
915+
916+
COMMAND_BODY(Product)
917+
// ----------------------------------------------------------------------------
918+
// Return the product of a list or array
919+
// ----------------------------------------------------------------------------
920+
{
921+
return pair_map(ID_mul);
922+
}
923+
924+
814925
object_p list::head() const
815926
// ----------------------------------------------------------------------------
816927
// Return the first element in the list

src/list.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ COMMAND_DECLARE(Tail);
314314
COMMAND_DECLARE(Map);
315315
COMMAND_DECLARE(Reduce);
316316
COMMAND_DECLARE(Filter);
317+
COMMAND_DECLARE(Sum);
318+
COMMAND_DECLARE(Product);
319+
317320

318321

319322
inline list_g operator+(list_r x, list_r y)

src/menu.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,8 +919,8 @@ MENU(DataMenu,
919919
"Reduce", ID_Reduce,
920920
"Filter", ID_Filter,
921921

922-
"", ID_Unimplemented,
923-
"", ID_Unimplemented,
922+
"", ID_Sum,
923+
"", ID_Product,
924924
"", ID_Unimplemented,
925925
"Get", ID_Get,
926926
"Put", ID_Put,

0 commit comments

Comments
 (0)