[apps/probability] Make law model an abstract class with inheritance for

all specific laws (binomial...)

Change-Id: Ida6d5bfb7a3fbfc288393cd2f7e9e9b934798073
This commit is contained in:
Émilie Feral
2016-12-14 11:16:11 +01:00
parent 8c284ba34f
commit 2a79d8bfd9
29 changed files with 885 additions and 472 deletions

View File

@@ -1,13 +1,21 @@
app_objs += $(addprefix apps/probability/,\
app.o\
binomial_law.o\
calculation.o\
calculation_controller.o\
cell.o\
evaluate_context.o\
exponential_law.o\
image_table_view.o\
law.o\
law_controller.o\
law_curve_view.o\
normal_law.o\
one_parameter_law.o\
parameters_controller.o\
poisson_law.o\
two_parameter_law.o\
uniform_law.o\
)
app_images += $(addprefix apps/probability/images/,\

View File

@@ -0,0 +1,71 @@
#include "binomial_law.h"
#include <assert.h>
namespace Probability {
BinomialLaw::BinomialLaw(EvaluateContext * evaluateContext) :
TwoParameterLaw(evaluateContext),
m_expression(Expression::parse("p1-p2*t"))
{
//m_expression = Expression::parse("binomial(p1, p2)*p2^t*(1-p2)^(p1-t)");
assert(m_expression != nullptr);
}
BinomialLaw::~BinomialLaw() {
delete m_expression;
}
const char * BinomialLaw::title() {
return "Loi binomiale";
}
Expression * BinomialLaw::expression() const {
return m_expression;
}
Law::Type BinomialLaw::type() const {
return Type::Binomial;
}
bool BinomialLaw::isContinuous() {
return false;
}
const char * BinomialLaw::parameterNameAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return "n";
} else {
return "p";
}
}
const char * BinomialLaw::parameterDefinitionAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return "n : nombre de repetitions";
} else {
return "p : probabilites de succes";
}
}
float BinomialLaw::xMin() {
return 0.0f;
}
float BinomialLaw::xMax() {
if (m_parameter1 == 0) {
return 1.0f;
}
return m_parameter1;
}
float BinomialLaw::yMin() {
return -0.2f;
}
float BinomialLaw::yMax() {
return 1.0f;
}
}

View File

@@ -0,0 +1,29 @@
#ifndef PROBABILITE_BINOMIAL_LAW_H
#define PROBABILITE_BINOMIAL_LAW_H
#include "evaluate_context.h"
#include "two_parameter_law.h"
namespace Probability {
class BinomialLaw : public TwoParameterLaw {
public:
BinomialLaw(EvaluateContext * evaluateContext);
~BinomialLaw() override;
const char * title() override;
Expression * expression() const override;
Type type() const override;
bool isContinuous() override;
float xMin() override;
float yMin() override;
float xMax() override;
float yMax() override;
const char * parameterNameAtIndex(int index) override;
const char * parameterDefinitionAtIndex(int index) override;
private:
Expression * m_expression;
};
}
#endif

View File

@@ -0,0 +1,97 @@
#include "calculation.h"
#include <assert.h>
#include <math.h>
namespace Probability {
Calculation::Calculation():
m_type(LeftIntegral),
m_parameter1(0.0f),
m_parameter2(0.0f),
m_parameter3(0.0f),
m_law(nullptr)
{
}
void Calculation::setLaw(Law * law) {
m_law = law;
computeCalculation(0);
}
void Calculation::setType(Type type) {
m_type = type;
initParameters();
}
Calculation::Type Calculation::type() const {
return m_type;
}
float Calculation::parameterAtIndex(int index) {
if (index == 0) {
return m_parameter1;
}
if (index == 1) {
return m_parameter2;
}
return m_parameter3;
}
void Calculation::setParameterAtIndex(float f, int index) {
if (index == 0) {
m_parameter1 = f;
}
if (index == 1) {
m_parameter2 = f;
}
if (index == 2) {
m_parameter3 = f;
}
computeCalculation(index);
}
void Calculation::computeCalculation(int indexKnownElement) {
if (m_law == nullptr) {
return;
}
if (m_type == LeftIntegral) {
if (indexKnownElement == 0) {
// TODO: compute integral from -Inf to m_parameter1
m_parameter2 = m_law->evaluateAtAbscissa(m_parameter1);
} else {
// TODO: find m_parameter1
m_parameter1 = m_law->evaluateAtAbscissa(m_parameter2);
}
}
if (m_type == FiniteIntegral) {
// TODO: compute integral from m_parameter1 to m_parameter2
m_parameter3 = m_law->evaluateAtAbscissa(m_parameter1 + m_parameter2);
}
if (m_type == RightIntegral) {
if (indexKnownElement == 0) {
// TODO: compute integral from m_parameter1 to +Inf
m_parameter2 = m_law->evaluateAtAbscissa(m_parameter1);
} else {
// TODO: find m_parameter1
m_parameter1 = m_law->evaluateAtAbscissa(m_parameter2);
}
}
}
void Calculation::initParameters() {
if (m_type == LeftIntegral) {
m_parameter1 = 0.0f;
computeCalculation(0);
}
if (m_type == FiniteIntegral) {
m_parameter1 = -1.0f;
m_parameter2 = 1.0f;
computeCalculation(0);
}
if (m_type == RightIntegral) {
m_parameter1 = 0.0f;
computeCalculation(0);
}
}
}

View File

@@ -0,0 +1,34 @@
#ifndef PROBABILITE_CALCULATION_H
#define PROBABILITE_CALCULATION_H
#include "evaluate_context.h"
#include "law.h"
namespace Probability {
class Calculation {
public:
enum Type : uint8_t {
LeftIntegral = 0,
FiniteIntegral = 1,
RightIntegral = 2,
};
Calculation();
void setLaw(Law * law);
void setType(Type type);
Type type() const;
float parameterAtIndex(int index);
void setParameterAtIndex(float f, int index);
private:
void computeCalculation(int indexKnownElement);
void initParameters();
Type m_type;
float m_parameter1;
float m_parameter2;
float m_parameter3;
Law * m_law;
};
}
#endif

View File

@@ -5,10 +5,10 @@
namespace Probability {
CalculationController::ContentView::ContentView(Responder * parentResponder, Law * law) :
m_lawCurveView(LawCurveView(law)),
m_imageTableView(ImageTableView(parentResponder, law)),
m_law(law)
CalculationController::ContentView::ContentView(Responder * parentResponder,Calculation * calculation) :
m_lawCurveView(LawCurveView()),
m_imageTableView(ImageTableView(parentResponder, calculation)),
m_calculation(calculation)
{
for (int k = 0; k < k_maxNumberOfEditableFields; k++) {
m_calculationCell[k].setParentResponder(parentResponder);
@@ -17,8 +17,12 @@ CalculationController::ContentView::ContentView(Responder * parentResponder, Law
}
}
void CalculationController::ContentView::setLaw(Law * law) {
m_lawCurveView.setLaw(law);
}
int CalculationController::ContentView::numberOfSubviews() const {
if ((int)m_law->calculationType() == 1) {
if ((int)m_calculation->type() == 1) {
return 8;
}
return 6;
@@ -33,7 +37,7 @@ View * CalculationController::ContentView::subviewAtIndex(int index) {
return &m_imageTableView;
}
if (index == 2) {
if ((int)m_law->calculationType() == 0) {
if ((int)m_calculation->type() == 0) {
m_text[0].setText("P(X <= ");
} else {
m_text[0].setText("P( ");
@@ -42,13 +46,13 @@ View * CalculationController::ContentView::subviewAtIndex(int index) {
return &m_text[0];
}
if (index == 4) {
if ((int)m_law->calculationType() == 0) {
if (m_calculation->type() == Calculation::Type::LeftIntegral) {
m_text[1].setText(") = ");
}
if ((int)m_law->calculationType() == 1) {
if (m_calculation->type() == Calculation::Type::FiniteIntegral) {
m_text[1].setText(" <= X <= ");
}
if ((int)m_law->calculationType() == 2) {
if (m_calculation->type() == Calculation::Type::RightIntegral) {
m_text[1].setText(" <= X ) = ");
}
m_text[1].setAlignment(0.5f, 0.5f);
@@ -67,7 +71,7 @@ View * CalculationController::ContentView::subviewAtIndex(int index) {
void CalculationController::ContentView::willDisplayEditableCellAtIndex(int index) {
char buffer[Constant::FloatBufferSizeInScientificMode];
Float(m_law->calculationElementAtIndex(index)).convertFloatToText(buffer, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
Float(m_calculation->parameterAtIndex(index)).convertFloatToText(buffer, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
m_calculationCell[index].setText(buffer);
}
@@ -78,20 +82,20 @@ void CalculationController::ContentView::layoutSubviews() {
m_imageTableView.setFrame(KDRect(xCoordinate, 0, ImageTableView::k_imageWidth, 3*ImageTableView::k_imageHeight));
xCoordinate += ImageTableView::k_imageWidth + k_textMargin;
KDCoordinate numberOfCharacters = 7;
if ((int)m_law->calculationType() > 0) {
if ((int)m_calculation->type() > 0) {
numberOfCharacters = 3;
}
m_text[0].setFrame(KDRect(xCoordinate, 0, numberOfCharacters*k_charWidth, ImageTableView::k_imageHeight));
xCoordinate += numberOfCharacters*k_charWidth + k_textMargin;
m_calculationCell[0].setFrame(KDRect(xCoordinate, 0, k_textFieldWidth, ImageTableView::k_imageHeight));
xCoordinate += k_textFieldWidth + k_textMargin;
if ((int)m_law->calculationType() == 0) {
if (m_calculation->type() == Calculation::Type::LeftIntegral) {
numberOfCharacters = 4;
}
if ((int)m_law->calculationType() == 1) {
if (m_calculation->type() == Calculation::Type::FiniteIntegral) {
numberOfCharacters = 9;
}
if ((int)m_law->calculationType() == 2) {
if (m_calculation->type() == Calculation::Type::RightIntegral) {
numberOfCharacters = 10;
}
m_text[1].setFrame(KDRect(xCoordinate, 0, numberOfCharacters*k_charWidth, ImageTableView::k_imageHeight));
@@ -125,11 +129,11 @@ EditableTextCell * CalculationController::ContentView::calculationCellAtIndex(in
return &m_calculationCell[index];
}
CalculationController::CalculationController(Responder * parentResponder, Law * law) :
CalculationController::CalculationController(Responder * parentResponder) :
ViewController(parentResponder),
m_contentView(ContentView(this, law)),
m_contentView(ContentView(this, &m_calculation)),
m_highlightedSubviewIndex(1),
m_law(law)
m_calculation(Calculation())
{
}
@@ -141,6 +145,15 @@ const char * CalculationController::title() const {
return "Calculer les probabilites";
}
void CalculationController::setLaw(Law * law) {
m_contentView.setLaw(law);
m_calculation.setLaw(law);
}
Calculation * CalculationController::calculation() {
return &m_calculation;
}
bool CalculationController::handleEvent(Ion::Events::Event event) {
if ((event == Ion::Events::Left && m_highlightedSubviewIndex > 0) || (event == Ion::Events::Right && m_highlightedSubviewIndex < ContentView::k_maxNumberOfEditableFields - 1)) {
@@ -181,7 +194,7 @@ bool CalculationController::textFieldDidFinishEditing(TextField * textField, con
AppsContainer * appsContainer = (AppsContainer *)app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(text)->approximate(*globalContext);
m_law->setCalculationElementAtIndex(floatBody, m_highlightedSubviewIndex-1);
m_calculation.setParameterAtIndex(floatBody, m_highlightedSubviewIndex-1);
for (int k = 0; k < ContentView::k_maxNumberOfEditableFields; k++) {
m_contentView.willDisplayEditableCellAtIndex(k);
}
@@ -205,10 +218,6 @@ void CalculationController::didBecomeFirstResponder() {
m_contentView.lawCurveView()->reload();
}
Law * CalculationController::law() {
return m_law;
}
void CalculationController::selectSubview(int subviewIndex) {
m_highlightedSubviewIndex = subviewIndex;
}

View File

@@ -10,19 +10,21 @@ namespace Probability {
class CalculationController : public ViewController, public TextFieldDelegate {
public:
CalculationController(Responder * parentResponder, Law * law);
CalculationController(Responder * parentResponder);
View * view() override;
const char * title() const override;
void setLaw(Law * law);
Calculation * calculation();
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
Law * law();
void selectSubview(int subviewIndex);
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text) override;
private:
class ContentView : public View {
public:
ContentView(Responder * parentResponder, Law * law);
ContentView(Responder * parentResponder, Calculation * Calculation);
void setLaw(Law * law);
void layoutSubviews() override;
void drawRect(KDContext * ctx, KDRect rect) const override;
LawCurveView * lawCurveView();
@@ -40,11 +42,11 @@ private:
ImageTableView m_imageTableView;
PointerTextView m_text[k_maxNumberOfEditableFields];
EditableTextCell m_calculationCell[k_maxNumberOfEditableFields];
Law * m_law;
Calculation * m_calculation;
};
ContentView m_contentView;
int m_highlightedSubviewIndex;
Law * m_law;
Calculation m_calculation;
};
}

View File

@@ -0,0 +1,63 @@
#include "exponential_law.h"
#include <assert.h>
namespace Probability {
ExponentialLaw::ExponentialLaw(EvaluateContext * evaluateContext) :
OneParameterLaw(evaluateContext),
m_expression(Expression::parse("p1*t"))
{
//m_expression = Expression::parse("p1*exp(-p1*t)");
assert(m_expression != nullptr);
}
ExponentialLaw::~ExponentialLaw() {
delete m_expression;
}
const char * ExponentialLaw::title() {
return "Loi exponentielle";
}
Expression * ExponentialLaw::expression() const {
return m_expression;
}
Law::Type ExponentialLaw::type() const {
return Type::Exponential;
}
bool ExponentialLaw::isContinuous() {
return true;
}
const char * ExponentialLaw::parameterNameAtIndex(int index) {
assert(index == 0);
return "l";
}
const char * ExponentialLaw::parameterDefinitionAtIndex(int index) {
assert(index == 0);
return "l : parametre";
}
float ExponentialLaw::xMin() {
return 0.0f;
}
float ExponentialLaw::xMax() {
if (m_parameter1 == 0.0f) {
return 100.0f;
}
return 5.0f/m_parameter1;
}
float ExponentialLaw::yMin() {
return -0.2f;
}
float ExponentialLaw::yMax() {
return 1.0f;
}
}

View File

@@ -0,0 +1,29 @@
#ifndef PROBABILITE_EXPONENTIAL_LAW_H
#define PROBABILITE_EXPONENTIAL_LAW_H
#include "evaluate_context.h"
#include "one_parameter_law.h"
namespace Probability {
class ExponentialLaw : public OneParameterLaw {
public:
ExponentialLaw(EvaluateContext * evaluateContext);
~ExponentialLaw() override;
const char * title() override;
Expression * expression() const override;
Type type() const override;
bool isContinuous() override;
float xMin() override;
float yMin() override;
float xMax() override;
float yMax() override;
const char * parameterNameAtIndex(int index) override;
const char * parameterDefinitionAtIndex(int index) override;
private:
Expression * m_expression;
};
}
#endif

View File

@@ -42,12 +42,12 @@ void ImageTableView::ImageCell::setImage(const Image * image, const Image * focu
m_focusedIcon = focusedImage;
}
ImageTableView::ImageTableView(Responder * parentResponder, Law * law) :
ImageTableView::ImageTableView(Responder * parentResponder, Calculation * calculation) :
View(),
Responder(parentResponder),
m_selectableTableView(SelectableTableView(this, this, 0, 0, 0, 0, nullptr, false, false)),
m_isSelected(false),
m_law(law)
m_calculation(calculation)
{
}
@@ -63,7 +63,7 @@ void ImageTableView::didBecomeFirstResponder() {
bool ImageTableView::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
m_law->setCalculationType((Law::CalculationType)m_selectableTableView.selectedRow());
m_calculation->setType((Calculation::Type)m_selectableTableView.selectedRow());
select(false);
setHighlight(true);
m_selectableTableView.reloadData();
@@ -79,7 +79,7 @@ void ImageTableView::select(bool select) {
m_isSelected = select;
} else {
m_isSelected = select;
m_selectableTableView.selectCellAtLocation(0, m_law->calculationType());
m_selectableTableView.selectCellAtLocation(0, m_calculation->type());
}
}
@@ -110,34 +110,12 @@ int ImageTableView::reusableCellCount() {
void ImageTableView::willDisplayCellForIndex(TableViewCell * cell, int index) {
ImageCell * myCell = (ImageCell *)cell;
const Image * images[3] = {ImageStore::Calcul1Icon, ImageStore::Calcul2Icon, ImageStore::Calcul3Icon};
const Image * focusedImages[3] = {ImageStore::FocusedCalcul1Icon, ImageStore::FocusedCalcul2Icon, ImageStore::FocusedCalcul3Icon};
if (!m_isSelected) {
switch (m_law->calculationType()) {
case 0:
myCell->setImage(ImageStore::Calcul1Icon, ImageStore::FocusedCalcul1Icon);
break;
case 1:
myCell->setImage(ImageStore::Calcul2Icon, ImageStore::FocusedCalcul2Icon);
break;
case 2:
myCell->setImage(ImageStore::Calcul3Icon, ImageStore::FocusedCalcul3Icon);
break;
default:
break;
}
myCell->setImage(images[m_calculation->type()], focusedImages[m_calculation->type()]);
} else {
switch (index) {
case 0:
myCell->setImage(ImageStore::Calcul1Icon, ImageStore::FocusedCalcul1Icon);
break;
case 1:
myCell->setImage(ImageStore::Calcul2Icon, ImageStore::FocusedCalcul2Icon);
break;
case 2:
myCell->setImage(ImageStore::Calcul3Icon, ImageStore::FocusedCalcul3Icon);
break;
default:
break;
}
myCell->setImage(images[index], focusedImages[index]);
}
myCell->reloadCell();
}

View File

@@ -2,13 +2,13 @@
#define PROBABILITY_IMAGE_TABLE_VIEW_H
#include <escher.h>
#include "law.h"
#include "calculation.h"
namespace Probability {
class ImageTableView : public View, public Responder, public SimpleListViewDataSource {
public:
ImageTableView(Responder * parentResponder, Law * law);
ImageTableView(Responder * parentResponder, Calculation * calculation);
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
void select(bool select);
@@ -41,7 +41,7 @@ private:
ImageCell m_imageCells[k_numberOfImages];
SelectableTableView m_selectableTableView;
bool m_isSelected;
Law * m_law;
Calculation * m_calculation;
};
}

View File

@@ -1,338 +1,35 @@
#include "law.h"
#include <assert.h>
#include <math.h>
namespace Probability {
Law::Law(EvaluateContext * evaluateContext):
m_type(Law::Type::NoType),
m_calculationType(LeftIntegral),
m_parameter1(0.0f),
m_parameter2(0.0f),
m_expression(nullptr),
m_xMin(-10.0f),
m_xMax(10.0f),
m_yMin(-0.1f),
m_yMax(1.0f),
m_gridUnit(1.0f),
m_calculationElement1(0.0f),
m_calculationElement2(0.0f),
m_calculationElement3(0.0f),
m_evaluateContext(evaluateContext)
{
computeCalculation(0);
}
Law::~Law() {
if (m_expression != nullptr) {
delete m_expression;
}
}
EvaluateContext * Law::evaluateContext() {
return m_evaluateContext;
}
void Law::setType(Type type) {
if (m_expression != nullptr) {
delete m_expression;
m_expression = nullptr;
}
const char * text = nullptr;
switch (type) {
// TODO: implement binomial, indicator function
case Type::Binomial:
text = "binomial(p1, p2)*p2^t*(1-p2)^(p1-t)";
//break;
case Type::Uniform:
text = "1/(p2-p1)";
//break;
case Type::Exponential:
text = "p1*exp(-p1*t)";
//break;
case Type::Normal:
text = "(1/(p2*sqrt(2*Pi))*exp(-0.5*((t-p1)/p2)^2)";
//break;
case Type::Poisson:
text = "exp(-p1)*p1^t/t!";
text = "p1+p2*t";
break;
default:
break;
}
if (text) {
m_expression = Expression::parse(text);
}
setParameterAtIndex(0.0f, 0);
setParameterAtIndex(0.0f, 1);
m_type = type;
}
Law::Type Law::type() const {
return m_type;
}
void Law::setCalculationType(CalculationType calculationType) {
m_calculationType = calculationType;
initCalculationElements();
}
Law::CalculationType Law::calculationType() const {
return m_calculationType;
}
Expression * Law::expression() {
return m_expression;
}
bool Law::isContinuous() {
switch (m_type) {
case Type::Binomial:
return false;
case Type::Uniform:
return true;
case Type::Exponential:
return true;
case Type::Normal:
return true;
case Type::Poisson:
return false;
default:
return false;
}
}
float Law::xMin() {
return m_xMin;
}
float Law::yMin() {
return m_yMin;
}
float Law::xMax() {
return m_xMax;
}
float Law::yMax() {
return m_yMax;
}
float Law::gridUnit() {
return m_gridUnit;
}
float Law::calculationElementAtIndex(int index) {
if (index == 0) {
return m_calculationElement1;
}
if (index == 1) {
return m_calculationElement2;
}
return m_calculationElement3;
}
void Law::setCalculationElementAtIndex(float f, int index) {
if (index == 0) {
m_calculationElement1 = f;
}
if (index == 1) {
m_calculationElement2 = f;
}
if (index == 2) {
m_calculationElement3 = f;
}
computeCalculation(index);
}
int Law::numberOfParameter() {
switch (m_type) {
case Type::Binomial:
return 2;
case Type::Uniform:
return 2;
case Type::Exponential:
return 1;
case Type::Normal:
return 2;
case Type::Poisson:
return 1;
default:
return 0;
}
}
float Law::parameterValueAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return m_parameter1;
}
return m_parameter2;
}
const char * Law::parameterNameAtIndex(int index) {
assert(index >= 0 && index < 2);
switch (m_type) {
// TODO: replace by greek letter
case Type::Binomial:
if (index == 0) {
return "n";
} else {
return "p";
}
case Type::Uniform:
if (index == 0) {
return "a";
} else {
return "b";
}
case Type::Exponential:
return "l";
case Type::Normal:
if (index == 0) {
return "u";
} else {
return "o";
}
case Type::Poisson:
return "l";
default:
return 0;
}
}
const char * Law::parameterDefinitionAtIndex(int index) {
assert(index >= 0 && index < 2);
switch (m_type) {
case Type::Binomial:
if (index == 0) {
return "n : nombre de repetitions";
} else {
return "p : probabilites de succes";
}
case Type::Uniform:
if (index == 0) {
return "[a, b] intervalle";
} else {
return nullptr;
}
case Type::Exponential:
return "l : parametre";
case Type::Normal:
if (index == 0) {
return "u : moyenne";
} else {
return "o : ecart-type";
}
case Type::Poisson:
return "l : parametre";
default:
return 0;
}
}
void Law::setParameterAtIndex(float f, int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
m_parameter1 = f;
m_evaluateContext->setOverridenValueForFirstParameter(f);
} else {
m_parameter2 = f;
m_evaluateContext->setOverridenValueForSecondParameter(f);
}
setWindow();
}
float Law::evaluateAtAbscissa(float t, EvaluateContext * context) const {
context->setOverridenValueForSymbolT(t);
return m_expression->approximate(*context);
}
void Law::setWindow() {
switch (m_type) {
case Type::Binomial:
m_xMin = 0.0f;
m_xMax = m_parameter1;
break;
case Type::Uniform:
m_xMin = m_parameter1 - 3.0f;
m_xMax = m_parameter2 + 3.0f;
break;
case Type::Exponential:
m_xMin = 0.0f;
m_xMax = 5.0f/m_parameter1;
break;
case Type::Normal:
m_xMin = m_parameter1 - 5.0f*m_parameter2;
m_xMax = m_parameter1 + 5.0f*m_parameter2;
break;
case Type::Poisson:
m_xMin = 0.0f;
m_xMax = m_parameter1 + 5.0f*sqrtf(m_parameter1);
default:
return;
}
computeGridUnit();
}
void Law::computeGridUnit() {
int a = 0;
int b = 0;
float d = m_xMax - m_xMin;
if (floorf(log10f(d/90.0f)) != floorf(log10f(d/35.0f))) {
b = floorf(log10f(d/35.0f));
a = 5;
}
if (floorf(log10f(d/36.0f)) != floorf(log10f(d/14.0f))) {
b = floorf(log10f(d/14.0f));
a = 2;
}
if (floorf(log10f(d/18.0f)) != floorf(log10f(d/7.0f))) {
b = floorf(log10f(d/7.0f));
a = 1;
}
m_gridUnit = a*powf(10,b);
}
void Law::computeCalculation(int indexKnownElement) {
if (m_calculationType == LeftIntegral) {
if (indexKnownElement == 0) {
// TODO: compute integral from -Inf to m_calculationElement1
m_calculationElement2 = 3.0f;
} else {
// TODO: find m_calculationElement1
m_calculationElement1 = 4.0f;
}
}
if (m_calculationType == FiniteIntegral) {
// TODO: compute integral from m_calculationElement1 to m_calculationElement2
m_calculationElement3 = 5.0f;
}
if (m_calculationType == RightIntegral) {
if (indexKnownElement == 0) {
// TODO: compute integral from m_calculationElement1 to +Inf
m_calculationElement2 = 6.0f;
} else {
// TODO: find m_calculationElement1
m_calculationElement1 = 7.0f;
float d = xMax() - xMin();
float units[3] = {k_oneUnit, k_twoUnit, k_fiveUnit};
for (int k = 0; k < 3; k++) {
float unit = units[k];
if (floorf(log10f(d/(unit*k_maxNumberOfXGridUnits))) != floorf(log10f(d/(unit*k_minNumberOfXGridUnits)))) {
b = floorf(log10f(d/(unit*k_minNumberOfXGridUnits)));
a = unit;
}
}
return a*powf(10,b);
}
void Law::initCalculationElements() {
if (m_calculationType == LeftIntegral) {
m_calculationElement1 = 0.0f;
computeCalculation(0);
}
if (m_calculationType == FiniteIntegral) {
m_calculationElement1 = -1.0f;
m_calculationElement2 = 1.0f;
computeCalculation(0);
}
if (m_calculationType == RightIntegral) {
m_calculationElement1 = 0.0f;
computeCalculation(0);
}
float Law::evaluateAtAbscissa(float t) const {
m_evaluateContext->setOverridenValueForSymbolT(t);
return expression()->approximate(*m_evaluateContext);
}
}

View File

@@ -7,59 +7,37 @@ namespace Probability {
class Law {
public:
enum class Type {
NoType,
enum class Type : uint8_t{
Binomial,
Uniform,
Exponential,
Normal,
Poisson
};
enum CalculationType : uint8_t {
LeftIntegral = 0,
FiniteIntegral = 1,
RightIntegral = 2,
};
Law(EvaluateContext * evaluateContext);
~Law();
virtual ~Law() {};
virtual const char * title() = 0;
EvaluateContext * evaluateContext();
void setType(Type type);
Type type() const;
void setCalculationType(CalculationType calculationType);
CalculationType calculationType() const;
Expression * expression();
bool isContinuous();
float xMin();
float yMin();
float xMax();
float yMax();
virtual Type type() const = 0;
virtual Expression * expression() const = 0;
virtual bool isContinuous() = 0;
virtual float xMin() = 0;
virtual float yMin() = 0;
virtual float xMax() = 0;
virtual float yMax() = 0;
float gridUnit();
float calculationElementAtIndex(int index);
void setCalculationElementAtIndex(float f, int index);
int numberOfParameter();
float parameterValueAtIndex(int index);
const char * parameterNameAtIndex(int index);
const char * parameterDefinitionAtIndex(int index);
void setParameterAtIndex(float f, int index);
float evaluateAtAbscissa(float x, EvaluateContext * context) const;
private:
void setWindow();
void computeGridUnit();
void computeCalculation(int indexKnownElement);
void initCalculationElements();
Type m_type;
CalculationType m_calculationType;
float m_parameter1;
float m_parameter2;
Expression * m_expression;
float m_xMin;
float m_xMax;
float m_yMin;
float m_yMax;
float m_gridUnit;
float m_calculationElement1;
float m_calculationElement2;
float m_calculationElement3;
virtual int numberOfParameter() = 0;
virtual float parameterValueAtIndex(int index) = 0;
virtual const char * parameterNameAtIndex(int index) = 0;
virtual const char * parameterDefinitionAtIndex(int index) = 0;
virtual void setParameterAtIndex(float f, int index) = 0;
float evaluateAtAbscissa(float x) const;
protected:
constexpr static float k_minNumberOfXGridUnits = 7.0f;
constexpr static float k_maxNumberOfXGridUnits = 18.0f;
constexpr static float k_oneUnit = 1.0f;
constexpr static float k_twoUnit = 2.0f;
constexpr static float k_fiveUnit = 5.0f;
EvaluateContext * m_evaluateContext;
};

View File

@@ -1,6 +1,11 @@
#include "law_controller.h"
#include <assert.h>
#include "app.h"
#include "binomial_law.h"
#include "exponential_law.h"
#include "normal_law.h"
#include "poisson_law.h"
#include "uniform_law.h"
#include "images/binomial_icon.h"
#include "images/exponential_icon.h"
#include "images/normal_icon.h"
@@ -26,8 +31,9 @@ LawController::LawController(Responder * parentResponder, EvaluateContext * eval
ViewController(parentResponder),
m_selectableTableView(SelectableTableView(this, this, Metric::TopMargin, Metric::RightMargin,
Metric::BottomMargin, Metric::LeftMargin)),
m_law(evaluateContext),
m_parametersController(ParametersController(nullptr, &m_law))
m_law(nullptr),
m_evaluateContext(evaluateContext),
m_parametersController(ParametersController(nullptr))
{
m_messages = sMessages;
}
@@ -37,24 +43,18 @@ View * LawController::view() {
}
const char * LawController::title() const {
switch (m_law.type()) {
case Law::Type::Binomial:
return "Loi binomiale";
case Law::Type::Uniform:
return "Loi uniforme";
case Law::Type::Exponential:
return "Loi exponentielle";
case Law::Type::Normal:
return "Loi normale";
case Law::Type::Poisson:
return "Loi Poisson";
default:
return "Choisir le type de Loi";
if (m_law == nullptr) {
return "Choisir le type de Loi";
}
return m_law->title();
}
void Probability::LawController::didBecomeFirstResponder() {
m_law.setType(Law::Type::NoType);
if (m_law != nullptr) {
delete m_law;
m_law = nullptr;
m_parametersController.setLaw(m_law);
}
StackViewController * stack = (StackViewController *)parentResponder();
stack->updateTitle();
if (m_selectableTableView.selectedRow() == -1) {
@@ -68,7 +68,7 @@ void Probability::LawController::didBecomeFirstResponder() {
bool Probability::LawController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
StackViewController * stack = (StackViewController *)parentResponder();
m_law.setType(typeAtIndex(m_selectableTableView.selectedRow()));
setLawAccordingToIndex(m_selectableTableView.selectedRow());
stack->updateTitle();
stack->push(&m_parametersController);
return true;
@@ -93,25 +93,11 @@ int Probability::LawController::reusableCellCount() {
void Probability::LawController::willDisplayCellForIndex(TableViewCell * cell, int index) {
Cell * myCell = (Cell *)cell;
myCell->setLabel(m_messages[index]);
switch (typeAtIndex(index)) {
case Law::Type::Binomial:
myCell->setImage(ImageStore::BinomialIcon, ImageStore::FocusedBinomialIcon);
break;
case Law::Type::Uniform:
myCell->setImage(ImageStore::UniformIcon, ImageStore::FocusedUniformIcon);
break;
case Law::Type::Exponential:
myCell->setImage(ImageStore::ExponentialIcon, ImageStore::FocusedExponentialIcon);
break;
case Law::Type::Normal:
myCell->setImage(ImageStore::NormalIcon, ImageStore::FocusedNormalIcon);
break;
case Law::Type::Poisson:
myCell->setImage(ImageStore::PoissonIcon, ImageStore::FocusedPoissonIcon);
break;
default:
break;
}
const Image * images[5] = {ImageStore::BinomialIcon, ImageStore::UniformIcon, ImageStore::ExponentialIcon,
ImageStore::NormalIcon, ImageStore::PoissonIcon};
const Image * focusedImages[5] = {ImageStore::FocusedBinomialIcon, ImageStore::FocusedUniformIcon, ImageStore::FocusedExponentialIcon,
ImageStore::FocusedNormalIcon, ImageStore::FocusedPoissonIcon};
myCell->setImage(images[index], focusedImages[index]);
myCell->reloadCell();
}
@@ -119,21 +105,31 @@ KDCoordinate Probability::LawController::cellHeight() {
return 35;
}
Law::Type Probability::LawController::typeAtIndex(int index) {
void Probability::LawController::setLawAccordingToIndex(int index) {
if (m_law != nullptr) {
delete m_law;
m_law = nullptr;
}
switch (index) {
case 0:
return Law::Type::Binomial;
m_law = new BinomialLaw(m_evaluateContext);
break;
case 1:
return Law::Type::Uniform;
m_law = new UniformLaw(m_evaluateContext);
break;
case 2:
return Law::Type::Exponential;
m_law = new ExponentialLaw(m_evaluateContext);
break;
case 3:
return Law::Type::Normal;
m_law = new NormalLaw(m_evaluateContext);
break;
case 4:
return Law::Type::Poisson;
m_law = new PoissonLaw(m_evaluateContext);
break;
default:
return Law::Type::NoType;
return;
}
m_parametersController.setLaw(m_law);
}
}

View File

@@ -23,14 +23,15 @@ public:
TableViewCell * reusableCell(int index) override;
int reusableCellCount() override;
private:
Law::Type typeAtIndex(int index);
void setLawAccordingToIndex(int index);
constexpr static int k_totalNumberOfModels = 5;
// !!! CAUTION: The order here is important
// The cells should be initialized *before* the listview!
Cell m_cells[k_totalNumberOfModels];
SelectableTableView m_selectableTableView;
const char ** m_messages;
Law m_law;
Law * m_law;
EvaluateContext * m_evaluateContext;
ParametersController m_parametersController;
};

View File

@@ -3,12 +3,16 @@
namespace Probability {
LawCurveView::LawCurveView(Law * law) :
LawCurveView::LawCurveView() :
CurveView(),
m_law(law)
m_law(nullptr)
{
}
void LawCurveView::setLaw(Law * law) {
m_law = law;
}
void LawCurveView::reload() {
markRectAsDirty(bounds());
computeLabels(Axis::Horizontal);

View File

@@ -11,7 +11,8 @@ namespace Probability {
class LawCurveView : public CurveView {
public:
LawCurveView(Law * law);
LawCurveView();
void setLaw(Law * law);
void reload();
void drawRect(KDContext * ctx, KDRect rect) const override;
protected:

View File

@@ -0,0 +1,74 @@
#include "normal_law.h"
#include <assert.h>
namespace Probability {
NormalLaw::NormalLaw(EvaluateContext * evaluateContext) :
TwoParameterLaw(evaluateContext),
m_expression(Expression::parse("p1-p2*t"))
{
//m_expression = Expression::parse("(1/(p2*sqrt(2*Pi))*exp(-0.5*((t-p1)/p2)^2)");
assert(m_expression != nullptr);
}
NormalLaw::~NormalLaw() {
delete m_expression;
}
const char * NormalLaw::title() {
return "Loi normale";
}
Expression * NormalLaw::expression() const {
return m_expression;
}
Law::Type NormalLaw::type() const {
return Type::Normal;
}
bool NormalLaw::isContinuous() {
return true;
}
const char * NormalLaw::parameterNameAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return "u";
} else {
return "o";
}
}
const char * NormalLaw::parameterDefinitionAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return "u : moyenne";
} else {
return "o : ecart-type";
}
}
float NormalLaw::xMin() {
if (m_parameter2 == 0.0f) {
return m_parameter1 - 1.0f;
}
return m_parameter1 - 5.0f*m_parameter2;
}
float NormalLaw::xMax() {
if (m_parameter2 == 0.0f) {
return m_parameter1 + 1.0f;
}
return m_parameter1 + 5.0f*m_parameter2;
}
float NormalLaw::yMin() {
return -0.2f;
}
float NormalLaw::yMax() {
return 1.0f;
}
}

View File

@@ -0,0 +1,29 @@
#ifndef PROBABILITE_NORMAL_LAW_H
#define PROBABILITE_NORMAL_LAW_H
#include "evaluate_context.h"
#include "two_parameter_law.h"
namespace Probability {
class NormalLaw : public TwoParameterLaw {
public:
NormalLaw(EvaluateContext * evaluateContext);
~NormalLaw() override;
const char * title() override;
Expression * expression() const override;
Type type() const override;
bool isContinuous() override;
float xMin() override;
float yMin() override;
float xMax() override;
float yMax() override;
const char * parameterNameAtIndex(int index) override;
const char * parameterDefinitionAtIndex(int index) override;
private:
Expression * m_expression;
};
}
#endif

View File

@@ -0,0 +1,28 @@
#include "one_parameter_law.h"
#include <assert.h>
namespace Probability {
OneParameterLaw::OneParameterLaw(EvaluateContext * evaluateContext) :
Law(evaluateContext),
m_parameter1(0.5f)
{
m_evaluateContext->setOverridenValueForFirstParameter(m_parameter1);
}
int OneParameterLaw::numberOfParameter() {
return 1;
}
float OneParameterLaw::parameterValueAtIndex(int index) {
assert(index == 0);
return m_parameter1;
}
void OneParameterLaw::setParameterAtIndex(float f, int index) {
assert(index == 0);
m_parameter1 = f;
m_evaluateContext->setOverridenValueForFirstParameter(f);
}
}

View File

@@ -0,0 +1,22 @@
#ifndef PROBABILITE_ONE_PARAMETER_LAW_H
#define PROBABILITE_ONE_PARAMETER_LAW_H
#include "evaluate_context.h"
#include "law.h"
namespace Probability {
class OneParameterLaw : public Law {
public:
OneParameterLaw(EvaluateContext * evaluateContext);
virtual ~OneParameterLaw() {};
int numberOfParameter() override;
float parameterValueAtIndex(int index) override;
void setParameterAtIndex(float f, int index) override;
protected:
float m_parameter1;
};
}
#endif

View File

@@ -11,8 +11,8 @@ ParametersController::ContentView::ContentView(Responder * parentResponder, Sele
ParametersController * parameterController = (ParametersController *) context;
CalculationController * calculationController = parameterController->calculationController();
calculationController->selectSubview(1);
Law * law = calculationController->law();
law->setCalculationType(Law::CalculationType::LeftIntegral);
Calculation * calculation = calculationController->calculation();
calculation->setType(Calculation::Type::LeftIntegral);
StackViewController * stack = parameterController->stackController();
stack->updateTitle();
stack->push(calculationController);
@@ -68,12 +68,12 @@ void ParametersController::ContentView::layoutSubviews() {
/* Parameters Controller */
ParametersController::ParametersController(Responder * parentResponder, Law * law) :
ParametersController::ParametersController(Responder * parentResponder) :
FloatParameterController(parentResponder),
m_contentView(ContentView(this, &m_selectableTableView)),
m_law(law),
m_law(nullptr),
m_buttonSelected(false),
m_calculationController(CalculationController(nullptr, law))
m_calculationController(CalculationController(nullptr))
{
for (int k = 0; k < k_maxNumberOfCells; k++) {
m_menuListCell[k].setParentResponder(&m_selectableTableView);
@@ -97,6 +97,11 @@ const char * ParametersController::title() const {
return m_titleBuffer;
}
void ParametersController::setLaw(Law * law) {
m_law = law;
m_calculationController.setLaw(law);
}
void ParametersController::updateTitle() {
int currentChar = 0;
for (int index = 0; index < m_law->numberOfParameter(); index++) {

View File

@@ -10,10 +10,11 @@ namespace Probability {
class ParametersController : public FloatParameterController {
public:
ParametersController(Responder * parentResponder, Law * law);
ParametersController(Responder * parentResponder);
ExpressionTextFieldDelegate * textFieldDelegate() override;
View * view() override;
const char * title() const override;
void setLaw(Law * law);
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
StackViewController * stackController();

View File

@@ -0,0 +1,64 @@
#include "poisson_law.h"
#include <assert.h>
#include <math.h>
namespace Probability {
PoissonLaw::PoissonLaw(EvaluateContext * evaluateContext) :
OneParameterLaw(evaluateContext),
m_expression(Expression::parse("p1*t"))
{
//m_expression = Expression::parse("exp(-p1)*p1^t/t!");
assert(m_expression != nullptr);
}
PoissonLaw::~PoissonLaw() {
delete m_expression;
}
const char * PoissonLaw::title() {
return "Loi Poisson";
}
Expression * PoissonLaw::expression() const {
return m_expression;
}
Law::Type PoissonLaw::type() const {
return Type::Poisson;
}
bool PoissonLaw::isContinuous() {
return false;
}
const char * PoissonLaw::parameterNameAtIndex(int index) {
assert(index == 0);
return "l";
}
const char * PoissonLaw::parameterDefinitionAtIndex(int index) {
assert(index == 0);
return "l : parametre";
}
float PoissonLaw::xMin() {
return 0.0f;
}
float PoissonLaw::xMax() {
if (m_parameter1 == 0.0f) {
return 1.0f;
}
return m_parameter1 + 5.0f*sqrtf(m_parameter1);
}
float PoissonLaw::yMin() {
return -0.2f;
}
float PoissonLaw::yMax() {
return 1.0f;
}
}

View File

@@ -0,0 +1,29 @@
#ifndef PROBABILITE_POISSON_LAW_H
#define PROBABILITE_POISSON_LAW_H
#include "evaluate_context.h"
#include "one_parameter_law.h"
namespace Probability {
class PoissonLaw : public OneParameterLaw {
public:
PoissonLaw(EvaluateContext * evaluateContext);
~PoissonLaw() override;
const char * title() override;
Expression * expression() const override;
Type type() const override;
bool isContinuous() override;
float xMin() override;
float yMin() override;
float xMax() override;
float yMax() override;
const char * parameterNameAtIndex(int index) override;
const char * parameterDefinitionAtIndex(int index) override;
private:
Expression * m_expression;
};
}
#endif

View File

@@ -0,0 +1,38 @@
#include "two_parameter_law.h"
#include <assert.h>
namespace Probability {
TwoParameterLaw::TwoParameterLaw(EvaluateContext * evaluateContext) :
Law(evaluateContext),
m_parameter1(0.0f),
m_parameter2(0.0f)
{
m_evaluateContext->setOverridenValueForFirstParameter(m_parameter1);
m_evaluateContext->setOverridenValueForSecondParameter(m_parameter2);
}
int TwoParameterLaw::numberOfParameter() {
return 2;
}
float TwoParameterLaw::parameterValueAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return m_parameter1;
}
return m_parameter2;
}
void TwoParameterLaw::setParameterAtIndex(float f, int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
m_parameter1 = f;
m_evaluateContext->setOverridenValueForFirstParameter(f);
} else {
m_parameter2 = f;
m_evaluateContext->setOverridenValueForSecondParameter(f);
}
}
}

View File

@@ -0,0 +1,23 @@
#ifndef PROBABILITE_TWO_PARAMETER_LAW_H
#define PROBABILITE_TWO_PARAMETER_LAW_H
#include "evaluate_context.h"
#include "law.h"
namespace Probability {
class TwoParameterLaw : public Law {
public:
TwoParameterLaw(EvaluateContext * evaluateContext);
virtual ~TwoParameterLaw() {};
int numberOfParameter() override;
float parameterValueAtIndex(int index) override;
void setParameterAtIndex(float f, int index) override;
protected:
float m_parameter1;
float m_parameter2;
};
}
#endif

View File

@@ -0,0 +1,74 @@
#include "uniform_law.h"
#include <assert.h>
namespace Probability {
UniformLaw::UniformLaw(EvaluateContext * evaluateContext) :
TwoParameterLaw(evaluateContext)
{
// TODO: parse indicator function
m_expression = Expression::parse("1/(p2-p1)");
assert(m_expression != nullptr);
}
UniformLaw::~UniformLaw() {
delete m_expression;
}
const char * UniformLaw::title() {
return "Loi uniforme";
}
Expression * UniformLaw::expression() const {
return m_expression;
}
Law::Type UniformLaw::type() const {
return Type::Uniform;
}
bool UniformLaw::isContinuous() {
return true;
}
const char * UniformLaw::parameterNameAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return "a";
} else {
return "b";
}
}
const char * UniformLaw::parameterDefinitionAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return "[a, b] intervalle";
} else {
return nullptr;
}
}
float UniformLaw::xMin() {
if (m_parameter2 < m_parameter1) {
return m_parameter2 - 3.0f;
}
return m_parameter1 - 3.0f;
}
float UniformLaw::xMax() {
if (m_parameter2 < m_parameter1) {
return m_parameter1 + 3.0f;
}
return m_parameter2 + 3.0f;;
}
float UniformLaw::yMin() {
return -0.2f;
}
float UniformLaw::yMax() {
return 1.0f;
}
}

View File

@@ -0,0 +1,29 @@
#ifndef PROBABILITE_UNIFORM_LAW_H
#define PROBABILITE_UNIFORM_LAW_H
#include "evaluate_context.h"
#include "two_parameter_law.h"
namespace Probability {
class UniformLaw : public TwoParameterLaw {
public:
UniformLaw(EvaluateContext * evaluateContext);
~UniformLaw() override;
const char * title() override;
Expression * expression() const override;
Type type() const override;
bool isContinuous() override;
float xMin() override;
float yMin() override;
float xMax() override;
float yMax() override;
const char * parameterNameAtIndex(int index) override;
const char * parameterDefinitionAtIndex(int index) override;
private:
Expression * m_expression;
};
}
#endif