mirror of
https://gitlab.com/c3d/db48x.git
synced 2024-09-29 05:36:58 +02:00
Add expand
, collect
and simplify
functions
Add the basic rules for `expand`, `collect` and `simplify`. And to be honest, I am quite proud of the fact that the core code looks _exactly_ like this (this is actual code): ```c++ return rewrite((x+y)*z, x*z+y*z, x*(y+z), x*y+x*z, (x-y)*z, x*z-y*z, x*(y-z), x*y-x*z); ``` A lot of template metaprogramming to turn that into transparent building of _compile-time constants_ representing the RPL objects for the equations, and passing that to the `rewrite` function that was implemented earlier. What is really neet about this is that the generated equations: * Are automatically _shared_ if used multiple times, because they are represented by the same template. So the equations used in `collect` and those used in `expand` (which are the same in reverse) share the same memory. * Automatically go into QSPI, not consuming precious flash space, because they are represented as initialized data arrays, and I requested that all C++ .rodata go in QSPI. I intentionally did not support the historical names (`expan` and `colct`). Our level of compatibility with the HP48 is never going to be that good anyway. The code as is works with `clang`, but runs into unsatisfied symbols with g++ 10.3 due to what I believe is a g++ bug (that's what living on the edge of template metaprogramming gives you): ``` /opt/homebrew/Cellar/arm-none-eabi-gcc/10.3-2021.07/gcc/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: build/release/equation.o: in function `equation::collect() const': equation.cc:(.text._ZNK8equation7collectEv+0xd0): undefined reference to `eq<(unsigned char)10, (unsigned char)1, (unsigned char)120, (unsigned char)10, (unsigned char)1, (unsigned char)122, (unsigned char)57, (unsigned char)10, (unsigned char)1, (unsigned char)121, (unsigned char)10, (unsigned char)1, (unsigned char)122, (unsigned char)57, (unsigned char)55>::object_data' ``` Fixes: #231 Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
parent
7451edfccc
commit
9a47650ca9
9 changed files with 139 additions and 8 deletions
|
@ -7,7 +7,7 @@ extern const unsigned char EditorFont_sparse_font_data[];
|
||||||
const unsigned char EditorFont_sparse_font_data[74100] FONT_QSPI =
|
const unsigned char EditorFont_sparse_font_data[74100] FONT_QSPI =
|
||||||
{
|
{
|
||||||
|
|
||||||
0x81, 0x02, 0xEF, 0xC2, 0x04, 0x36, 0x00, 0x01, 0x00, 0x2C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
|
0x84, 0x02, 0xEF, 0xC2, 0x04, 0x36, 0x00, 0x01, 0x00, 0x2C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
|
||||||
0x00, 0x2C, 0x01, 0x01, 0x08, 0x00, 0x20, 0x5F, 0x00, 0x2C, 0x01, 0x01, 0x08, 0x00, 0x02, 0x0B,
|
0x00, 0x2C, 0x01, 0x01, 0x08, 0x00, 0x20, 0x5F, 0x00, 0x2C, 0x01, 0x01, 0x08, 0x00, 0x02, 0x0B,
|
||||||
0x05, 0x21, 0x09, 0xEF, 0xBD, 0xF7, 0xDE, 0x7B, 0xEF, 0xBD, 0xF7, 0xDE, 0x7B, 0xEF, 0xBD, 0xF7,
|
0x05, 0x21, 0x09, 0xEF, 0xBD, 0xF7, 0xDE, 0x7B, 0xEF, 0xBD, 0xF7, 0xDE, 0x7B, 0xEF, 0xBD, 0xF7,
|
||||||
0x1E, 0x00, 0x00, 0xB8, 0xFF, 0xFF, 0xFF, 0x0E, 0x03, 0x0B, 0x0B, 0x0F, 0x11, 0x8F, 0x7F, 0xFC,
|
0x1E, 0x00, 0x00, 0xB8, 0xFF, 0xFF, 0xFF, 0x0E, 0x03, 0x0B, 0x0B, 0x0F, 0x11, 0x8F, 0x7F, 0xFC,
|
||||||
|
|
|
@ -7,7 +7,7 @@ extern const unsigned char HelpFont_sparse_font_data[];
|
||||||
const unsigned char HelpFont_sparse_font_data[15113] FONT_QSPI =
|
const unsigned char HelpFont_sparse_font_data[15113] FONT_QSPI =
|
||||||
{
|
{
|
||||||
|
|
||||||
0x81, 0x02, 0x85, 0x76, 0x14, 0x00, 0x01, 0x00, 0x11, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01, 0x00,
|
0x84, 0x02, 0x85, 0x76, 0x14, 0x00, 0x01, 0x00, 0x11, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01, 0x00,
|
||||||
0x11, 0x01, 0x01, 0x03, 0x00, 0x20, 0x5F, 0x00, 0x11, 0x01, 0x01, 0x03, 0x00, 0x01, 0x04, 0x02,
|
0x11, 0x01, 0x01, 0x03, 0x00, 0x20, 0x5F, 0x00, 0x11, 0x01, 0x01, 0x03, 0x00, 0x01, 0x04, 0x02,
|
||||||
0x0D, 0x04, 0xFF, 0xFF, 0xF3, 0x03, 0x01, 0x04, 0x04, 0x05, 0x06, 0xFF, 0xFF, 0x0F, 0x01, 0x04,
|
0x0D, 0x04, 0xFF, 0xFF, 0xF3, 0x03, 0x01, 0x04, 0x04, 0x05, 0x06, 0xFF, 0xFF, 0x0F, 0x01, 0x04,
|
||||||
0x08, 0x0D, 0x0A, 0x12, 0x12, 0x14, 0x7F, 0x7F, 0x24, 0x24, 0x24, 0xFE, 0xFE, 0x28, 0x48, 0x48,
|
0x08, 0x0D, 0x0A, 0x12, 0x12, 0x14, 0x7F, 0x7F, 0x24, 0x24, 0x24, 0xFE, 0xFE, 0x28, 0x48, 0x48,
|
||||||
|
|
|
@ -7,7 +7,7 @@ extern const unsigned char StackFont_sparse_font_data[];
|
||||||
const unsigned char StackFont_sparse_font_data[36629] FONT_QSPI =
|
const unsigned char StackFont_sparse_font_data[36629] FONT_QSPI =
|
||||||
{
|
{
|
||||||
|
|
||||||
0x81, 0x02, 0x90, 0x9E, 0x02, 0x24, 0x00, 0x01, 0x00, 0x1C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
|
0x84, 0x02, 0x90, 0x9E, 0x02, 0x24, 0x00, 0x01, 0x00, 0x1C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
|
||||||
0x00, 0x1C, 0x01, 0x01, 0x06, 0x00, 0x20, 0x5F, 0x00, 0x1C, 0x01, 0x01, 0x06, 0x00, 0x02, 0x05,
|
0x00, 0x1C, 0x01, 0x01, 0x06, 0x00, 0x20, 0x5F, 0x00, 0x1C, 0x01, 0x01, 0x06, 0x00, 0x02, 0x05,
|
||||||
0x03, 0x17, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xC0, 0xFF, 0x1F, 0x02, 0x05, 0x08, 0x0A,
|
0x03, 0x17, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xC0, 0xFF, 0x1F, 0x02, 0x05, 0x08, 0x0A,
|
||||||
0x0C, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x01, 0x05, 0x0E, 0x17, 0x10,
|
0x0C, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x01, 0x05, 0x0E, 0x17, 0x10,
|
||||||
|
|
|
@ -701,3 +701,54 @@ COMMAND_BODY(Rewrite)
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static eq_symbol<'x'> x;
|
||||||
|
static eq_symbol<'y'> y;
|
||||||
|
static eq_symbol<'z'> z;
|
||||||
|
static eq_integer<0> zero;
|
||||||
|
static eq_integer<1> one;
|
||||||
|
static eq_integer<2> two;
|
||||||
|
|
||||||
|
equation_p equation::expand() const
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Run various rewrites to expand equation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return rewrite((x+y)*z, x*z+y*z,
|
||||||
|
x*(y+z), x*y+x*z,
|
||||||
|
(x-y)*z, x*z-y*z,
|
||||||
|
x*(y-z), x*y-x*z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
equation_p equation::collect() const
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Run various rewrites to collect terms / factor equation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return rewrite(x*z+y*z, (x+y)*z,
|
||||||
|
x*y+x*z, x*(y+z),
|
||||||
|
x*z-y*z, (x-y)*z,
|
||||||
|
x*y-x*z, x*(y-z));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
equation_p equation::simplify() const
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Run various rewrites to simplify equation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return rewrite(x + zero, x,
|
||||||
|
zero + x, x,
|
||||||
|
x - zero, x,
|
||||||
|
zero - x, x,
|
||||||
|
x * zero, zero,
|
||||||
|
zero * x, zero,
|
||||||
|
x * one, x,
|
||||||
|
one * x, x,
|
||||||
|
x / one, x,
|
||||||
|
x / x, one,
|
||||||
|
one / x, inv(x),
|
||||||
|
x * x * x, cubed(x),
|
||||||
|
x * x, sq(x));
|
||||||
|
}
|
||||||
|
|
|
@ -88,11 +88,34 @@ struct equation : program
|
||||||
}
|
}
|
||||||
|
|
||||||
equation_p rewrite(equation_r from, equation_r to) const;
|
equation_p rewrite(equation_r from, equation_r to) const;
|
||||||
|
equation_p rewrite(equation_p from, equation_p to) const
|
||||||
|
{
|
||||||
|
return rewrite(equation_g(from), equation_g(to));
|
||||||
|
}
|
||||||
|
|
||||||
static equation_p rewrite(equation_r eq, equation_r from, equation_r to)
|
static equation_p rewrite(equation_r eq, equation_r from, equation_r to)
|
||||||
{
|
{
|
||||||
return eq->rewrite(from, to);
|
return eq->rewrite(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename from_eq, typename to_eq>
|
||||||
|
equation_p rewrite(from_eq from, to_eq to) const
|
||||||
|
{
|
||||||
|
return rewrite(from.as_equation(), to.as_equation());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename from_eq, typename to_eq, typename ...args>
|
||||||
|
equation_p rewrite(from_eq from, to_eq to, args... rest) const
|
||||||
|
{
|
||||||
|
if (equation_p eq = rewrite(from, to))
|
||||||
|
return eq->rewrite(rest...);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
equation_p expand() const;
|
||||||
|
equation_p collect() const;
|
||||||
|
equation_p simplify() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static symbol_g render(uint depth, int &precedence, bool edit);
|
static symbol_g render(uint depth, int &precedence, bool edit);
|
||||||
static symbol_g parentheses(symbol_g what);
|
static symbol_g parentheses(symbol_g what);
|
||||||
|
|
|
@ -514,3 +514,51 @@ INSERT_BODY(fact)
|
||||||
// We need to pass "x!' because ui.edit() strips the x
|
// We need to pass "x!' because ui.edit() strips the x
|
||||||
return ui.edit(utf8("x!"), 2, ui.POSTFIX);
|
return ui.edit(utf8("x!"), 2, ui.POSTFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTION_BODY(Expand)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Expand equations
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
if (!x.Safe())
|
||||||
|
return nullptr;
|
||||||
|
if (equation_p eq = x->as<equation>())
|
||||||
|
return algebraic_p(eq->expand());
|
||||||
|
if (x->is_algebraic())
|
||||||
|
return x;
|
||||||
|
rt.type_error();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTION_BODY(Collect)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Collect equations
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
if (!x.Safe())
|
||||||
|
return nullptr;
|
||||||
|
if (equation_p eq = x->as<equation>())
|
||||||
|
return algebraic_p(eq->collect());
|
||||||
|
if (x->is_algebraic())
|
||||||
|
return x;
|
||||||
|
rt.type_error();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTION_BODY(Simplify)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Simplify equations
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
if (!x.Safe())
|
||||||
|
return nullptr;
|
||||||
|
if (equation_p eq = x->as<equation>())
|
||||||
|
return algebraic_p(eq->simplify());
|
||||||
|
if (x->is_algebraic())
|
||||||
|
return x;
|
||||||
|
rt.type_error();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -194,4 +194,8 @@ FUNCTION(im);
|
||||||
FUNCTION(arg);
|
FUNCTION(arg);
|
||||||
FUNCTION(conj);
|
FUNCTION(conj);
|
||||||
|
|
||||||
|
FUNCTION(Expand);
|
||||||
|
FUNCTION(Collect);
|
||||||
|
FUNCTION(Simplify);
|
||||||
|
|
||||||
#endif // FUNCTIONS_H
|
#endif // FUNCTIONS_H
|
||||||
|
|
|
@ -236,7 +236,7 @@ CMD(re)
|
||||||
CMD(im)
|
CMD(im)
|
||||||
CMD(arg)
|
CMD(arg)
|
||||||
CMD(conj)
|
CMD(conj)
|
||||||
NAMED(det, "Determinant")
|
NAMED(det, "Determinant") // Last algebraic
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -265,6 +265,9 @@ NAMED(ToList, "→List")
|
||||||
CMD(Get)
|
CMD(Get)
|
||||||
|
|
||||||
CMD(Rewrite)
|
CMD(Rewrite)
|
||||||
|
CMD(Expand)
|
||||||
|
CMD(Collect)
|
||||||
|
CMD(Simplify)
|
||||||
|
|
||||||
NAMED(RealToComplex, "ℝ→ℂ")
|
NAMED(RealToComplex, "ℝ→ℂ")
|
||||||
ALIAS(RealToComplex, "R→C")
|
ALIAS(RealToComplex, "R→C")
|
||||||
|
|
|
@ -537,11 +537,12 @@ MENU(SymbolicMenu,
|
||||||
// Symbolic operations
|
// Symbolic operations
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
ID_Rewrite,
|
ID_Rewrite,
|
||||||
"Collect", ID_Unimplemented,
|
ID_Collect,
|
||||||
"Expand", ID_Unimplemented,
|
ID_Expand,
|
||||||
|
ID_Simplify,
|
||||||
|
|
||||||
"Isolate", ID_Unimplemented,
|
"Isolate", ID_Unimplemented,
|
||||||
"Apply", ID_Unimplemented,
|
"Apply", ID_Unimplemented,
|
||||||
"Taylor", ID_Unimplemented,
|
|
||||||
|
|
||||||
"Ex/Co", ID_Unimplemented,
|
"Ex/Co", ID_Unimplemented,
|
||||||
"→Q", ID_Unimplemented,
|
"→Q", ID_Unimplemented,
|
||||||
|
@ -554,6 +555,7 @@ MENU(SymbolicMenu,
|
||||||
"∑", ID_Unimplemented,
|
"∑", ID_Unimplemented,
|
||||||
"∏", ID_Unimplemented,
|
"∏", ID_Unimplemented,
|
||||||
"∆", ID_Unimplemented,
|
"∆", ID_Unimplemented,
|
||||||
|
"Taylor", ID_Unimplemented,
|
||||||
|
|
||||||
"Show", ID_Unimplemented,
|
"Show", ID_Unimplemented,
|
||||||
"Quote", ID_Unimplemented,
|
"Quote", ID_Unimplemented,
|
||||||
|
|
Loading…
Reference in a new issue