Merge changes Ic3151274,I44131774,I2afed196,Ib903a31d,I74cad802

* changes:
  [apps] Fix bug: display 'n' when clicking on XNT in sum and product function
  [poincare] Add comments to integral approximation for future improvements
  [poincare] Create a first version of a class integral (approx method is to be improved with QUADPACK algo)
  [poincare] Create a class opposite
  [poincare] Add a class exponential
This commit is contained in:
Émilie Feral
2017-01-26 17:58:02 +01:00
committed by Gerrit
13 changed files with 247 additions and 9 deletions

View File

@@ -9,13 +9,16 @@ const char * ExpressionTextFieldDelegate::XNT() {
bool ExpressionTextFieldDelegate::cursorInToken(TextField * textField, const char * token) {
const char * text = textField->text();
int cursorLocation = textField->cursorLocation();
int location = textField->cursorLocation();
int tokenLength = strlen(token);
if (cursorLocation - tokenLength < 0) {
while (text[location] != '(') {
location --;
}
if (location - tokenLength < 0) {
return false;
}
char previousToken[10];
strlcpy(previousToken, text+cursorLocation-tokenLength, tokenLength+1);
strlcpy(previousToken, text+location-tokenLength, tokenLength+1);
if (strcmp(previousToken, token) == 0) {
return true;
}
@@ -61,7 +64,7 @@ bool ExpressionTextFieldDelegate::textFieldDidReceiveEvent(TextField * textField
textField->setEditing(true);
textField->setText("");
}
if (cursorInToken(textField, "sum(") || cursorInToken(textField, "product(")) {
if (cursorInToken(textField, "sum") || cursorInToken(textField, "product")) {
textField->insertTextAtLocation("n", textField->cursorLocation());
textField->setCursorLocation(textField->cursorLocation()+strlen("n"));
return true;

View File

@@ -6,7 +6,7 @@
* and the text which would be edited by clicking on the row. When the node is a
* subtree, the edited text is set at nullptr. */
const ToolboxNode calculChildren[4] = {ToolboxNode("diff(,)", "Nombre derive"), ToolboxNode("Int(,,)", "Integrale"), ToolboxNode("sum(,,)", "Somme"), ToolboxNode("product(,,)", "Produit")};
const ToolboxNode calculChildren[4] = {ToolboxNode("diff(,)", "Nombre derive"), ToolboxNode("int(,,)", "Integrale"), ToolboxNode("sum(,,)", "Somme"), ToolboxNode("product(,,)", "Produit")};
const ToolboxNode complexChildren[5] = {ToolboxNode("abs()", "Module"), ToolboxNode("arg()", "Argument"), ToolboxNode("re()", "Partie reelle"), ToolboxNode("im()", "Partie imaginaire"), ToolboxNode("conj()", "Conjugue")};
const ToolboxNode probabilityChildren[4] = {ToolboxNode("binomial()", "Combinaison"), ToolboxNode("permute(,)", "Arrangement"), ToolboxNode("random(,)", "Nombre aleatoire"), ToolboxNode("gamma()", "Fonction gamma")};
const ToolboxNode arithmeticChildren[4] = {ToolboxNode("gcd()", "PGCD"), ToolboxNode("lcm()", "PPCM"), ToolboxNode("rem()", "Reste division euclidienne"), ToolboxNode("quo()","Quotien division euclidienne")};

View File

@@ -8,6 +8,7 @@ objs += $(addprefix poincare/src/,\
binary_operation.o\
cosine.o\
derivative.o\
exponential.o\
expression.o\
expression_lexer.o\
expression_parser.o\
@@ -16,12 +17,14 @@ objs += $(addprefix poincare/src/,\
function.o\
global_context.o\
integer.o\
integral.o\
list_data.o\
leaf_expression.o\
logarithm.o\
matrix.o\
matrix_data.o\
nth_root.o\
opposite.o\
parenthesis.o\
power.o\
product.o\

View File

@@ -7,16 +7,19 @@
#include <poincare/cosine.h>
#include <poincare/derivative.h>
#include <poincare/expression.h>
#include <poincare/exponential.h>
#include <poincare/float.h>
#include <poincare/fraction.h>
#include <poincare/function.h>
#include <poincare/global_context.h>
#include <poincare/integer.h>
#include <poincare/integral.h>
#include <poincare/list_data.h>
#include <poincare/logarithm.h>
#include <poincare/matrix.h>
#include <poincare/matrix_data.h>
#include <poincare/nth_root.h>
#include <poincare/opposite.h>
#include <poincare/parenthesis.h>
#include <poincare/power.h>
#include <poincare/product.h>

View File

@@ -0,0 +1,15 @@
#ifndef POINCARE_EXPONENTIAL_H
#define POINCARE_EXPONENTIAL_H
#include <poincare/function.h>
class Exponential : public Function {
public:
Exponential();
float approximate(Context & context) const override;
Type type() const override;
Expression * cloneWithDifferentOperands(Expression ** newOperands,
int numberOfOperands, bool cloneOperands = true) const override;
};
#endif

View File

@@ -13,11 +13,14 @@ class Expression {
Addition,
Cosine,
Derivative,
Exponential,
Float,
Integer,
Integral,
Logarithm,
Matrix,
NthRoot,
Opposite,
Fraction,
Parenthesis,
Power,

View File

@@ -0,0 +1,18 @@
#ifndef POINCARE_INTEGRAL_H
#define POINCARE_INTEGRAL_H
#include <poincare/function.h>
#include <poincare/x_context.h>
class Integral : public Function {
public:
Integral();
float approximate(Context & context) const override;
Type type() const override;
Expression * cloneWithDifferentOperands(Expression ** newOperands,
int numberOfOperands, bool cloneOperands = true) const override;
private:
float functionValueAtAbscissa(float x, XContext xcontext) const;
};
#endif

View File

@@ -0,0 +1,26 @@
#ifndef POINCARE_OPPOSITE_H
#define POINCARE_OPPOSITE_H
#include <poincare/expression.h>
#include <poincare/matrix.h>
#include <poincare/float.h>
class Opposite : public Expression {
public:
Opposite(Expression * operand, bool cloneOperands = true);
~Opposite();
const Expression * operand(int i) const override;
int numberOfOperands() const override;
Expression * clone() const override;
Expression * evaluate(Context& context) const override;
ExpressionLayout * createLayout() const override;
float approximate(Context& context) const override;
Type type() const override;
Expression * cloneWithDifferentOperands(Expression** newOperands,
int numnerOfOperands, bool cloneOperands = true) const override;
protected:
Expression * m_operand;
Expression * evaluateOnMatrix(Matrix * m, Context& context) const;
};
#endif

View File

@@ -0,0 +1,28 @@
#include <poincare/exponential.h>
extern "C" {
#include <assert.h>
#include <math.h>
}
Exponential::Exponential() :
Function("exp")
{
}
Expression::Type Exponential::type() const {
return Type::Exponential;
}
Expression * Exponential::cloneWithDifferentOperands(Expression** newOperands,
int numberOfOperands, bool cloneOperands) const {
assert(numberOfOperands == 1);
assert(newOperands != nullptr);
Exponential * e = new Exponential();
e->setArgument(newOperands, numberOfOperands, cloneOperands);
return e;
}
float Exponential::approximate(Context& context) const {
return expf(m_args[0]->approximate(context));
}

View File

@@ -82,8 +82,10 @@ E { return EE; }
abs { poincare_expression_yylval.expression = new AbsoluteValue(); return FUNCTION; }
diff { poincare_expression_yylval.expression = new Derivative(); return FUNCTION; }
ans { poincare_expression_yylval.character = Symbol::Ans; return SYMBOL; }
exp { poincare_expression_yylval.expression = new Exponential(); return FUNCTION; }
sin { poincare_expression_yylval.expression = new Sine(); return FUNCTION; }
cos { poincare_expression_yylval.expression = new Cosine(); return FUNCTION; }
int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; }
tan { poincare_expression_yylval.expression = new Tangent(); return FUNCTION; }
log { poincare_expression_yylval.expression = new Logarithm(); return FUNCTION; }
root { poincare_expression_yylval.expression = new NthRoot(); return FUNCTION; }

View File

@@ -112,13 +112,9 @@ mtxData:
number:
DIGITS { $$ = new Integer($1.address, false); }
| MINUS DIGITS { $$ = new Integer($2.address, true); }
| DIGITS DOT DIGITS { $$ = new Float($1.address, $1.length, false, $3.address, $3.length, nullptr, 0, false); }
| MINUS DIGITS DOT DIGITS { $$ = new Float($2.address, $2.length, true, $4.address, $4.length, nullptr, 0, false); }
| DIGITS DOT DIGITS EE DIGITS { $$ = new Float($1.address, $1.length, false, $3.address, $3.length, $5.address, $5.length, false); }
| MINUS DIGITS DOT DIGITS EE DIGITS { $$ = new Float($2.address, $2.length, true, $4.address, $4.length, $6.address, $6.length, false); }
| DIGITS DOT DIGITS EE MINUS DIGITS { $$ = new Float($1.address, $1.length, false, $3.address, $3.length, $6.address, $6.length, true); }
| MINUS DIGITS DOT DIGITS EE MINUS DIGITS { $$ = new Float($2.address, $2.length, true, $4.address, $4.length, $7.address, $7.length, true); }
exp:
number { $$ = $1; }
@@ -128,6 +124,7 @@ exp:
| exp MULTIPLY exp { Expression * terms[2] = {$1,$3}; $$ = new Product(terms, false); }
| exp DIVIDE exp { Expression * terms[2] = {$1,$3}; $$ = new Fraction(terms, false); }
| exp POW exp { Expression * terms[2] = {$1,$3}; $$ = new Power(terms, false); }
| MINUS exp { $$ = new Opposite($2, false); }
| LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Parenthesis($2, false); }
| LEFT_BRACKET mtxData RIGHT_BRACKET { $$ = new Matrix($2); }
| FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; $1->setArgument($3, false);}

60
poincare/src/integral.cpp Normal file
View File

@@ -0,0 +1,60 @@
#include <poincare/integral.h>
#include <poincare/symbol.h>
#include <poincare/float.h>
#include <poincare/context.h>
extern "C" {
#include <assert.h>
#include <math.h>
}
Integral::Integral() :
Function("int")
{
}
Expression::Type Integral::type() const {
return Type::Integral;
}
Expression * Integral::cloneWithDifferentOperands(Expression** newOperands,
int numberOfOperands, bool cloneOperands) const {
assert(numberOfOperands == 3);
assert(newOperands != nullptr);
Integral * i = new Integral();
i->setArgument(newOperands, numberOfOperands, cloneOperands);
return i;
}
float Integral::approximate(Context& context) const {
/* We here use Gauss-Legendre quadrature with n = 5
* Gauss-Legendre abscissae and weights taken from
* http://www.holoborodko.com/pavel/numerical-methods/numerical-integration/*/
/* TODO: implement an adaptive quadrature version
* Use Gauss-Konrad quadrature (the one used in GNU scientific library)?
* QAGS and QAGI from netlib?
* Add to this version:
* - assess error
* - higher degree if error > threshold
* - find a way to reuse x and w ? Or useless, store all values ? */
XContext xContext = XContext(&context);
static float x[5]={0.1488743389816312108848260f, 0.4333953941292471907992659f, 0.6794095682990244062343274f, 0.8650633666889845107320967f, 0.9739065285171717200779640f};
static float w[5]={0.2955242247147528701738930f, 0.2692667193099963550912269f, 0.2190863625159820439955349f, 0.1494513491505805931457763f, 0.0666713443086881375935688f};
float a = m_args[1]->approximate(context);
float b = m_args[2]->approximate(context);
float xm = 0.5f*(a+b);
float xr = 0.5f*(b-a);
float result = 0.0f;
for (int j = 0; j < 5; j++) {
float dx = xr * x[j];
result += w[j]*(functionValueAtAbscissa(xm+dx, xContext) + functionValueAtAbscissa(xm-dx, xContext));
}
result *= xr;
return result;
}
float Integral::functionValueAtAbscissa(float x, XContext xContext) const {
Float e = Float(x);
Symbol xSymbol = Symbol('x');
xContext.setExpressionForSymbolName(&e, &xSymbol);
return m_args[0]->approximate(xContext);
}

80
poincare/src/opposite.cpp Normal file
View File

@@ -0,0 +1,80 @@
#include <poincare/opposite.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
}
#include "layout/horizontal_layout.h"
#include "layout/string_layout.h"
Opposite::Opposite(Expression * operand, bool cloneOperands) {
assert(operand != nullptr);
if (cloneOperands) {
m_operand = operand->clone();
} else {
m_operand = operand;
}
}
Opposite::~Opposite() {
delete m_operand;
}
const Expression * Opposite::operand(int i) const {
assert(i == 0);
return m_operand;
}
int Opposite::numberOfOperands() const {
return 1;
}
Expression * Opposite::clone() const {
return this->cloneWithDifferentOperands((Expression**)&m_operand, 1, true);
}
Expression * Opposite::evaluate(Context& context) const {
Expression * operandEvalutation = m_operand->evaluate(context);
if (operandEvalutation == nullptr) {
return nullptr;
}
Expression * result = nullptr;
if (operandEvalutation->type() == Type::Float) {
result = new Float(this->approximate(context));
}
if (operandEvalutation->type() == Type::Matrix) {
result = evaluateOnMatrix((Matrix *)operandEvalutation, context);
}
delete operandEvalutation;
return result;
}
ExpressionLayout * Opposite::createLayout() const {
ExpressionLayout** children_layouts = (ExpressionLayout **)malloc(2*sizeof(ExpressionLayout *));
char string[2] = {'-', '\0'};
children_layouts[0] = new StringLayout(string, 1);
children_layouts[1] = m_operand->createLayout();
return new HorizontalLayout(children_layouts, 2);
}
float Opposite::approximate(Context& context) const {
return -m_operand->approximate(context);
}
Expression::Type Opposite::type() const {
return Expression::Type::Opposite;
}
Expression * Opposite::cloneWithDifferentOperands(Expression** newOperands,
int numberOfOperands, bool cloneOperands) const {
assert(newOperands != nullptr);
assert(numberOfOperands == 1);
return new Opposite(newOperands[0], cloneOperands);
}
Expression * Opposite::evaluateOnMatrix(Matrix * m, Context& context) const {
Expression * operands[m->numberOfRows() * m->numberOfColumns()];
for (int i = 0; i < m->numberOfRows() * m->numberOfColumns(); i++) {
operands[i] = new Float(- m->operand(i)->approximate(context));
}
return new Matrix(operands, m->numberOfRows() * m->numberOfColumns(), m->numberOfColumns(), m->numberOfRows(), false);
}