From 02e79ad595330931cf94994248935482bada5c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 21 Feb 2020 17:57:22 +0100 Subject: [PATCH 001/117] [apps/code] Do not refresh the print if the sandbox is displayed Otherwise the first responder becomes the console edit line, and events (such as Toolbox) are not intercepted by the sandbox anymore. --- apps/code/console_controller.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 697872131..b920fd714 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -399,6 +399,9 @@ void ConsoleController::resetSandbox() { } void ConsoleController::refreshPrintOutput() { + if (sandboxIsDisplayed()) { + return; + } m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); if (m_preventEdition) { From acb71d29759a3dadac9221570058159adedb7da6 Mon Sep 17 00:00:00 2001 From: DSchndr Date: Tue, 25 Feb 2020 20:10:33 +0100 Subject: [PATCH 002/117] German translations --- apps/calculation/base.de.i18n | 14 +-- apps/code/catalog.de.i18n | 192 +++++++++++++++++----------------- apps/home/base.de.i18n | 4 +- apps/settings/base.de.i18n | 24 ++--- apps/toolbox.de.i18n | 92 ++++++++-------- 5 files changed, 163 insertions(+), 163 deletions(-) diff --git a/apps/calculation/base.de.i18n b/apps/calculation/base.de.i18n index e71cdc958..ebb1bd928 100644 --- a/apps/calculation/base.de.i18n +++ b/apps/calculation/base.de.i18n @@ -1,9 +1,9 @@ CalculApp = "Berechnung" CalculAppCapital = "BERECHNUNG" -AdditionalResults = "????" -DecimalBase = "????" -HexadecimalBase = "????" -BinaryBase = "????" -PrimeFactors = "????" -MixedFraction = "????" -EuclideanDivision = "????" +AdditionalResults = "Weitere Ergebnisse" +DecimalBase = "Dezimal" +HexadecimalBase = "Hexadezimal" +BinaryBase = "Binär" +PrimeFactors = "Primfaktor" +MixedFraction = "Gemischte Fraktion" +EuclideanDivision = "Euklidische Division" diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 4fc15ea09..57c071bbb 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -12,105 +12,105 @@ PythonSingleQuote = "Einfaches Anführungszeichen" PythonAbs = "Absolute/r Wert/Größe" PythonAcos = "Arkuskosinus" PythonAcosh = "Hyperbelkosinus" -PythonAppend = "Add x to the end of the list" +PythonAppend = "Hängt x an das Ende der Liste" PythonAsin = "Arkussinus" PythonAsinh = "Hyperbelsinus" PythonAtan = "Arkustangens" PythonAtan2 = "Gib atan(y/x)" PythonAtanh = "Hyperbeltangens" -PythonBin = "Ganzzahl nach binär konvertieren" +PythonBin = "Ganzzahl nach binär" PythonCeil = "Aufrundung" PythonChoice = "Zufallszahl aus der Liste" -PythonClear = "Empty the list" +PythonClear = "Leere die Liste" PythonCmathFunction = "cmath-Modul-Funktionspräfix" -PythonColor = "Definiere eine RGB-Farbe" +PythonColor = "Definiert eine RGB-Farbe" PythonComplex = "a+ib zurückgeben" -PythonCopySign = "Return x with the sign of y" +PythonCopySign = "x mit dem Vorzeichen von y" PythonCos = "Kosinus" PythonCosh = "Hyperbolic cosine" -PythonCount = "Count the occurrences of x" -PythonDegrees = "Convert x from radians to degrees" -PythonDivMod = "Quotient and remainder" -PythonDrawString = "Display a text from pixel (x,y)" +PythonCount = "Zählt wie oft x vorkommt" +PythonDegrees = "x von Radian zu Grad umwandeln" +PythonDivMod = "Quotient und Rest" +PythonDrawString = "Schreibt Text bei (x,y)" PythonConstantE = "2.718281828459046" -PythonErf = "Error function" +PythonErf = "Fehlerfunktion" PythonErfc = "Complementary error function" PythonEval = "Return the evaluated expression" -PythonExp = "Exponential function" -PythonExpm1 = "Compute exp(x)-1" -PythonFabs = "Absolute value" -PythonFillRect = "Fill a rectangle at pixel (x,y)" -PythonFloat = "Convert x to a float" +PythonExp = "Exponentialfunktion" +PythonExpm1 = "Berechne exp(x)-1" +PythonFabs = "Absoluter Wert" +PythonFillRect = "Malt ein Rechteck bei Pixel (x,y)" +PythonFloat = "Wandelt x zu float um" PythonFloor = "Floor" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" -PythonGamma = "Gamma function" -PythonGetPixel = "Return pixel (x,y) color" -PythonGetrandbits = "Integer with k random bits" -PythonHex = "Convert integer to hexadecimal" -PythonImportCmath = "Import cmath module" -PythonImportIon = "Import ion module" -PythonImportKandinsky = "Import kandinsky module" -PythonImportRandom = "Import random module" -PythonImportMath = "Import math module" -PythonImportTime = "Import time module" -PythonImportTurtle = "Import turtle module" -PythonIndex = "Index of the first x occurrence" -PythonInput = "Prompt a value" -PythonInsert = "Insert x at index i in the list" -PythonInt = "Convert x to an integer" +PythonFrExp = "Rest und Exponent von x" +PythonGamma = "Gammafunktion" +PythonGetPixel = "Farbe von Pixel (x,y)" +PythonGetrandbits = "Ganzzahl mit k zufälligen Bits" +PythonHex = "Ganzzahl zu Hexadecimal" +PythonImportCmath = "cmath Modul importieren" +PythonImportIon = "ion Modul importieren" +PythonImportKandinsky = "kandinsky Modul importieren" +PythonImportRandom = "random Modul importieren" +PythonImportMath = "math Modul importieren" +PythonImportTime = "time Modul importieren" +PythonImportTurtle = "turtle Modul importieren" +PythonIndex = "Index, bei dem x zuerst vorkommt" +PythonInput = "Eingabeaufforderung" +PythonInsert = "x bei index i in der Liste einsetzen" +PythonInt = "x zu Ganzzahl" PythonIonFunction = "ion module function prefix" -PythonIsFinite = "Check if x is finite" -PythonIsInfinite = "Check if x is infinity" -PythonIsNaN = "Check if x is a NaN" -PythonIsKeyDown = "Return True if the k key is down" +PythonIsFinite = "Prüft ob x endlich ist" +PythonIsInfinite = "Prüft ob x unendlich ist" +PythonIsNaN = "Prüft ob x NaN ist" +PythonIsKeyDown = "true wenn k gedrückt ist" PythonKandinskyFunction = "kandinsky module function prefix" -PythonKeyLeft = "LEFT ARROW key" -PythonKeyUp = "UP ARROW key" -PythonKeyDown = "DOWN ARROW key" -PythonKeyRight = "RIGHT ARROW key" -PythonKeyOk = "OK key" -PythonKeyBack = "BACK key" -PythonKeyHome = "HOME key" -PythonKeyOnOff = "ON/OFF key" -PythonKeyShift = "SHIFT key" -PythonKeyAlpha = "ALPHA key" -PythonKeyXnt = "X,N,T key" -PythonKeyVar = "VAR key" -PythonKeyToolbox = "TOOLBOX key" -PythonKeyBackspace = "BACKSPACE key" -PythonKeyExp = "EXPONENTIAL key" -PythonKeyLn = "NATURAL LOGARITHM key" -PythonKeyLog = "DECIMAL LOGARITHM key" -PythonKeyImaginary = "IMAGINARY I key" -PythonKeyComma = "COMMA key" -PythonKeyPower = "POWER key" -PythonKeySine = "SINE key" -PythonKeyCosine = "COSINE key" -PythonKeyTangent = "TANGENT key" -PythonKeyPi = "PI key" -PythonKeySqrt = "SQUARE ROOT key" -PythonKeySquare = "SQUARE key" -PythonKeySeven = "7 key" -PythonKeyEight = "8 key" -PythonKeyNine = "9 key" +PythonKeyLeft = "Linke Pfeiltaste" +PythonKeyUp = "Pfeiltaste nach oben" +PythonKeyDown = "Pfeiltaste nach unten" +PythonKeyRight = "Rechte Pfeiltaste" +PythonKeyOk = "OK Taste" +PythonKeyBack = "ZURÜCK Taste" +PythonKeyHome = "HOME Taste" +PythonKeyOnOff = "AN/AUS Taste" +PythonKeyShift = "SHIFT Taste" +PythonKeyAlpha = "ALPHA Taste" +PythonKeyXnt = "X,N,T Taste" +PythonKeyVar = "VAR Taste" +PythonKeyToolbox = "WERKZEUGBOX Taste" +PythonKeyBackspace = "LÖSCHEN Taste" +PythonKeyExp = "EXPONENTIAL Taste" +PythonKeyLn = "NATURAL LOGARITHM Taste" +PythonKeyLog = "DECIMAL LOGARITHM Taste" +PythonKeyImaginary = "IMAGINÄRES I Taste" +PythonKeyComma = "KOMMA Taste" +PythonKeyPower = "HOCH Taste" +PythonKeySine = "SINUS Taste" +PythonKeyCosine = "COSINUS Taste" +PythonKeyTangent = "TANGENZ Taste" +PythonKeyPi = "PI Taste" +PythonKeySqrt = "WURZEL Taste" +PythonKeySquare = "QUADRAT Taste" +PythonKeySeven = "7 Taste" +PythonKeyEight = "8 Taste" +PythonKeyNine = "9 Taste" PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" -PythonKeyFour = "4 key" -PythonKeyFive = "5 key" -PythonKeySix = "6 key" -PythonKeyMultiplication = "MULTIPLICATION key" -PythonKeyDivision = "DIVISION key" -PythonKeyOne = "1 key" -PythonKeyTwo = "2 key" -PythonKeyThree = "3 key" -PythonKeyPlus = "PLUS key" -PythonKeyMinus = "MINUS key" -PythonKeyZero = "0 key" -PythonKeyDot = "DOT key" -PythonKeyEe = "10 POWER X key" -PythonKeyAns = "ANS key" -PythonKeyExe = "EXE key" +PythonKeyFour = "4 Taste" +PythonKeyFive = "5 Taste" +PythonKeySix = "6 Taste" +PythonKeyMultiplication = "MULTIPLIKATIONSTASTE" +PythonKeyDivision = "DIVISIONSTASTE" +PythonKeyOne = "1 Taste" +PythonKeyTwo = "2 Taste" +PythonKeyThree = "3 Taste" +PythonKeyPlus = "PLUS Taste" +PythonKeyMinus = "MINUS Taste" +PythonKeyZero = "0 Taste" +PythonKeyDot = "PUNKT Taste" +PythonKeyEe = "10 HOCH X Taste" +PythonKeyAns = "ANS Taste" +PythonKeyExe = "EXE Taste" PythonLdexp = "Return x*(2**i), inverse of frexp" PythonLength = "Length of an object" PythonLgamma = "Log-gamma function" @@ -142,27 +142,27 @@ PythonReverse = "Reverse the elements of the list" PythonRound = "Round to n digits" PythonSeed = "Initialize random number generator" PythonSetPixel = "Color pixel (x,y)" -PythonSin = "Sine" +PythonSin = "Sinus" PythonSinh = "Hyperbolic sine" PythonSleep = "Suspend the execution for t seconds" PythonSort = "Sort the list" -PythonSqrt = "Square root" +PythonSqrt = "Wurzel" PythonSum = "Sum the items of a list" -PythonTan = "Tangent" +PythonTan = "Tangens" PythonTanh = "Hyperbolic tangent" PythonTimeFunction = "time module function prefix" PythonTrunc = "x truncated to an integer" PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" +PythonTurtleBlack = "Schwarze Farbe" +PythonTurtleBlue = "Blaue Farbe" +PythonTurtleBrown = "Braune Farbe" PythonTurtleCircle = "Circle of radius r pixels" -PythonTurtleColor = "Set the pen color" +PythonTurtleColor = "Stiftfarbe setzen" PythonTurtleForward = "Move forward by x pixels" PythonTurtleFunction = "turtle module function prefix" PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" +PythonTurtleGreen = "Grüne Farbe" +PythonTurtleGrey = "Graue Farbe" PythonTurtleHeading = "Return the current heading" PythonTurtleHideturtle = "Hide the turtle" PythonTurtleIsdown = "Return True if the pen is down" @@ -171,19 +171,19 @@ PythonTurtleOrange = "Orange color" PythonTurtlePendown = "Pull the pen down" PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" +PythonTurtlePink = "Pinke Farbe" PythonTurtlePosition = "Return the current (x,y) location" PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" +PythonTurtleRed = "Rote Farbe" PythonTurtleReset = "Reset the drawing" PythonTurtleRight = "Turn right by a degrees" PythonTurtleSetheading = "Set the orientation to a degrees" -PythonTurtleSetposition = "Positionne la tortue" -PythonTurtleShowturtle = "Show the turtle" -PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" -PythonUniform = "Floating point number in [a,b]" +PythonTurtleSetposition = "Position des turtles" +PythonTurtleShowturtle = "Die turtle anzeigen" +PythonTurtleSpeed = "Zeichengeschwindigkeit zwischen 0 und 10" +PythonTurtleWhite = "Weiße Farbe" +PythonTurtleYellow = "Gelbe Farbe" +PythonUniform = "Fließkommazahl in [a,b]" PythonTimeFromImport = "Import time module" PythonTimeImport = "Import time module" PythonTimePrefix = "time module function prefix" diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n index 352d41520..99f705c4b 100644 --- a/apps/home/base.de.i18n +++ b/apps/home/base.de.i18n @@ -1,4 +1,4 @@ Apps = "Anwendungen" AppsCapital = "OMEGA" -ForbidenAppInExamMode1 = "This application is" -ForbidenAppInExamMode2 = "forbidden in exam mode" +ForbidenAppInExamMode1 = "Diese Anwendung ist im" +ForbidenAppInExamMode2 = "Prüfungsmodus verboten" diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 6f377cd0a..ad17a949f 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -7,9 +7,9 @@ EditionLinear = "Linear " Edition2D = "Natürlich " ComplexFormat = "Komplex" ExamMode = "Testmodus" -ActivateExamMode = "Starten Testmodus" -ExamModeActive = "Wieder starten Testmodus" -ActivateDutchExamMode = "Activate Dutch exam mode" +ActivateExamMode = "Testmodus starten" +ExamModeActive = "Testmodus neustarten" +ActivateDutchExamMode = "Niederländischen Testmodus starten" ToDeactivateExamMode1 = "Um den Testmodus auszuschalten," ToDeactivateExamMode2 = "schließen Sie den Rechner an einen" ToDeactivateExamMode3 = "Computer oder eine Steckdose an." @@ -38,20 +38,20 @@ SoftwareVersion = "Epsilon version" CustomSoftwareVersion = "Omega version" Username = "Name" MicroPythonVersion = "µPythonversion" -ResultDisplay = "Resultaatweergave" -DefaultResult = "Standaard " +ResultDisplay = "Ergebniswiedergabe" +DefaultResult = "Standard " CompactResult = "Compact " FontSizes = "Python Schriftgröße" -LargeFont = "Große " -SmallFont = "Kleine " +LargeFont = "Groß " +SmallFont = "Klein " SerialNumber = "Seriennummer" UpdatePopUp = "Erinnerung: Update" BetaPopUp = "Beta pop-up" -LEDColor = "LEDs farbe" +LEDColor = "LED Farbe" ExamModeMode = "Modus" ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "Ohne symbolisch " -ExamModeModeNoSymNoText = "No sym no text " +ExamModeModeNoSym = "Ohne Symbole " +ExamModeModeNoSymNoText = "Ohne Symbole & Text " ExamModeModeDutch = "Niederländisch " ColorRed = "Rot " ColorWhite = "Weiss " @@ -68,13 +68,13 @@ AccessibilityGamma = "Gammakorrektur" AccessibilityGammaRed = "Rotes Gamma" AccessibilityGammaGreen = "Grünes Gamma" AccessibilityGammaBlue = "Blaues Gamma" -MathOptions = "Mathe-optionen" +MathOptions = "Berechnungseinstellungen" SymbolMultiplication = "Multiplikation" SymbolMultiplicationCross = "Kreuz " SymbolMultiplicationMiddleDot = "Mittelpunkt " SymbolMultiplicationStar = "Stern " SymbolMultiplicationAutoSymbol = "automatisch " -PythonFont = "Python schriftart" +PythonFont = "Python Schriftart" Large = "Groß " Small = "Klein " MemUse = "Speicher" diff --git a/apps/toolbox.de.i18n b/apps/toolbox.de.i18n index 61999f5f7..c7acf774d 100644 --- a/apps/toolbox.de.i18n +++ b/apps/toolbox.de.i18n @@ -1,17 +1,17 @@ -Unit = "Units" -UnitTimeMenu = "Time" -UnitTimeSecondMenu = "Second" -UnitTimeSecond = "Second" -UnitTimeSecondMilli = "Millisecond" -UnitTimeSecondMicro = "Microsecond" -UnitTimeSecondNano = "Nanosecond" +Unit = "Einheiten" +UnitTimeMenu = "Zeit" +UnitTimeSecondMenu = "Sekunde" +UnitTimeSecond = "Sekunde" +UnitTimeSecondMilli = "Millisekunde" +UnitTimeSecondMicro = "Microsekunde" +UnitTimeSecondNano = "Nanosekunde" UnitTimeMinute = "Minute" -UnitTimeHour = "Hour" -UnitTimeDay = "Day" -UnitTimeWeek = "Week" -UnitTimeMonth = "Month" -UnitTimeYear = "Year" -UnitDistanceMenu = "Distance" +UnitTimeHour = "Stunde" +UnitTimeDay = "Tag" +UnitTimeWeek = "Woche" +UnitTimeMonth = "Monat" +UnitTimeYear = "Jahr" +UnitDistanceMenu = "Distanz" UnitDistanceMeterMenu = "Meter" UnitDistanceMeterKilo = "Kilometer" UnitDistanceMeter = "Meter" @@ -19,43 +19,43 @@ UnitDistanceMeterMilli = "Millimeter" UnitDistanceMeterMicro = "Micrometer" UnitDistanceMeterNano = "Nanometer" UnitDistanceMeterPico = "Picometer" -UnitDistanceAstronomicalUnit = "Astronomical unit" -UnitDistanceLightYear = "Light year" +UnitDistanceAstronomicalUnit = "Astronomische Einheit" +UnitDistanceLightYear = "Lichtjahr" UnitDistanceParsec = "Parsec" -UnitMassMenu = "Mass" -UnitMassGramKilo = "Kilogram" -UnitMassGram = "Gram" -UnitMassGramMilli = "Milligram" -UnitMassGramMicro = "Microgram" -UnitMassGramNano = "Nanogram" +UnitMassMenu = "Masse" +UnitMassGramKilo = "Kilogramm" +UnitMassGram = "Gramm" +UnitMassGramMilli = "Milligramm" +UnitMassGramMicro = "Microgramm" +UnitMassGramNano = "Nanogramm" UnitMassTonne = "Tonne" -UnitCurrentMenu = "Electric current" +UnitCurrentMenu = "Elektrischer Strom" UnitCurrentAmpere = "Ampere" UnitCurrentAmpereMilli = "Milliampere" UnitCurrentAmpereMicro = "Microampere" -UnitTemperatureMenu = "Temperature" +UnitTemperatureMenu = "Temperaturen" UnitTemperatureKelvin = "Kelvin" -UnitAmountMenu = "Amount of substance" -UnitAmountMole = "Mole" -UnitAmountMoleMilli = "Millimole" -UnitAmountMoleMicro = "Micromole" -UnitLuminousIntensityMenu = "Luminous intensity" +UnitAmountMenu = "Substanzmenge" +UnitAmountMole = "Mol" +UnitAmountMoleMilli = "Millimol" +UnitAmountMoleMicro = "Micromol" +UnitLuminousIntensityMenu = "Helligkeit" UnitLuminousIntensityCandela = "Candela" -UnitFrequencyMenu = "Frequency" +UnitFrequencyMenu = "Frequenz" UnitFrequencyHertzGiga = "Gigahertz" UnitFrequencyHertzMega = "Megahertz" UnitFrequencyHertzKilo = "Kilohertz" UnitFrequencyHertz = "Hertz" -UnitForceMenu = "Force" +UnitForceMenu = "Kraft" UnitForceNewtonKilo = "Kilonewton" UnitForceNewton = "Newton" UnitForceNewtonMilli = "Millinewton" -UnitPressureMenu = "Pressure" +UnitPressureMenu = "Druck" UnitPressurePascal = "Pascal" UnitPressurePascalHecto = "Hectopascal" UnitPressureBar = "Bar" UnitPressureAtm = "Atmosphere" -UnitEnergyMenu = "Energy" +UnitEnergyMenu = "Energie" UnitEnergyJouleMenu = "Joule" UnitEnergyJouleKilo = "Kilojoule" UnitEnergyJoule = "Joule" @@ -65,37 +65,37 @@ UnitEnergyElectronVoltMega = "Megaelectronvolt" UnitEnergyElectronVoltKilo = "Kiloelectronvolt" UnitEnergyElectronVolt = "Electronvolt" UnitEnergyElectronVoltMilli = "Millielectronvolt" -UnitPowerMenu = "Power" +UnitPowerMenu = "Leistung" UnitPowerWattGiga = "Gigawatt" UnitPowerWattMega = "Megawatt" UnitPowerWattKilo = "Kilowatt" UnitPowerWatt = "Watt" UnitPowerWattMilli = "Milliwatt" UnitPowerWattMicro = "Microwatt" -UnitElectricChargeMenu = "Electric charge" +UnitElectricChargeMenu = "Elektrische Ladung" UnitChargeCoulomb = "Coulomb" -UnitPotentialMenu = "Electric potential" +UnitPotentialMenu = "Elektrisches Potenzial" UnitPotentialVoltKilo = "Kilovolt" UnitPotentialVolt = "Volt" UnitPotentialVoltMilli = "Millivolt" UnitPotentialVoltMicro = "Microvolt" -UnitCapacitanceMenu = "Electrical capacitance" +UnitCapacitanceMenu = "Elektrische Kapazität" UnitCapacitanceFarad = "Farad" UnitCapacitanceFaradMilli = "Millifarad" UnitCapacitanceFaradMicro = "Microfarad" -UnitResistanceMenu = "Electrical resistance" +UnitResistanceMenu = "Elektrischer Widerstand" UnitResistanceOhmKilo = "Kiloohm" UnitResistanceOhm = "Ohm" -UnitConductanceMenu = "Electrical conductance" +UnitConductanceMenu = "Elektrische Leitfähigkeit" UnitConductanceSiemens = "Siemens" UnitConductanceSiemensMilli = "Millisiemens" -UnitMagneticFieldMenu = "Magnetic field" +UnitMagneticFieldMenu = "Magnetisches Feld" UnitMagneticFieldTesla = "Tesla" -InductanceMenu = "Electrical inductance" +InductanceMenu = "Elektrische Induktion" UnitInductanceHenry = "Henry" -UnitSurfaceMenu = "Area" -UnitSurfaceHectar = "Hectare" -UnitVolumeMenu = "Volume" +UnitSurfaceMenu = "Fläche" +UnitSurfaceHectar = "Hektar" +UnitVolumeMenu = "Volumen" UnitVolumeLiter = "Liter" UnitVolumeLiterDeci = "Deciliter" UnitVolumeLiterCenti = "Centiliter" @@ -409,9 +409,9 @@ NumberElementUue = "119 - Ununennium (Uue)" AlphaElementUue = "Uue - Ununennium (119)" NumberElementUbn = "120 - Unbinilium (Ubn)" AlphaElementUbn = "Ubn - Unbinilium (120)" -UnitOfMesurement = "Unit of mesurement" +UnitOfMesurement = "Messeinheit" SpeedOfLightTag = "Lichtgeschwindigkeit (m·s^-1)" -YearLightTag = "Ein Jahr Licht (km)" +YearLightTag = "Lichtjahr (km)" Thermodynamics = "Thermodynamik" BoltzmannTag = "Boltzmann Konstante (J·K^-1)" AvogadroTag = "Avogadro-Konstante (mol^-1)" @@ -427,4 +427,4 @@ NeutronMassTag = "Masse eines Neutrons (kg)" Gravitation = "Gravitation" ElementalChargeTag = "Elementarladung (C)" GAccelerationTag = "Beschleunigung (m·s^-2)" -GConstantTag = "Konstant (m^3·kg^-1·s^-2)" \ No newline at end of file +GConstantTag = "Konstant (m^3·kg^-1·s^-2)" From 1e81a944e3be75eca8a774f50ce2bc2beaea10b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 10 Feb 2020 16:26:57 +0100 Subject: [PATCH 003/117] [build] Web: enable to build target simulator.official.zip and epsilon.official.js --- build/targets.simulator.web.mak | 5 +++-- build/toolchain.emscripten.mak | 2 +- ion/src/simulator/web/Makefile | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index 65abe11f7..f5b1158e0 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -1,13 +1,14 @@ -$(BUILD_DIR)/epsilon.js: EMSCRIPTEN_INIT_FILE = 1 +$(BUILD_DIR)/epsilon%packed.js: EMSCRIPTEN_INIT_FILE = 0 $(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0 $(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src)) +$(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src)) .PHONY: workshop_python_emulator workshop_python_emulator: $(MAKE) PLATFORM=simulator TARGET=web clean_for_apps_selection - $(MAKE) PLATFORM=simulator TARGET=web EPSILON_APPS=code + $(MAKE) PLATFORM=simulator TARGET=web EPSILON_APPS=code epsilon.official.js $(MAKE) PLATFORM=simulator TARGET=web clean_for_apps_selection .PHONY: clean_for_apps_selection diff --git a/build/toolchain.emscripten.mak b/build/toolchain.emscripten.mak index a773fd190..10f39df5c 100644 --- a/build/toolchain.emscripten.mak +++ b/build/toolchain.emscripten.mak @@ -129,7 +129,7 @@ EMFLAGS += -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 # Configure LDFLAGS EMSCRIPTEN_MODULARIZE ?= 1 LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"' -EMSCRIPTEN_INIT_FILE ?= 0 +EMSCRIPTEN_INIT_FILE ?= 1 LDFLAGS += --memory-init-file $(EMSCRIPTEN_INIT_FILE) SFLAGS += $(EMFLAGS) diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index ada734ed7..08177b0ac 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -26,10 +26,10 @@ endif DEFAULT = $(BUILD_DIR)/simulator.zip -$(BUILD_DIR)/simulator.zip: $(BUILD_DIR)/epsilon.packed.js +$(BUILD_DIR)/simulator%zip: $(BUILD_DIR)/epsilon%packed.js @rm -rf $(basename $@) @mkdir -p $(basename $@) - @cp $^ $(basename $@)/epsilon.js + @cp $^ $(basename $@)/epsilon.official.packed.js @cp ion/src/simulator/assets/background.jpg $(basename $@)/ @cp ion/src/simulator/web/simulator.html $(basename $@)/ $(call rule_label,ZIP) From 6693102d5f3fa83a196618c09141d02f2c3158ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 10 Feb 2020 16:27:55 +0100 Subject: [PATCH 004/117] [build] binpack: fix name change build --> output --- build/targets.device.n0110.mak | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 8f56063df..082adac82 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -31,19 +31,19 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex .PHONY: binpack binpack: - rm -rf build/binpack - mkdir -p build/binpack + rm -rf output/binpack + mkdir -p output/binpack ${MAKE} clean ${MAKE} $(BUILD_DIR)/flasher.light.bin - cp $(BUILD_DIR)/flasher.light.bin build/binpack + cp $(BUILD_DIR)/flasher.light.bin output/binpack ${MAKE} clean ${MAKE} $(BUILD_DIR)/bench.flash.bin ${MAKE} $(BUILD_DIR)/bench.ram.bin - cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin build/binpack + cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack ${MAKE} clean ${MAKE} epsilon.onboarding.update.two_binaries - cp $(BUILD_DIR)/epsilon.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.onboarding.update.external.bin build/binpack + cp $(BUILD_DIR)/epsilon.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.onboarding.update.external.bin output/binpack ${MAKE} clean - cd build && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done - cd build && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack - rm -rf build/binpack + cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done + cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack + rm -rf output/binpack From 2351b03fb7c2d929634763d9adb5ba519b516011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 10 Feb 2020 17:28:10 +0100 Subject: [PATCH 005/117] [build] Fix binpack target --- build/targets.device.n0110.mak | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 082adac82..556bae335 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -26,8 +26,8 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex $(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin $(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin @echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin" - $(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).external.bin - $(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).internal.bin + $(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).external.bin + $(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).internal.bin .PHONY: binpack binpack: @@ -36,14 +36,12 @@ binpack: ${MAKE} clean ${MAKE} $(BUILD_DIR)/flasher.light.bin cp $(BUILD_DIR)/flasher.light.bin output/binpack - ${MAKE} clean ${MAKE} $(BUILD_DIR)/bench.flash.bin ${MAKE} $(BUILD_DIR)/bench.ram.bin cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack + ${MAKE} epsilon.official.onboarding.update.two_binaries + cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack ${MAKE} clean - ${MAKE} epsilon.onboarding.update.two_binaries - cp $(BUILD_DIR)/epsilon.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.onboarding.update.external.bin output/binpack - ${MAKE} clean - cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done + cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack rm -rf output/binpack From b85f19c99c0c151f8e0211931e402344b82b2c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 10 Feb 2020 17:28:28 +0100 Subject: [PATCH 006/117] [build] Remove useless and wrong workshop_python_emulator (GET_OPT option is missing, which also forces a real clean) --- build/targets.simulator.web.mak | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index f5b1158e0..0a8b41169 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -5,12 +5,6 @@ $(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0 $(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src)) $(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src)) -.PHONY: workshop_python_emulator -workshop_python_emulator: - $(MAKE) PLATFORM=simulator TARGET=web clean_for_apps_selection - $(MAKE) PLATFORM=simulator TARGET=web EPSILON_APPS=code epsilon.official.js - $(MAKE) PLATFORM=simulator TARGET=web clean_for_apps_selection - .PHONY: clean_for_apps_selection clean_for_apps_selection: @echo "CLEAN BEFORE CHANGING EPSILON_APPS" From 06202aac49ff3508941bb6a918de851f1792acbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 11 Feb 2020 11:12:20 +0100 Subject: [PATCH 007/117] [build] Remove useless clean_for_apps_selection target --- build/targets.simulator.web.mak | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index 0a8b41169..a1774a34a 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -4,9 +4,3 @@ $(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0 $(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src)) $(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src)) - -.PHONY: clean_for_apps_selection -clean_for_apps_selection: - @echo "CLEAN BEFORE CHANGING EPSILON_APPS" - $(Q) rm -f $(BUILD_DIR)/apps/apps_container_storage.o - $(Q) rm -f $(BUILD_DIR)/apps/i18n.* From be0b2787b4a8a111286a9e5c92813cfd158bf100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 11 Feb 2020 11:18:21 +0100 Subject: [PATCH 008/117] [ion] Web Makefile: simulator.html expects a epsilon.js file and not a epsilon.official.js file --- ion/src/simulator/web/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 08177b0ac..b31be6f0b 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -29,7 +29,7 @@ DEFAULT = $(BUILD_DIR)/simulator.zip $(BUILD_DIR)/simulator%zip: $(BUILD_DIR)/epsilon%packed.js @rm -rf $(basename $@) @mkdir -p $(basename $@) - @cp $^ $(basename $@)/epsilon.official.packed.js + @cp $^ $(basename $@)/epsilon.js @cp ion/src/simulator/assets/background.jpg $(basename $@)/ @cp ion/src/simulator/web/simulator.html $(basename $@)/ $(call rule_label,ZIP) From 4aace23362b6dfb3e96cddcbf8ceb8db740fb2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 11 Feb 2020 15:11:41 +0100 Subject: [PATCH 009/117] [ion] Makefile of android: enable to build epsilon.apk and epsilon.official.apk --- ion/src/simulator/android/Makefile | 33 ++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index ec4cb714a..ae968c811 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -38,10 +38,15 @@ $(BUILD_DIR)/app/res/%.xml: ion/src/simulator/android/src/res/%.xml | $$(@D)/. .PHONY: force_remake -$(BUILD_DIR)/app/libs/%/libepsilon.so: force_remake $$(@D)/. - $(Q) echo "MAKE NDK_ABI=$*" - $(Q) $(MAKE) NDK_ABI=$* epsilon.so - $(Q) cp $(BUILD_DIR)/$*/epsilon.so $@ +define rule_for_libepsilon +$$(BUILD_DIR)/app/libs/%/lib$(1): force_remake $$$$(@D)/. + $(Q) echo "MAKE NDK_ABI=$$*" + $(Q) $$(MAKE) NDK_ABI=$$* $(1) + $(Q) cp $$(BUILD_DIR)/$$*/$(1) $@ +endef + +$(eval $(call rule_for_libepsilon,epsilon.so)) +$(eval $(call rule_for_libepsilon,epsilon.official.so)) # If NDK_ABI is not defined, we will re-trigger a build for each avaialble ABI. # This is used to build APKs, which needs to embbed a binary for each ABI. @@ -50,22 +55,28 @@ ifndef NDK_ABI NDK_ABIS = armeabi-v7a arm64-v8a x86 x86_64 -epsilon_apk_deps = $(patsubst %,$(BUILD_DIR)/app/libs/%/libepsilon.so,$(NDK_ABIS)) -epsilon_apk_deps += $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*)) +epsilon_apk_deps = $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*)) epsilon_apk_deps += $(addprefix $(BUILD_DIR)/app/res/,mipmap/ic_launcher.png mipmap-v26/ic_launcher_foreground.png) -.PHONY: gradle_% -gradle_%: $(epsilon_apk_deps) +define rule_for_gradle +.PHONY: gradle_$1_$2 +gradle_$1_$2: $$(epsilon_apk_deps) $$(patsubst %,$$(BUILD_DIR)/app/libs/%/libepsilon$2so,$(NDK_ABIS)) @echo "GRADLE ion/src/simulator/android/build.gradle" - $(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle $* + $(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle $1 +endef + +$(eval $(call rule_for_gradle,assembleCodesigned,.)) +$(eval $(call rule_for_gradle,assembleRelease,.)) +$(eval $(call rule_for_gradle,assembleCodesigned,.official.)) +$(eval $(call rule_for_gradle,assembleRelease,.official.)) DEFAULT = epsilon.apk .PHONY: epsilon.apk ifdef ANDROID_SIGNING_STORE_FILE -epsilon.apk: gradle_assembleCodesigned +epsilon%apk: gradle_assembleCodesigned_% else -epsilon.apk: gradle_assembleRelease +epsilon%apk: gradle_assembleRelease_% $(warning Building without code signing. Define ANDROID_SIGNING_STORE_FILE, ANDROID_SIGNING_STORE_PASSWORD, ANDROID_SIGNING_KEY_ALIAS and ANDROID_SIGNING_KEY_PASSWORD for a signed build.) endif From 92a3e07643612be56257ac7f9fe478182bc6c0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 12 Feb 2020 17:19:25 +0100 Subject: [PATCH 010/117] [ion] Enable to build official and unofficial softwares for ios and macos platform --- ion/src/simulator/ios/Makefile | 29 ++++++++++--------- ion/src/simulator/macos/Makefile | 17 ++++++++--- ion/src/simulator/shared/apple/Makefile | 38 ++++++++++++++++--------- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index 876963d03..58dea89ba 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -35,7 +35,7 @@ SIMULATOR_ICONSET = $(SIMULATOR_ASSETS_PATH)/AppIcon.appiconset include ion/src/simulator/shared/apple/Makefile -$(call simulator_app_plist,Info.plist): ion/src/simulator/ios/Info.plist $(call simulator_app_resource,Assets.car) +$(call simulator_app_plist,%,Info.plist): ion/src/simulator/ios/Info.plist $(call simulator_app_resource,%,Assets.car) $(call rule_label,PLUTIL) $(Q) cp $< $@ $(Q) plutil -insert "BuildMachineOSBuild" -string "$(IOS_BUILD_MACHINE_OS_BUILD)" $@ @@ -54,22 +54,23 @@ $(call simulator_app_plist,Info.plist): ion/src/simulator/ios/Info.plist $(call $(Q) plutil -replace CFBundleIcons -json `plutil -extract CFBundleIcons json -o - $(BUILD_DIR)/app/assets/partial.plist` $@ $(Q) plutil -replace CFBundleIcons~ipad -json `plutil -extract CFBundleIcons~ipad json -o - $(BUILD_DIR)/app/assets/partial.plist` $@ -$(call simulator_app_resource,launch.storyboardc): ion/src/simulator/ios/launch.storyboard | $$(@D)/. +$(call simulator_app_resource,%,launch.storyboardc): ion/src/simulator/ios/launch.storyboard | $$(@D)/. $(call rule_label,IBTOOL) $(Q) $(IBTOOL) --minimum-deployment-target $(APPLE_PLATFORM_MIN_VERSION) --compile $@ $^ ifdef IOS_PROVISIONNING_PROFILE -$(call simulator_app_resource,embedded.mobileprovision): $(IOS_PROVISIONNING_PROFILE) | $$(@D)/. +$(call simulator_app_resource,%,embedded.mobileprovision): $(IOS_PROVISIONNING_PROFILE) | $$(@D)/. $(call rule_label,COPY) $(Q) cp $^ $@ -$(BUILD_DIR)/app/entitlements.plist: $(call simulator_app_resource,embedded.mobileprovision) +$(BUILD_DIR)/app/entitlements.plist: $(IOS_PROVISIONNING_PROFILE) $(call rule_label,SCMS) $(Q) security cms -D -i $(IOS_PROVISIONNING_PROFILE) | plutil -extract Entitlements xml1 - -o $@ -SIMULATOR_APP_DEPS += $(BUILD_DIR)/app/entitlements.plist +simulator_app_deps += $(BUILD_DIR)/app/entitlements.plist +simulator_app_deps += $(call simulator_app_resource,$1,embedded.mobileprovision) else -$(call simulator_app_resource,embedded.mobileprovision): +$(call simulator_app_resource,%,embedded.mobileprovision): $(warning Building without a provisionning profile. Please define IOS_PROVISIONNING_PROFILE to point to the .mobileprovision file you want to use.) endif @@ -77,19 +78,19 @@ $(SIMULATOR_ICONSET)/Contents.json: ion/src/simulator/ios/icon_assets.json $(SIM $(call rule_label,COPY) $(Q) cp $< $@ -$(call simulator_app_resource,Assets.car): $(SIMULATOR_ICONSET)/Contents.json | $$(@D)/. +$(call simulator_app_resource,%,Assets.car): $(SIMULATOR_ICONSET)/Contents.json | $$(@D)/. $(call rule_label,ACTOOL) - $(Q) $(ACTOOL) --compile $(BUILD_DIR)/app/Payload/Epsilon.app --minimum-deployment-target $(APPLE_PLATFORM_MIN_VERSION) --platform $(APPLE_SDK) --app-icon AppIcon --output-partial-info-plist $(BUILD_DIR)/app/assets/partial.plist $(SIMULATOR_ASSETS_PATH) > /dev/null + $(Q) $(ACTOOL) --compile $(BUILD_DIR)/app/Payload/$*.app --minimum-deployment-target $(APPLE_PLATFORM_MIN_VERSION) --platform $(APPLE_SDK) --app-icon AppIcon --output-partial-info-plist $(BUILD_DIR)/app/assets/partial.plist $(SIMULATOR_ASSETS_PATH) > /dev/null -SIMULATOR_APP_DEPS += $(call simulator_app_resource,\ +simulator_app_deps += $(call simulator_app_resource,$(1), \ Assets.car \ launch.storyboardc \ ) -$(BUILD_DIR)/app/epsilon.ipa: $(SIMULATOR_APP_DEPS) +$(BUILD_DIR)/app/epsilon%ipa: $(subst ..,.,$(call simulator_app_deps,Epsilon$*)) ifdef IOS_PROVISIONNING_PROFILE $(call rule_label,SIGN) - $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "iPhone Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon.app + $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "iPhone Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon$*app endif $(call rule_label,ZIP) $(Q) cd $(dir $@) ; zip -qr9 $(notdir $@) Payload @@ -99,7 +100,7 @@ DEFAULT := $(BUILD_DIR)/app/epsilon.ipa endif ifeq ($(APPLE_PLATFORM),ios-simulator) -.PHONY: epsilon_run -epsilon_run: $(SIMULATOR_APP_DEPS) - xcrun simctl install booted $(BUILD_DIR)/app/Payload/Epsilon.app +.PHONY: epsilon%run +epsilon%run: $(subst _.,.,$(call simulator_app_deps,Epsilon$*)) + xcrun simctl install booted $(BUILD_DIR)/app/Payload/Epsilon$(subst _,.,$*)app endif diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index ae25b03f3..0f27650df 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -22,7 +22,7 @@ SIMULATOR_ICONSET = $(BUILD_DIR)/app/assets/app.iconset include ion/src/simulator/shared/apple/Makefile -$(call simulator_app_plist,Info.plist): ion/src/simulator/macos/Info.plist +$(call simulator_app_plist,%,Info.plist): ion/src/simulator/macos/Info.plist $(call rule_label,PLUTIL) $(Q) cp $< $@ $(Q) plutil -insert "LSMinimumSystemVersion" -string "$(MACOS_MIN_VERSION)" $@ @@ -31,12 +31,21 @@ $(call simulator_app_plist,Info.plist): ion/src/simulator/macos/Info.plist # macOS uses icns files -$(call simulator_app_resource,app.icns): $(SIMULATOR_ICONS) | $$(@D)/. +.SECONDARY: $(SIMULATOR_ICONS) | $$(@D)/. + +$(call simulator_app_resource,%,app.icns): $(SIMULATOR_ICONS) | $$(@D)/. $(call rule_label,ICNUTIL) $(Q) iconutil --convert icns --output $@ $(SIMULATOR_ICONSET) -SIMULATOR_APP_DEPS += $(call simulator_app_resource,app.icns) +simulator_app_deps += $(call simulator_app_resource,$(1),app.icns) + +simulator_app_deps_unofficial = $(call simulator_app_deps,Epsilon) +simulator_app_deps_official = $(call simulator_app_deps,Epsilon.official) + +.PHONY: Epsilon.app Epsilon.official.app +Epsilon.app: $(simulator_app_deps_unofficial) +Epsilon.official.app: $(simulator_app_deps_official) ifndef ARCH -DEFAULT := $(SIMULATOR_APP_DEPS) +DEFAULT := Epsilon.app endif diff --git a/ion/src/simulator/shared/apple/Makefile b/ion/src/simulator/shared/apple/Makefile index f5b1c77fe..22faf47d7 100644 --- a/ion/src/simulator/shared/apple/Makefile +++ b/ion/src/simulator/shared/apple/Makefile @@ -2,27 +2,37 @@ # The only things that have to be customized per platform are the icons and the # Info.plist. -SIMULATOR_APP_PATH = $(BUILD_DIR)/app/Payload/Epsilon.app +SIMULATOR_APP_PATH = $(BUILD_DIR)/app/Payload -simulator_app_binary = $(addprefix $(SIMULATOR_APP_PATH)/$(SIMULATOR_APP_BINARY_PATH),$(1)) -simulator_app_resource = $(addprefix $(SIMULATOR_APP_PATH)/$(SIMULATOR_APP_RESOURCE_PATH),$(1)) -simulator_app_plist = $(addprefix $(SIMULATOR_APP_PATH)/$(SIMULATOR_APP_PLIST_PATH),$(1)) +simulator_app_binary = $(addprefix $(SIMULATOR_APP_PATH)/$(1).app/$(SIMULATOR_APP_BINARY_PATH),$(2)) +simulator_app_resource = $(addprefix $(SIMULATOR_APP_PATH)/$(1).app/$(SIMULATOR_APP_RESOURCE_PATH),$(2)) +simulator_app_plist = $(addprefix $(SIMULATOR_APP_PATH)/$(1).app/$(SIMULATOR_APP_PLIST_PATH),$(2)) # Epsilon binary .PHONY: force_remake -$(BUILD_DIR)/%/epsilon.bin: force_remake - $(Q) echo "MAKE ARCH=$*" - $(Q) $(MAKE) ARCH=$* +define rule_for_epsilon +$$(BUILD_DIR)/%/$(1): force_remake + $(Q) echo "MAKE ARCH=$$*" + $(Q) $$(MAKE) ARCH=$$* $(1) +endef -$(call simulator_app_binary,Epsilon): $(patsubst %,$(BUILD_DIR)/%/epsilon.bin,$(ARCHS)) | $$(@D)/. - $(call rule_label,LIPO) - $(Q) $(LIPO) -create $^ -output $@ +$(eval $(call rule_for_epsilon,epsilon.bin)) +$(eval $(call rule_for_epsilon,epsilon.official.bin)) + +define rule_for_lipo +$$(call simulator_app_binary,$1,Epsilon): $$(patsubst %,$(BUILD_DIR)/%/$2.bin,$$(ARCHS)) | $$$$(@D)/. + $$(call rule_label,LIPO) + $(Q) $$(LIPO) -create $$^ -output $$@ +endef + +$(eval $(call rule_for_lipo,Epsilon,epsilon)) +$(eval $(call rule_for_lipo,Epsilon.official,epsilon.official)) # Background image -$(call simulator_app_resource,background.jpg): ion/src/simulator/assets/background.jpg | $$(@D)/. +$(call simulator_app_resource,%,background.jpg): ion/src/simulator/assets/background.jpg | $$(@D)/. $(call rule_label,COPY) $(Q) cp $^ $@ @@ -44,6 +54,6 @@ $(addprefix $(SIMULATOR_ICONSET)/,icon_%.png): ion/src/simulator/assets/logo.svg # Export simulator app dependencies -SIMULATOR_APP_DEPS += $(call simulator_app_binary,Epsilon) -SIMULATOR_APP_DEPS += $(call simulator_app_plist,Info.plist) -SIMULATOR_APP_DEPS += $(call simulator_app_resource,background.jpg) +simulator_app_deps += $(call simulator_app_binary,$(1),Epsilon) +simulator_app_deps += $(call simulator_app_plist,$(1),Info.plist) +simulator_app_deps += $(call simulator_app_resource,$(1),background.jpg) From 558e2734f0d3f1961b0f47e1be5411c1f326fbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 17 Feb 2020 09:32:54 +0100 Subject: [PATCH 011/117] [ion] Android Makefile: fix rule for libepsilon --- ion/src/simulator/android/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index ae968c811..0d6789477 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -42,7 +42,7 @@ define rule_for_libepsilon $$(BUILD_DIR)/app/libs/%/lib$(1): force_remake $$$$(@D)/. $(Q) echo "MAKE NDK_ABI=$$*" $(Q) $$(MAKE) NDK_ABI=$$* $(1) - $(Q) cp $$(BUILD_DIR)/$$*/$(1) $@ + $(Q) cp $$(BUILD_DIR)/$$*/$(1) $$@ endef $(eval $(call rule_for_libepsilon,epsilon.so)) From d6504a6c6ad5c1af6c858c8d80fad4e94441e084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 17 Feb 2020 14:01:51 +0100 Subject: [PATCH 012/117] [build] Make a target stable_release which build every executable needed for a stable release --- build/targets.mak | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/build/targets.mak b/build/targets.mak index 68ce3de04..c770b34bf 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -41,3 +41,58 @@ endef -include build/targets.$(PLATFORM).mak $(foreach extension,$(HANDY_TARGETS_EXTENSIONS),$(foreach executable,$(HANDY_TARGETS),$(eval $(call handy_target_rule,$(executable),$(extension))))) + +define source_emsdk +source ~/emsdk/emsdk_env.sh > /dev/null +endef + +ANDROID_GRADLE_KEYSTORE:= $(wildcard ~/.gradle/google-play-upload.keystore) +ANDROID_GRADLE_PROPERTIES:= $(wildcard ~/.gradle/gradle.properties) +IOS_MOBILE_PROVISION:= $(wildcard ~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision) + +MISSING_FILES=1 + +ifneq "$(and $(ANDROID_GRADLE_KEYSTORE),$(ANDROID_GRADLE_PROPERTIES))" "" +ifneq "$(IOS_MOBILE_PROVISION)" "" + MISSING_FILES=0 +endif +endif + +.PHONY: stable_release +ifeq ($(MISSING_FILES),1) +stable_release: + @echo "Some required files for app signing are missing among: ~/.gradle/google-play-upload.keystore, ~/.gradle/gradle.properties or ~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision." +else +stable_release: + $(Q) rm -rf output/stable_release + $(Q) mkdir -p output/stable_release + $(Q) echo "BUILD_FIRMWARE DEVICE N0110" + $(Q) make clean + $(Q) make -j8 epsilon.official.onboarding.dfu + $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu + $(Q) echo "BUILD_FIRMWARE DEVICE N0100" + $(Q) make MODEL=n0100 clean + $(Q) make -j8 MODEL=n0100 epsilon.official.onboarding.dfu + $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP" + $(Q) make -j8 DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); make -j8 DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip + $(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" + $(Q) $(call source_emsdk); make -j8 DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" + $(Q) make -j8 DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); make -j8 DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js + $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" + $(Q) make -j8 PLATFORM=simulator TARGET=android clean + $(Q) make -j8 PLATFORM=simulator TARGET=android epsilon.official.apk +#TODO: what are the files made by gradle? +# $(Q) cp output/release/simulator/android/epsilon.official.apk output/stable_release/epsilon.apk + $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" + $(Q) make -j8 PLATFORM=simulator TARGET=ios clean + $(Q) make -j8 PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa +#TODO: which files are generated by codesign? +# $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa +endif From a7c26ce3a8ef35ae88a6ee15d2c66c6dc8b94a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 17 Feb 2020 14:56:33 +0100 Subject: [PATCH 013/117] [ion] ios Makefile: fix codesigning --- ion/src/simulator/ios/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index 58dea89ba..b5f94f39d 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -90,7 +90,7 @@ simulator_app_deps += $(call simulator_app_resource,$(1), \ $(BUILD_DIR)/app/epsilon%ipa: $(subst ..,.,$(call simulator_app_deps,Epsilon$*)) ifdef IOS_PROVISIONNING_PROFILE $(call rule_label,SIGN) - $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "iPhone Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon$*app + $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "iPhone Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon.app endif $(call rule_label,ZIP) $(Q) cd $(dir $@) ; zip -qr9 $(notdir $@) Payload From ac6d6f4d5c2816778c77758a0a0293ad3c1dba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 17 Feb 2020 14:57:53 +0100 Subject: [PATCH 014/117] [build] Complete stable_release target --- build/targets.mak | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build/targets.mak b/build/targets.mak index c770b34bf..80ba16aa1 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -88,11 +88,9 @@ stable_release: $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" $(Q) make -j8 PLATFORM=simulator TARGET=android clean $(Q) make -j8 PLATFORM=simulator TARGET=android epsilon.official.apk -#TODO: what are the files made by gradle? -# $(Q) cp output/release/simulator/android/epsilon.official.apk output/stable_release/epsilon.apk + $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" $(Q) make -j8 PLATFORM=simulator TARGET=ios clean $(Q) make -j8 PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa -#TODO: which files are generated by codesign? -# $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa + $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa endif From a92ee368c511bb7704154b00b55806ae58cf407f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 17 Feb 2020 17:23:13 +0100 Subject: [PATCH 015/117] [ion] ios Makefile: fix code-signing with new certificates --- ion/src/simulator/ios/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index b5f94f39d..c19966b28 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -90,7 +90,7 @@ simulator_app_deps += $(call simulator_app_resource,$(1), \ $(BUILD_DIR)/app/epsilon%ipa: $(subst ..,.,$(call simulator_app_deps,Epsilon$*)) ifdef IOS_PROVISIONNING_PROFILE $(call rule_label,SIGN) - $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "iPhone Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon.app + $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "Apple Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon.app endif $(call rule_label,ZIP) $(Q) cd $(dir $@) ; zip -qr9 $(notdir $@) Payload From ef62c70913c3113d0527e21c7f97c57d13fe6c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 18 Feb 2020 10:01:27 +0100 Subject: [PATCH 016/117] [build] Target: clean epsilon targets dependencies --- build/targets.mak | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/build/targets.mak b/build/targets.mak index 80ba16aa1..0f1d0bc16 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -1,23 +1,14 @@ # Define standard Epsilon targets base_src = $(liba_src) $(kandinsky_src) $(escher_src) $(libaxx_src) $(poincare_src) $(python_src) -epsilon_src = $(base_src) $(ion_default_src) $(apps_default_src) -epsilon_official_src = $(base_src) $(ion_default_src) $(apps_official_default_src) -epsilon_onboarding_src = $(base_src) $(ion_default_src) $(apps_onboarding_src) -epsilon_official_onboarding_src = $(base_src) $(ion_default_src) $(apps_official_onboarding_src) -epsilon_onboarding_update_src = $(base_src) $(ion_default_src) $(apps_onboarding_update_src) -epsilon_official_onboarding_update_src = $(base_src) $(ion_default_src) $(apps_official_onboarding_update_src) -epsilon_onboarding_beta_src = $(base_src) $(ion_default_src) $(apps_onboarding_beta_src) -epsilon_official_onboarding_beta_src = $(base_src) $(ion_default_src) $(apps_official_onboarding_beta_src) - -$(BUILD_DIR)/epsilon.$(EXE): $(call object_for,$(epsilon_src)) -$(BUILD_DIR)/epsilon.official.$(EXE): $(call object_for,$(epsilon_official_src)) -$(BUILD_DIR)/epsilon.onboarding.$(EXE): $(call object_for,$(epsilon_onboarding_src)) -$(BUILD_DIR)/epsilon.official.onboarding.$(EXE): $(call object_for,$(epsilon_official_onboarding_src)) -$(BUILD_DIR)/epsilon.onboarding.update.$(EXE): $(call object_for,$(epsilon_onboarding_update_src)) -$(BUILD_DIR)/epsilon.official.onboarding.update.$(EXE): $(call object_for,$(epsilon_official_onboarding_update_src)) -$(BUILD_DIR)/epsilon.onboarding.beta.$(EXE): $(call object_for,$(epsilon_onboarding_beta_src)) -$(BUILD_DIR)/epsilon.official.onboarding.beta.$(EXE): $(call object_for,$(epsilon_official_onboarding_beta_src)) +$(BUILD_DIR)/epsilon.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_default_src)) +$(BUILD_DIR)/epsilon.official.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_default_src)) +$(BUILD_DIR)/epsilon.onboarding.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_src)) +$(BUILD_DIR)/epsilon.official.onboarding.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_src)) +$(BUILD_DIR)/epsilon.onboarding.update.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_update_src)) +$(BUILD_DIR)/epsilon.official.onboarding.update.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_update_src)) +$(BUILD_DIR)/epsilon.onboarding.beta.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_beta_src)) +$(BUILD_DIR)/epsilon.official.onboarding.beta.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_beta_src)) test_base_src = $(base_src) $(apps_tests_src) $(runner_src) $(tests_src) From 6c0bb3cdde4259544c41c16fa32b2792e1c7b8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 18 Feb 2020 11:54:35 +0100 Subject: [PATCH 017/117] [build] Replace make by $(MAKE) in Makefiles --- build/scenario/Makefile | 4 ++-- build/targets.mak | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/scenario/Makefile b/build/scenario/Makefile index aafb398e8..64f65e8bf 100644 --- a/build/scenario/Makefile +++ b/build/scenario/Makefile @@ -1,11 +1,11 @@ .PHONY: scenario_logger scenario_logger: - $(Q) make -j8 PLATFORM=simulator clean && make -j8 DEBUG=1 ARCH=x86_64 PLATFORM=simulator epsilon.headless.bin + $(Q) $(MAKE) PLATFORM=simulator clean && $(MAKE) DEBUG=1 ARCH=x86_64 PLATFORM=simulator epsilon.headless.bin $(Q) cp output/debug/simulator/macos/x86_64/epsilon.headless.bin epsilon_scenario_logger.bin @echo "Run ./epsilon_scenario_logger.bin --logAfter 0 < scenario.esc to log a scenario" .PHONY: scenario_creator scenario_creator: - $(Q) make -j8 PLATFORM=simulator clean && make -j8 DEBUG=1 ESCHER_LOG_EVENTS_BINARY=1 PLATFORM=simulator + $(Q) $(MAKE) PLATFORM=simulator clean && $(MAKE) DEBUG=1 ESCHER_LOG_EVENTS_BINARY=1 PLATFORM=simulator $(Q) cp -R output/debug/simulator/macos/app/Payload/Epsilon.app epsilon_scenario_creator.app @echo "Run lldb epsilon_scenario_creator.app then process launch -o scenario.esc to create a scenario" diff --git a/build/targets.mak b/build/targets.mak index 0f1d0bc16..cdc58c3e4 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -58,30 +58,30 @@ stable_release: $(Q) rm -rf output/stable_release $(Q) mkdir -p output/stable_release $(Q) echo "BUILD_FIRMWARE DEVICE N0110" - $(Q) make clean - $(Q) make -j8 epsilon.official.onboarding.dfu + $(Q) $(MAKE) clean + $(Q) $(MAKE) epsilon.official.onboarding.dfu $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu $(Q) echo "BUILD_FIRMWARE DEVICE N0100" - $(Q) make MODEL=n0100 clean - $(Q) make -j8 MODEL=n0100 epsilon.official.onboarding.dfu + $(Q) $(MAKE) MODEL=n0100 clean + $(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP" - $(Q) make -j8 DEBUG=0 PLATFORM=simulator TARGET=web clean - $(Q) $(call source_emsdk); make -j8 DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip + $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip $(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" - $(Q) $(call source_emsdk); make -j8 DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" - $(Q) make -j8 DEBUG=0 PLATFORM=simulator TARGET=web clean - $(Q) $(call source_emsdk); make -j8 DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js + $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" - $(Q) make -j8 PLATFORM=simulator TARGET=android clean - $(Q) make -j8 PLATFORM=simulator TARGET=android epsilon.official.apk + $(Q) $(MAKE) PLATFORM=simulator TARGET=android clean + $(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" - $(Q) make -j8 PLATFORM=simulator TARGET=ios clean - $(Q) make -j8 PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa endif From 38d02663b420caa208ecbee4bfa55934ebc6eafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 18 Feb 2020 13:50:59 +0100 Subject: [PATCH 018/117] [build] epsilon_src & epsilon_official_src have to be defined because they're used by target.simulator.web.mak --- Makefile | 2 +- apps/Makefile | 2 +- build/targets.mak | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8594beee0..46acaaa5a 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ include build/struct_layout/Makefile include build/scenario/Makefile include quiz/Makefile # Quiz needs to be included at the end -all_src = $(apps_all_src) $(escher_src) $(ion_all_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(poincare_src) $(python_src) $(epsilon_src) $(runner_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(ion_target_device_bench_src) $(tests_src) +all_src = $(apps_all_src) $(escher_src) $(ion_all_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(poincare_src) $(python_src) $(runner_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(ion_target_device_bench_src) $(tests_src) all_objs = $(call object_for,$(all_src)) .SECONDARY: $(all_objs) diff --git a/apps/Makefile b/apps/Makefile index a61605344..c3af54608 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -89,7 +89,7 @@ $(BUILD_DIR)/apps/i18n.h: $(BUILD_DIR)/apps/i18n.cpp $(eval $(call depends_on_image,apps/title_bar_view.cpp,apps/exam_icon.png)) -all_app_src = $(app_src) $(epsilon_src) $(apps_launch_on_boarding_src) $(apps_launch_default_src) $(apps_prompt_none_src) $(apps_prompt_update_src) $(apps_prompt_beta_src) $(apps_official) $(apps_non_official) $(tests_src) +all_app_src = $(app_src)(apps_launch_on_boarding_src) $(apps_launch_default_src) $(apps_prompt_none_src) $(apps_prompt_update_src) $(apps_prompt_beta_src) $(apps_official) $(apps_non_official) $(tests_src) $(call object_for,$(all_app_src)): $(BUILD_DIR)/apps/i18n.h $(call object_for,$(all_app_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.generated.h diff --git a/build/targets.mak b/build/targets.mak index cdc58c3e4..4f28bd056 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -1,8 +1,11 @@ # Define standard Epsilon targets base_src = $(liba_src) $(kandinsky_src) $(escher_src) $(libaxx_src) $(poincare_src) $(python_src) -$(BUILD_DIR)/epsilon.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_default_src)) -$(BUILD_DIR)/epsilon.official.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_default_src)) +epsilon_src = $(base_src) $(ion_default_src) $(apps_default_src) +epsilon_official_src = $(base_src) $(ion_default_src) $(apps_official_default_src) + +$(BUILD_DIR)/epsilon.$(EXE): $(call object_for,$(epsilon_src)) +$(BUILD_DIR)/epsilon.official.$(EXE): $(call object_for,$(epsilon_official_src)) $(BUILD_DIR)/epsilon.onboarding.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_src)) $(BUILD_DIR)/epsilon.official.onboarding.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_src)) $(BUILD_DIR)/epsilon.onboarding.update.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_update_src)) From c8cbd9475d15074d4bef43cf72b19935c87b87a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 18 Feb 2020 14:05:18 +0100 Subject: [PATCH 019/117] [ion] android Makefile: declare targets as PHONY --- ion/src/simulator/android/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index 0d6789477..44771b25e 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -72,7 +72,7 @@ $(eval $(call rule_for_gradle,assembleRelease,.official.)) DEFAULT = epsilon.apk -.PHONY: epsilon.apk +.PHONY: epsilon%apk ifdef ANDROID_SIGNING_STORE_FILE epsilon%apk: gradle_assembleCodesigned_% else From 3aeb4b9ea96b5cc79013f0d45b2d96a1a6f603eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 18 Feb 2020 16:44:07 +0100 Subject: [PATCH 020/117] [build] Coding style --- build/targets.device.n0110.mak | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 556bae335..5b5078ac5 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -33,15 +33,15 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex binpack: rm -rf output/binpack mkdir -p output/binpack - ${MAKE} clean - ${MAKE} $(BUILD_DIR)/flasher.light.bin + $(MAKE) clean + $(MAKE) $(BUILD_DIR)/flasher.light.bin cp $(BUILD_DIR)/flasher.light.bin output/binpack - ${MAKE} $(BUILD_DIR)/bench.flash.bin - ${MAKE} $(BUILD_DIR)/bench.ram.bin + $(MAKE) $(BUILD_DIR)/bench.flash.bin + $(MAKE) $(BUILD_DIR)/bench.ram.bin cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack - ${MAKE} epsilon.official.onboarding.update.two_binaries + $(MAKE) epsilon.official.onboarding.update.two_binaries cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack - ${MAKE} clean + $(MAKE) clean cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack rm -rf output/binpack From d2e9d5fbea4db6a9739129c1e23b378c751b2046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 20 Feb 2020 11:58:14 +0100 Subject: [PATCH 021/117] [build] Split stable_release target from target.mak, change name to all_official --- build/targets.all.mak | 60 +++++++++++++++++++++++++++++++++++++++++++ build/targets.mak | 53 +------------------------------------- 2 files changed, 61 insertions(+), 52 deletions(-) create mode 100644 build/targets.all.mak diff --git a/build/targets.all.mak b/build/targets.all.mak new file mode 100644 index 000000000..989c4fb7b --- /dev/null +++ b/build/targets.all.mak @@ -0,0 +1,60 @@ +ANDROID_GRADLE_KEYSTORE ?= ~/.gradle/google-play-upload.keystore +ANDROID_GRADLE_PROPERTIES ?= ~/.gradle/gradle.properties +IOS_MOBILE_PROVISION ?= build/artifacts/NumWorks_Graphing_Calculator_Distribution.mobileprovision +EMCC ?= emcc + +define source_emsdk +source ~/emsdk/emsdk_env.sh > /dev/null +endef + +define file_check +@ if test ! -f $(1); \ + then \ + echo "Missing file: $(1)"; \ + exit 1; \ +fi +endef + +define command_check +@ if ! command -v $(1) > /dev/null; \ + then \ + echo "Missing command: $(1), did you forget to source?"; \ + exit 1; \ +fi +endef + +.PHONY: all_official +all_official: + $(call file_check,$(ANDROID_GRADLE_KEYSTORE)) + $(call file_check,$(ANDROID_GRADLE_PROPERTIES)) + $(call file_check,$(IOS_MOBILE_PROVISION)) + $(call command_check,$(EMCC)) + $(Q) rm -rf output/stable_release + $(Q) mkdir -p output/stable_release + $(Q) echo "BUILD_FIRMWARE DEVICE N0110" + $(Q) $(MAKE) clean + $(Q) $(MAKE) epsilon.official.onboarding.dfu + $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu + $(Q) echo "BUILD_FIRMWARE DEVICE N0100" + $(Q) $(MAKE) MODEL=n0100 clean + $(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu + $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP" + $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip + $(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" + $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js + $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" + $(Q) $(MAKE) PLATFORM=simulator TARGET=android clean + $(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk + $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk + $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa + $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa diff --git a/build/targets.mak b/build/targets.mak index 4f28bd056..ca7b9d97c 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -36,55 +36,4 @@ endef $(foreach extension,$(HANDY_TARGETS_EXTENSIONS),$(foreach executable,$(HANDY_TARGETS),$(eval $(call handy_target_rule,$(executable),$(extension))))) -define source_emsdk -source ~/emsdk/emsdk_env.sh > /dev/null -endef - -ANDROID_GRADLE_KEYSTORE:= $(wildcard ~/.gradle/google-play-upload.keystore) -ANDROID_GRADLE_PROPERTIES:= $(wildcard ~/.gradle/gradle.properties) -IOS_MOBILE_PROVISION:= $(wildcard ~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision) - -MISSING_FILES=1 - -ifneq "$(and $(ANDROID_GRADLE_KEYSTORE),$(ANDROID_GRADLE_PROPERTIES))" "" -ifneq "$(IOS_MOBILE_PROVISION)" "" - MISSING_FILES=0 -endif -endif - -.PHONY: stable_release -ifeq ($(MISSING_FILES),1) -stable_release: - @echo "Some required files for app signing are missing among: ~/.gradle/google-play-upload.keystore, ~/.gradle/gradle.properties or ~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision." -else -stable_release: - $(Q) rm -rf output/stable_release - $(Q) mkdir -p output/stable_release - $(Q) echo "BUILD_FIRMWARE DEVICE N0110" - $(Q) $(MAKE) clean - $(Q) $(MAKE) epsilon.official.onboarding.dfu - $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu - $(Q) echo "BUILD_FIRMWARE DEVICE N0100" - $(Q) $(MAKE) MODEL=n0100 clean - $(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu - $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu - $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP" - $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean - $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip - $(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip - $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" - $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js - $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js - $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" - $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean - $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js - $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js - $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" - $(Q) $(MAKE) PLATFORM=simulator TARGET=android clean - $(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk - $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk - $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" - $(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean - $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa - $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa -endif +include build/targets.all.mak From 8075468568e5ffc7726f61da72ed809c36500a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 20 Feb 2020 12:02:37 +0100 Subject: [PATCH 022/117] .gitignore: add build/artefacts --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a43c2d871..b69802123 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /output/ +/build/artifacts/ build/device/**/*.pyc From 7b00072ccf5fcca70f044f160236c58efeebca67 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 10:29:13 +0100 Subject: [PATCH 023/117] [apps/regression/graph_controller] Factor m_roundCursorView.setColor in setRoundCrossCursorView --- apps/regression/graph_controller.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 78f8ea350..3e23236ca 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -88,14 +88,12 @@ void GraphController::viewWillAppear() { setRoundCrossCursorView(false); } else { setRoundCrossCursorView(true); - m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); } } void GraphController::selectRegressionCurve() { *m_selectedDotIndex = -1; setRoundCrossCursorView(true); - m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); } // Private @@ -405,7 +403,12 @@ InteractiveCurveViewRangeDelegate::Range GraphController::computeYRange(Interact } void GraphController::setRoundCrossCursorView(bool round) { + if (round) { + // Set the color although the cursor view stays round + m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); + } CursorView * nextCursorView = round ? static_cast(&m_roundCursorView) : static_cast(&m_crossCursorView); + // Escape if the cursor view stays the same if (m_view.cursorView() == nextCursorView) { return; } From d13c2438763459188f2acb78dba8aa9da688c278 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 10:30:48 +0100 Subject: [PATCH 024/117] [apps/regression/graph_controller] Simplify viewWillAppear --- apps/regression/graph_controller.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 3e23236ca..dd1442568 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -84,11 +84,7 @@ void GraphController::viewWillAppear() { /* Since *m_selectedDotIndex is altered by initCursorParameters(), * the following must absolutely come at the end. */ - if (*m_selectedDotIndex >= 0) { - setRoundCrossCursorView(false); - } else { - setRoundCrossCursorView(true); - } + setRoundCrossCursorView(*m_selectedDotIndex < 0); } void GraphController::selectRegressionCurve() { From 7e6a601af0f92d115dce52ac354072f4cbff38ec Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 13:59:18 +0100 Subject: [PATCH 025/117] [apps/regression/graph_controller] Inline selectRegressionCurve in moveCursorVertically In the graph controller, selectRegressionCurve is only called at one place (in moveCursorVertically). In general, setRoundCrossCursorView is called and *m_selectedDotIndex is updated. There is no reason at all to do things differently. Though selectRegressionCurve is called from GoToParameterController. --- apps/regression/graph_controller.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index dd1442568..fa11d95ff 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -321,7 +321,8 @@ bool GraphController::moveCursorVertically(int direction) { if (validRegression) { // Select the regression *m_selectedSeriesIndex = closestRegressionSeries; - selectRegressionCurve(); + *m_selectedDotIndex = -1; + setRoundCrossCursorView(true); m_cursor->moveTo(x, x, yValue(*m_selectedSeriesIndex, x, context)); return true; } From 436b934f7644e0ab6a35268172e7061748cf6b9b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 14:01:47 +0100 Subject: [PATCH 026/117] [apps/regression/graph_controller] selectRegressionCurve does not update the cursor view selectRegressionCurve is only called from GoToParameterController and is part of the GraphController's API for updating the model. It should not update the view. viewWillAppear does. --- apps/regression/graph_controller.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index fa11d95ff..7209e37e0 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -89,7 +89,6 @@ void GraphController::viewWillAppear() { void GraphController::selectRegressionCurve() { *m_selectedDotIndex = -1; - setRoundCrossCursorView(true); } // Private From 4f279f15da539c648bc2c2812d554c5912e6a1fc Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 14:43:10 +0100 Subject: [PATCH 027/117] [apps/regression/graph_controller] Inline selectRegressionCurve in header --- apps/regression/graph_controller.cpp | 4 ---- apps/regression/graph_controller.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 7209e37e0..4be142546 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -87,10 +87,6 @@ void GraphController::viewWillAppear() { setRoundCrossCursorView(*m_selectedDotIndex < 0); } -void GraphController::selectRegressionCurve() { - *m_selectedDotIndex = -1; -} - // Private Poincare::Context * GraphController::globalContext() { diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 0c35ad9ab..2011c9735 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -21,7 +21,7 @@ public: bool isEmpty() const override; I18n::Message emptyMessage() override; void viewWillAppear() override; - void selectRegressionCurve(); + void selectRegressionCurve() { *m_selectedDotIndex = -1; } int selectedSeriesIndex() const { return *m_selectedSeriesIndex; } // moveCursorHorizontally and Vertically are public to be used in tests From b8b6e4b5b8398f6d2f3a064232fd120150575cf7 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 16:31:37 +0100 Subject: [PATCH 028/117] [apps/regression/graph_controller] Update model before setting cursor view --- apps/regression/graph_controller.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 4be142546..cec30642f 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -313,6 +313,8 @@ bool GraphController::moveCursorVertically(int direction) { assert(!validDot || !validRegression); + /* The model should be up to date before setting the cursor view. */ + if (validRegression) { // Select the regression *m_selectedSeriesIndex = closestRegressionSeries; @@ -324,9 +326,9 @@ bool GraphController::moveCursorVertically(int direction) { if (validDot) { // Select the dot - setRoundCrossCursorView(false); *m_selectedSeriesIndex = closestDotSeries; *m_selectedDotIndex = dotSelected; + setRoundCrossCursorView(false); if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { // Select the mean dot double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); @@ -395,6 +397,8 @@ InteractiveCurveViewRangeDelegate::Range GraphController::computeYRange(Interact } void GraphController::setRoundCrossCursorView(bool round) { + /* At this point, the model (selected series and dot indices) should be up + * to date. */ if (round) { // Set the color although the cursor view stays round m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); From bdb29b9bf91e32084cdbf18dd8913404bac36af2 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 16:35:22 +0100 Subject: [PATCH 029/117] [apps/regression/graph_controller] Remove setRoundCrossCursorView's parameter Get it directly from model --- apps/regression/graph_controller.cpp | 9 +++++---- apps/regression/graph_controller.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index cec30642f..b59809bca 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -84,7 +84,7 @@ void GraphController::viewWillAppear() { /* Since *m_selectedDotIndex is altered by initCursorParameters(), * the following must absolutely come at the end. */ - setRoundCrossCursorView(*m_selectedDotIndex < 0); + setRoundCrossCursorView(); } // Private @@ -319,7 +319,7 @@ bool GraphController::moveCursorVertically(int direction) { // Select the regression *m_selectedSeriesIndex = closestRegressionSeries; *m_selectedDotIndex = -1; - setRoundCrossCursorView(true); + setRoundCrossCursorView(); m_cursor->moveTo(x, x, yValue(*m_selectedSeriesIndex, x, context)); return true; } @@ -328,7 +328,7 @@ bool GraphController::moveCursorVertically(int direction) { // Select the dot *m_selectedSeriesIndex = closestDotSeries; *m_selectedDotIndex = dotSelected; - setRoundCrossCursorView(false); + setRoundCrossCursorView(); if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { // Select the mean dot double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); @@ -396,9 +396,10 @@ InteractiveCurveViewRangeDelegate::Range GraphController::computeYRange(Interact return range; } -void GraphController::setRoundCrossCursorView(bool round) { +void GraphController::setRoundCrossCursorView() { /* At this point, the model (selected series and dot indices) should be up * to date. */ + bool round = *m_selectedDotIndex < 0; if (round) { // Set the color although the cursor view stays round m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 2011c9735..f1c257a12 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -55,7 +55,7 @@ private: // InteractiveCurveViewRangeDelegate Shared::InteractiveCurveViewRangeDelegate::Range computeYRange(Shared::InteractiveCurveViewRange * interactiveCurveViewRange) override; - void setRoundCrossCursorView(bool round); + void setRoundCrossCursorView(); Shared::CursorView m_crossCursorView; Shared::RoundCursorView m_roundCursorView; BannerView m_bannerView; From f74ed8ecd7f67bf36b9532b65eb3df1d4551a36f Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 22 Feb 2020 11:05:38 +0000 Subject: [PATCH 030/117] [ion] Fix error check in the USB stack The return type of the function receiveSomeData needs to be wider so the -1 error value could fit. Fixes #1335 --- ion/src/device/shared/usb/stack/endpoint0.cpp | 2 +- ion/src/device/shared/usb/stack/endpoint0.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ion/src/device/shared/usb/stack/endpoint0.cpp b/ion/src/device/shared/usb/stack/endpoint0.cpp index 14478a086..4e1d4e980 100644 --- a/ion/src/device/shared/usb/stack/endpoint0.cpp +++ b/ion/src/device/shared/usb/stack/endpoint0.cpp @@ -259,7 +259,7 @@ void Endpoint0::clearForOutTransactions(uint16_t wLength) { setOutNAK(false); } -uint16_t Endpoint0::receiveSomeData() { +int Endpoint0::receiveSomeData() { // If it is the first chunk of data to be received, m_transferBufferLength is 0. uint16_t packetSize = MIN(k_maxPacketSize, m_request.wLength() - m_transferBufferLength); uint16_t sizeOfPacketRead = readPacket(m_largeBuffer + m_transferBufferLength, packetSize); diff --git a/ion/src/device/shared/usb/stack/endpoint0.h b/ion/src/device/shared/usb/stack/endpoint0.h index ca6809bfb..a0ef41686 100644 --- a/ion/src/device/shared/usb/stack/endpoint0.h +++ b/ion/src/device/shared/usb/stack/endpoint0.h @@ -57,7 +57,7 @@ public: void clearForOutTransactions(uint16_t wLength); private: - uint16_t receiveSomeData(); + int receiveSomeData(); uint16_t readPacket(void * buffer, uint16_t length); uint16_t writePacket(const void * buffer, uint16_t length); From 2913bcb8b51ceabc4b18cb2290550bb906d48777 Mon Sep 17 00:00:00 2001 From: David <0b101@users.noreply.github.com> Date: Wed, 26 Feb 2020 10:44:52 -0600 Subject: [PATCH 031/117] [Fix] Bug with the default display mode --- apps/calculation/history_view_cell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index ce6360029..ff41c7b3e 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -186,7 +186,7 @@ void HistoryViewCell::layoutSubviews(bool force) { force); KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay(); int singleLine = outputSize.width() + inputSize.width() < bounds().width() - 6; - int outputHeight = (singleLine) ? (maxCoordinate(0, inputSize.height() - outputSize.height()) / 2) + maxCoordinate(0, (inputSize.height() - outputSize.height()) / 2) : inputSize.height(); + int outputHeight = (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) ? (maxCoordinate(0, inputSize.height() - outputSize.height()) / 2) + maxCoordinate(0, (inputSize.height() - outputSize.height()) / 2) : inputSize.height(); m_scrollableOutputView.setFrame(KDRect( maxCoordinate(0, maxFrameWidth - outputSize.width()), outputHeight, From f12c53b3f2c76f0970f32ec5ca006a3f495c3077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 25 Feb 2020 10:18:11 +0100 Subject: [PATCH 032/117] [apps/code] printText should not be asynchronous in emscripten Otherwise, we need to put in the whitelist all methods that might call printText, which are a lot. --- apps/code/console_controller.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index b920fd714..5d236b337 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -433,11 +433,26 @@ void ConsoleController::printText(const char * text, size_t length) { flushOutputAccumulationBufferToStore(); micropython_port_vm_hook_refresh_print(); } +#if __EMSCRIPTEN__ + /* If we called micropython_port_interrupt_if_needed here, we would need to + * put in the WHITELIST all the methods that call + * ConsoleController::printText, which means all the MicroPython methods that + * call print... This is a lot of work + might reduce the performance as + * emterpreted code is slower. + * + * We thus do not allow print interruption on the web simulator. It would be + * better to allow it, but the biggest problem was on the device anyways + * -> It is much quicker to interrupt Python on the web simulator than on the + * device. + * + * TODO: Allow print interrpution on emscripten -> maybe by using WASM=1 ? */ +#else /* micropython_port_vm_hook_loop is not enough to detect user interruptions, * because it calls micropython_port_interrupt_if_needed every 20000 * operations, and a print operation is quite long. We thus explicitely call * micropython_port_interrupt_if_needed here. */ micropython_port_interrupt_if_needed(); +#endif } void ConsoleController::autoImportScript(Script script, bool force) { From 4da9f34993858bf47baba7638aa6956ad2200f79 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Fri, 21 Feb 2020 20:34:27 +0000 Subject: [PATCH 033/117] [poincare] Fix checking for special tree identifier value Unsigned types are never negative, so the existant check does not make sense. Check correctly using the newly introduced TreeNode::IsValidIdentifier method. --- poincare/include/poincare/tree_handle.h | 2 +- poincare/include/poincare/tree_node.h | 2 ++ poincare/include/poincare/tree_pool.h | 4 ++-- poincare/src/tree_pool.cpp | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/poincare/include/poincare/tree_handle.h b/poincare/include/poincare/tree_handle.h index 68f99b41a..5e2a07d9b 100644 --- a/poincare/include/poincare/tree_handle.h +++ b/poincare/include/poincare/tree_handle.h @@ -128,7 +128,7 @@ protected: void setIdentifierAndRetain(uint16_t newId); void setTo(const TreeHandle & tr); - static bool hasNode(uint16_t identifier) { return identifier < TreeNode::NoNodeIdentifier; } + static bool hasNode(uint16_t identifier) { return TreeNode::IsValidIdentifier(identifier); } /* Hierarchy operations */ // Add diff --git a/poincare/include/poincare/tree_node.h b/poincare/include/poincare/tree_node.h index f46d6ff9a..71d1df351 100644 --- a/poincare/include/poincare/tree_node.h +++ b/poincare/include/poincare/tree_node.h @@ -172,6 +172,8 @@ public: void log(std::ostream & stream, bool recursive = true); #endif + static bool IsValidIdentifier(uint16_t id) { return id < NoNodeIdentifier; } + protected: TreeNode() : m_identifier(NoNodeIdentifier), diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index 463c41ec8..0da0d8f80 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -27,7 +27,7 @@ public: // Node TreeNode * node(uint16_t identifier) const { - assert(identifier >= 0 && identifier < MaxNumberOfNodes); + assert(TreeNode::IsValidIdentifier(identifier) && identifier < MaxNumberOfNodes); if (m_nodeForIdentifierOffset[identifier] != UINT16_MAX) { return const_cast(reinterpret_cast(m_alignedBuffer + m_nodeForIdentifierOffset[identifier])); } @@ -125,7 +125,7 @@ private: } } void push(uint16_t i) { - assert(m_currentIndex >= 0 && m_currentIndex < MaxNumberOfNodes); + assert(TreeNode::IsValidIdentifier(m_currentIndex) && m_currentIndex < MaxNumberOfNodes); m_availableIdentifiers[m_currentIndex++] = i; } uint16_t pop() { diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 00895e05d..7ab75d0d7 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -14,7 +14,7 @@ namespace Poincare { TreePool * TreePool::SharedStaticPool = nullptr; void TreePool::freeIdentifier(uint16_t identifier) { - if (identifier >= 0 && identifier < MaxNumberOfNodes) { + if (TreeNode::IsValidIdentifier(identifier) && identifier < MaxNumberOfNodes) { m_nodeForIdentifierOffset[identifier] = UINT16_MAX; m_identifiers.push(identifier); } From 9a79081b4794437aa0ae5d672114f7bea523b44f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 26 Feb 2020 16:35:56 +0100 Subject: [PATCH 034/117] [poincare/expression] Fix typo in nextIntersection The approximative solution should be rounded up to zero if it is dominated by the solver's precision. --- poincare/src/expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index a4793bc69..0b55f61a7 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -1003,7 +1003,7 @@ Coordinate2D Expression::nextIntersection(const char * symbol, double st return expression0->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit)-expression1->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit); }, context, complexFormat, angleUnit, expression); Coordinate2D result(resultAbscissa, approximateWithValueForSymbol(symbol, resultAbscissa, context, complexFormat, angleUnit)); - if (std::fabs(result.x2()) < step*k_solverPrecision) { + if (std::fabs(result.x2()) < std::fabs(step)*k_solverPrecision) { result.setX2(0.0); } return result; From 74f77054135063ff4354a4a3553c31f96cfb295a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 26 Feb 2020 16:45:25 +0100 Subject: [PATCH 035/117] [poincare/solver] Fix typo --- poincare/src/solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/solver.cpp b/poincare/src/solver.cpp index d78b1e5bf..ac43c9646 100644 --- a/poincare/src/solver.cpp +++ b/poincare/src/solver.cpp @@ -133,7 +133,7 @@ double Solver::BrentRoot(double ax, double bx, double precision, ValueAtAbscissa double xm = 0.5*(c-b); if (std::fabs(xm) <= tol1 || fb == 0.0) { double fbcMiddle = evaluation(0.5*(b+c), context, complexFormat, angleUnit, context1, context2, context3); - double isContinuous = (fb <= fbcMiddle && fbcMiddle <= fc) || (fc <= fbcMiddle && fbcMiddle <= fb); + bool isContinuous = (fb <= fbcMiddle && fbcMiddle <= fc) || (fc <= fbcMiddle && fbcMiddle <= fb); if (isContinuous) { return b; } From bb24c21320b0a4b7b6ea99a185a4ec526c8fab2e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 26 Feb 2020 16:47:01 +0100 Subject: [PATCH 036/117] [poincare/solver] Fix typo in BrentRoot algorithm --- poincare/src/solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/solver.cpp b/poincare/src/solver.cpp index ac43c9646..33914717e 100644 --- a/poincare/src/solver.cpp +++ b/poincare/src/solver.cpp @@ -138,7 +138,7 @@ double Solver::BrentRoot(double ax, double bx, double precision, ValueAtAbscissa return b; } } - if (std::fabs(e) >= tol1 && std::fabs(fa) > std::fabs(b)) { + if (std::fabs(e) >= tol1 && std::fabs(fa) > std::fabs(fb)) { double s = fb/fa; double p = 2.0*xm*s; double q = 1.0-s; @@ -168,7 +168,7 @@ double Solver::BrentRoot(double ax, double bx, double precision, ValueAtAbscissa if (std::fabs(d) > tol1) { b += d; } else { - b += xm > 0.0 ? tol1 : tol1; + b += xm > 0.0 ? tol1 : -tol1; } fb = evaluation(b, context, complexFormat, angleUnit, context1, context2, context3); } From a72e4d43ae1c042e0247d9dddcbc8de1e1cd5bc1 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 26 Feb 2020 16:48:57 +0100 Subject: [PATCH 037/117] [poincare/expression] Short-circuit brentMinimum and brentRoot --- poincare/include/poincare/expression.h | 2 -- poincare/src/expression.cpp | 31 ++------------------------ 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index d1a887c03..dea1fe006 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -413,10 +413,8 @@ private: constexpr static double k_maxFloat = 1e100; Coordinate2D nextMinimumOfExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression(), bool lookForRootMinimum = false) const; void bracketMinimum(const char * symbol, double start, double step, double max, double result[3], Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression()) const; - Coordinate2D brentMinimum(const char * symbol, double ax, double bx, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression()) const; double nextIntersectionWithExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const; void bracketRoot(const char * symbol, double start, double step, double max, double result[2], Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const; - double brentRoot(const char * symbol, double ax, double bx, double precision, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const; }; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 0b55f61a7..1bdfc8e71 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -1019,7 +1019,7 @@ Coordinate2D Expression::nextMinimumOfExpression(const char * symbol, do bool endCondition = false; do { bracketMinimum(symbol, x, step, max, bracket, evaluate, context, complexFormat, angleUnit, expression); - result = brentMinimum(symbol, bracket[0], bracket[2], evaluate, context, complexFormat, angleUnit, expression); + result = Solver::BrentMinimum(bracket[0], bracket[2], evaluate, context, complexFormat, angleUnit, this, symbol, &expression); x = bracket[1]; // Because of float approximation, exact zero is never reached if (std::fabs(result.x1()) < std::fabs(step)*k_solverPrecision) { @@ -1077,19 +1077,6 @@ void Expression::bracketMinimum(const char * symbol, double start, double step, result[2] = NAN; } -Coordinate2D Expression::brentMinimum(const char * symbol, double ax, double bx, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const { - return Solver::BrentMinimum( - ax, - bx, - evaluation, - context, - complexFormat, - angleUnit, - this, - symbol, - &expression); -} - double Expression::nextIntersectionWithExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const { if (start == max || step == 0.0) { return NAN; @@ -1100,7 +1087,7 @@ double Expression::nextIntersectionWithExpression(const char * symbol, double st double x = start+step; do { bracketRoot(symbol, x, step, max, bracket, evaluation, context, complexFormat, angleUnit, expression); - result = brentRoot(symbol, bracket[0], bracket[1], std::fabs(step/precisionByGradUnit), evaluation, context, complexFormat, angleUnit, expression); + result = Solver::BrentRoot(bracket[0], bracket[1], std::fabs(step/precisionByGradUnit), evaluation, context, complexFormat, angleUnit, this, symbol, &expression); x = bracket[1]; } while (std::isnan(result) && (step > 0.0 ? x <= max : x >= max)); @@ -1149,20 +1136,6 @@ void Expression::bracketRoot(const char * symbol, double start, double step, dou result[1] = NAN; } -double Expression::brentRoot(const char * symbol, double ax, double bx, double precision, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const { - return Solver::BrentRoot( - ax, - bx, - precision, - evaluation, - context, - complexFormat, - angleUnit, - this, - symbol, - &expression); -} - template float Expression::Epsilon(); template double Expression::Epsilon(); From 2d22887eaf10f06f11bd89a612730ad3936e3264 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 11:07:58 +0100 Subject: [PATCH 038/117] [poincare/test/function_solver] Factor Poincare::Context usage --- poincare/test/function_solver.cpp | 47 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index e95d77b30..104f9ba99 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -27,23 +27,23 @@ void assert_next_extrema_are( Coordinate2D * extrema, Expression e, const char * symbol, - Context * context, double start = -1.0, double step = 0.1, double max = 100.0, Preferences::ComplexFormat complexFormat = Preferences::ComplexFormat::Real, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { + Shared::GlobalContext context; double currentStart = start; for (int i = 0; i < numberOfExtrema; i++) { quiz_assert_log_if_failure(!std::isnan(currentStart), e); Coordinate2D nextExtrema; if (extremumType == ExtremumType::Maximum) { - nextExtrema = e.nextMaximum(symbol, currentStart, step, max, context, complexFormat, angleUnit); + nextExtrema = e.nextMaximum(symbol, currentStart, step, max, &context, complexFormat, angleUnit); } else if (extremumType == ExtremumType::Minimum) { - nextExtrema = e.nextMinimum(symbol, currentStart, step, max, context, complexFormat, angleUnit); + nextExtrema = e.nextMinimum(symbol, currentStart, step, max, &context, complexFormat, angleUnit); } else if (extremumType == ExtremumType::Root) { - nextExtrema = Coordinate2D(e.nextRoot(symbol, currentStart, step, max, context, complexFormat, angleUnit), 0.0 ); + nextExtrema = Coordinate2D(e.nextRoot(symbol, currentStart, step, max, &context, complexFormat, angleUnit), 0.0 ); } currentStart = nextExtrema.x1() + step; quiz_assert_log_if_failure( @@ -56,7 +56,6 @@ void assert_next_extrema_are( QUIZ_CASE(poincare_function_extremum) { const char * symbol = "a"; int symbolLength = strlen(symbol); - Shared::GlobalContext globalContext; { // cos Expression e = Cosine::Builder(Symbol::Builder(symbol, symbolLength)); @@ -66,13 +65,13 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0), Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol, &globalContext, -1.0, 0.1, 500.0); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol, -1.0, 0.1, 500.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol, &globalContext, 0.0, 0.1, 300.0); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol, 0.0, 0.1, 300.0); } } { @@ -82,13 +81,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol); } } @@ -99,13 +98,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol); } } @@ -116,13 +115,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol); } } } @@ -130,7 +129,6 @@ QUIZ_CASE(poincare_function_extremum) { QUIZ_CASE(poincare_function_root) { const char * symbol = "a"; int symbolLength = strlen(symbol); - Shared::GlobalContext globalContext; { // cos Expression e = Cosine::Builder(Symbol::Builder(symbol, symbolLength)); @@ -139,7 +137,7 @@ QUIZ_CASE(poincare_function_root) { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, &globalContext, 0.0, 0.1, 500.0); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, 0.0, 0.1, 500.0); } { // x^2 @@ -147,7 +145,7 @@ QUIZ_CASE(poincare_function_root) { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol); } { // x^2-4 @@ -156,7 +154,7 @@ QUIZ_CASE(poincare_function_root) { Coordinate2D roots[numberOfRoots] = { Coordinate2D(-2.0, 0.0), Coordinate2D(2.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, &globalContext, -5.0); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, -5.0); } { // 3 @@ -164,7 +162,7 @@ QUIZ_CASE(poincare_function_root) { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol); } { @@ -173,7 +171,7 @@ QUIZ_CASE(poincare_function_root) { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, &globalContext); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol); } } @@ -184,17 +182,17 @@ void assert_next_intersections_are( Coordinate2D * intersections, Expression e, const char * symbol, - Context * context, double start = -1.0, double step = 0.1, double max = 500.0, Preferences::ComplexFormat complexFormat = Preferences::ComplexFormat::Real, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { + Shared::GlobalContext context; double currentStart = start; for (int i = 0; i < numberOfIntersections; i++) { quiz_assert_log_if_failure(!std::isnan(currentStart), e); - Coordinate2D nextIntersection = e.nextIntersection(symbol, currentStart, step, max, context, complexFormat, angleUnit, otherExpression); + Coordinate2D nextIntersection = e.nextIntersection(symbol, currentStart, step, max, &context, complexFormat, angleUnit, otherExpression); currentStart = nextIntersection.x1() + step; quiz_assert_log_if_failure( (doubles_are_approximately_equal(intersections[i].x1(), nextIntersection.x1())) @@ -205,7 +203,6 @@ void assert_next_intersections_are( QUIZ_CASE(poincare_function_intersection) { const char * symbol = "a"; int symbolLength = strlen(symbol); - Shared::GlobalContext globalContext; Expression e = Cosine::Builder(Symbol::Builder(symbol, symbolLength)); { @@ -214,7 +211,7 @@ QUIZ_CASE(poincare_function_intersection) { constexpr int numberOfIntersections = 1; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(NAN, NAN)}; - assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol, &globalContext); + assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol); } { @@ -224,7 +221,7 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0)}; - assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol, &globalContext); + assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol); } { @@ -235,6 +232,6 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol, &globalContext); + assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol); } } From d6b2be1b05d0ab5bca7250e739bb4be88a457b51 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 11:25:10 +0100 Subject: [PATCH 039/117] [poincare/test/function_solver] Build Expressions by parsing text --- poincare/test/function_solver.cpp | 83 +++++++++---------------------- 1 file changed, 24 insertions(+), 59 deletions(-) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index 104f9ba99..956484273 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -1,5 +1,4 @@ #include -#include #include "helper.h" using namespace Poincare; @@ -25,7 +24,7 @@ void assert_next_extrema_are( ExtremumType extremumType, int numberOfExtrema, Coordinate2D * extrema, - Expression e, + const char * expression, const char * symbol, double start = -1.0, double step = 0.1, @@ -34,6 +33,7 @@ void assert_next_extrema_are( Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { Shared::GlobalContext context; + Poincare::Expression e = parse_expression(expression, &context, false); double currentStart = start; for (int i = 0; i < numberOfExtrema; i++) { quiz_assert_log_if_failure(!std::isnan(currentStart), e); @@ -54,133 +54,107 @@ void assert_next_extrema_are( } QUIZ_CASE(poincare_function_extremum) { - const char * symbol = "a"; - int symbolLength = strlen(symbol); { - // cos - Expression e = Cosine::Builder(Symbol::Builder(symbol, symbolLength)); { constexpr int numberOfMaxima = 3; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0), Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol, -1.0, 0.1, 500.0); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "cos(a)", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol, 0.0, 0.1, 300.0); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "cos(a)", "a", 0.0, 0.1, 300.0); } } { - // x^2 - Expression e = Power::Builder(Symbol::Builder(symbol, symbolLength), Rational::Builder(2)); { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "a^2", "a"); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "a^2", "a"); } } - { - // 3 - Expression e = Rational::Builder(3); { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "3", "a"); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "3", "a"); } } - { - // 0 - Expression e = Rational::Builder(0); { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, e, symbol); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "0", "a"); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, e, symbol); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "0", "a"); } } } QUIZ_CASE(poincare_function_root) { - const char * symbol = "a"; - int symbolLength = strlen(symbol); { - // cos - Expression e = Cosine::Builder(Symbol::Builder(symbol, symbolLength)); constexpr int numberOfRoots = 3; Coordinate2D roots[numberOfRoots] = { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, 0.0, 0.1, 500.0); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "cos(a)", "a", 0.0, 0.1, 500.0); } { - // x^2 - Expression e = Power::Builder(Symbol::Builder(symbol, symbolLength), Rational::Builder(2)); constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2", "a"); } { - // x^2-4 - Expression e = Subtraction::Builder(Power::Builder(Symbol::Builder(symbol, symbolLength), Rational::Builder(2)), Rational::Builder(4)); constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-2.0, 0.0), Coordinate2D(2.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol, -5.0); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2-4", "a", -5.0); } { - // 3 - Expression e = Rational::Builder(3); constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "3", "a"); } - { - // 0 - Expression e = Rational::Builder(0); constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, e, symbol); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "0", "a"); } - } void assert_next_intersections_are( - Expression otherExpression, + const char * otherExpression, int numberOfIntersections, Coordinate2D * intersections, - Expression e, + const char * expression, const char * symbol, double start = -1.0, double step = 0.1, @@ -189,10 +163,12 @@ void assert_next_intersections_are( Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { Shared::GlobalContext context; + Poincare::Expression e = parse_expression(expression, &context, false); + Poincare::Expression other = parse_expression(otherExpression, &context, false); double currentStart = start; for (int i = 0; i < numberOfIntersections; i++) { quiz_assert_log_if_failure(!std::isnan(currentStart), e); - Coordinate2D nextIntersection = e.nextIntersection(symbol, currentStart, step, max, &context, complexFormat, angleUnit, otherExpression); + Coordinate2D nextIntersection = e.nextIntersection(symbol, currentStart, step, max, &context, complexFormat, angleUnit, other); currentStart = nextIntersection.x1() + step; quiz_assert_log_if_failure( (doubles_are_approximately_equal(intersections[i].x1(), nextIntersection.x1())) @@ -200,38 +176,27 @@ void assert_next_intersections_are( e); } } -QUIZ_CASE(poincare_function_intersection) { - const char * symbol = "a"; - int symbolLength = strlen(symbol); - Expression e = Cosine::Builder(Symbol::Builder(symbol, symbolLength)); +QUIZ_CASE(poincare_function_intersection) { { - // cos with y=2 - Expression otherExpression = Rational::Builder(2); constexpr int numberOfIntersections = 1; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(NAN, NAN)}; - assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol); + assert_next_intersections_are("2", numberOfIntersections, intersections, "cos(a)", "a"); } - { - // cos with y=1 - Expression otherExpression = Rational::Builder(1); constexpr int numberOfIntersections = 2; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0)}; - assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol); + assert_next_intersections_are("1", numberOfIntersections, intersections, "cos(a)", "a"); } - { - // cos with y=0 - Expression otherExpression = Rational::Builder(0); constexpr int numberOfIntersections = 3; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_intersections_are(otherExpression, numberOfIntersections, intersections, e, symbol); + assert_next_intersections_are("0", numberOfIntersections, intersections, "cos(a)", "a"); } } From a62efecb177d646d57bb154b29475aa4d5733a06 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 14:34:51 +0100 Subject: [PATCH 040/117] [poincare/test/function_solver] Remove helper functions' default parameter values --- poincare/test/function_solver.cpp | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index 956484273..f34f19678 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -26,9 +26,9 @@ void assert_next_extrema_are( Coordinate2D * extrema, const char * expression, const char * symbol, - double start = -1.0, - double step = 0.1, - double max = 100.0, + double start, + double step, + double max, Preferences::ComplexFormat complexFormat = Preferences::ComplexFormat::Real, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { @@ -75,13 +75,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "a^2", "a"); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "a^2", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "a^2", "a"); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "a^2", "a", -1.0, 0.1, 100.0); } } { @@ -89,13 +89,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "3", "a"); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "3", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "3", "a"); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "3", "a", -1.0, 0.1, 100.0); } } { @@ -103,13 +103,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "0", "a"); + assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "0", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "0", "a"); + assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "0", "a", -1.0, 0.1, 100.0); } } } @@ -127,26 +127,26 @@ QUIZ_CASE(poincare_function_root) { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2", "a"); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-2.0, 0.0), Coordinate2D(2.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2-4", "a", -5.0); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2-4", "a", -5.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "3", "a"); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "3", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "0", "a"); + assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "0", "a", -1.0, 0.1, 100.0); } } @@ -156,9 +156,9 @@ void assert_next_intersections_are( Coordinate2D * intersections, const char * expression, const char * symbol, - double start = -1.0, - double step = 0.1, - double max = 500.0, + double start, + double step, + double max, Preferences::ComplexFormat complexFormat = Preferences::ComplexFormat::Real, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { @@ -182,14 +182,14 @@ QUIZ_CASE(poincare_function_intersection) { constexpr int numberOfIntersections = 1; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(NAN, NAN)}; - assert_next_intersections_are("2", numberOfIntersections, intersections, "cos(a)", "a"); + assert_next_intersections_are("2", numberOfIntersections, intersections, "cos(a)", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 2; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0)}; - assert_next_intersections_are("1", numberOfIntersections, intersections, "cos(a)", "a"); + assert_next_intersections_are("1", numberOfIntersections, intersections, "cos(a)", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 3; @@ -197,6 +197,6 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_intersections_are("0", numberOfIntersections, intersections, "cos(a)", "a"); + assert_next_intersections_are("0", numberOfIntersections, intersections, "cos(a)", "a", -1.0, 0.1, 500.0); } } From 6d48ef5eb01c6368459b08ed143c16ee0dc84122 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 15:51:55 +0100 Subject: [PATCH 041/117] [poincare/test/function_solver] Simplify helper function's Remove currentStart and simply use start instead --- poincare/test/function_solver.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index f34f19678..9676343f7 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -34,22 +34,21 @@ void assert_next_extrema_are( { Shared::GlobalContext context; Poincare::Expression e = parse_expression(expression, &context, false); - double currentStart = start; for (int i = 0; i < numberOfExtrema; i++) { - quiz_assert_log_if_failure(!std::isnan(currentStart), e); + quiz_assert_log_if_failure(!std::isnan(start), e); Coordinate2D nextExtrema; if (extremumType == ExtremumType::Maximum) { - nextExtrema = e.nextMaximum(symbol, currentStart, step, max, &context, complexFormat, angleUnit); + nextExtrema = e.nextMaximum(symbol, start, step, max, &context, complexFormat, angleUnit); } else if (extremumType == ExtremumType::Minimum) { - nextExtrema = e.nextMinimum(symbol, currentStart, step, max, &context, complexFormat, angleUnit); + nextExtrema = e.nextMinimum(symbol, start, step, max, &context, complexFormat, angleUnit); } else if (extremumType == ExtremumType::Root) { - nextExtrema = Coordinate2D(e.nextRoot(symbol, currentStart, step, max, &context, complexFormat, angleUnit), 0.0 ); + nextExtrema = Coordinate2D(e.nextRoot(symbol, start, step, max, &context, complexFormat, angleUnit), 0.0); } - currentStart = nextExtrema.x1() + step; quiz_assert_log_if_failure( (doubles_are_approximately_equal(extrema[i].x1(), nextExtrema.x1())) && (doubles_are_approximately_equal(extrema[i].x2(), nextExtrema.x2())), e); + start = nextExtrema.x1() + step; } } @@ -165,15 +164,14 @@ void assert_next_intersections_are( Shared::GlobalContext context; Poincare::Expression e = parse_expression(expression, &context, false); Poincare::Expression other = parse_expression(otherExpression, &context, false); - double currentStart = start; for (int i = 0; i < numberOfIntersections; i++) { - quiz_assert_log_if_failure(!std::isnan(currentStart), e); - Coordinate2D nextIntersection = e.nextIntersection(symbol, currentStart, step, max, &context, complexFormat, angleUnit, other); - currentStart = nextIntersection.x1() + step; + quiz_assert_log_if_failure(!std::isnan(start), e); + Coordinate2D nextIntersection = e.nextIntersection(symbol, start, step, max, &context, complexFormat, angleUnit, other); quiz_assert_log_if_failure( (doubles_are_approximately_equal(intersections[i].x1(), nextIntersection.x1())) && (doubles_are_approximately_equal(intersections[i].x2(), nextIntersection.x2())), e); + start = nextIntersection.x1() + step; } } From 29b0841a21feef7adbcb660cdc2b265c9400de07 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 16:44:18 +0100 Subject: [PATCH 042/117] [poincare/test/function_solver] Change term: extremum -> point of interest --- poincare/test/function_solver.cpp | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index 9676343f7..a4011348c 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -3,7 +3,7 @@ using namespace Poincare; -enum class ExtremumType : uint8_t { +enum class PointOfInterestType { Maximum, Minimum, Root @@ -20,10 +20,10 @@ bool doubles_are_approximately_equal(double d1, double d2) { return std::abs(d1-d2) < 0.00001; } -void assert_next_extrema_are( - ExtremumType extremumType, - int numberOfExtrema, - Coordinate2D * extrema, +void assert_points_of_interest_are( + PointOfInterestType type, + int numberOfPointsOfInterest, + Coordinate2D * pointsOfInterest, const char * expression, const char * symbol, double start, @@ -34,21 +34,21 @@ void assert_next_extrema_are( { Shared::GlobalContext context; Poincare::Expression e = parse_expression(expression, &context, false); - for (int i = 0; i < numberOfExtrema; i++) { + for (int i = 0; i < numberOfPointsOfInterest; i++) { quiz_assert_log_if_failure(!std::isnan(start), e); - Coordinate2D nextExtrema; - if (extremumType == ExtremumType::Maximum) { - nextExtrema = e.nextMaximum(symbol, start, step, max, &context, complexFormat, angleUnit); - } else if (extremumType == ExtremumType::Minimum) { - nextExtrema = e.nextMinimum(symbol, start, step, max, &context, complexFormat, angleUnit); - } else if (extremumType == ExtremumType::Root) { - nextExtrema = Coordinate2D(e.nextRoot(symbol, start, step, max, &context, complexFormat, angleUnit), 0.0); + Coordinate2D nextPointOfInterest; + if (type == PointOfInterestType::Maximum) { + nextPointOfInterest = e.nextMaximum(symbol, start, step, max, &context, complexFormat, angleUnit); + } else if (type == PointOfInterestType::Minimum) { + nextPointOfInterest = e.nextMinimum(symbol, start, step, max, &context, complexFormat, angleUnit); + } else if (type == PointOfInterestType::Root) { + nextPointOfInterest = Coordinate2D(e.nextRoot(symbol, start, step, max, &context, complexFormat, angleUnit), 0.0); } quiz_assert_log_if_failure( - (doubles_are_approximately_equal(extrema[i].x1(), nextExtrema.x1())) - && (doubles_are_approximately_equal(extrema[i].x2(), nextExtrema.x2())), + doubles_are_approximately_equal(pointsOfInterest[i].x1(), nextPointOfInterest.x1()) && + doubles_are_approximately_equal(pointsOfInterest[i].x2(), nextPointOfInterest.x2()), e); - start = nextExtrema.x1() + step; + start = nextPointOfInterest.x1() + step; } } @@ -60,13 +60,13 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0), Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "cos(a)", "a", -1.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "cos(a)", "a", 0.0, 0.1, 300.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", "a", 0.0, 0.1, 300.0); } } { @@ -74,13 +74,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "a^2", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "a^2", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", "a", -1.0, 0.1, 100.0); } } { @@ -88,13 +88,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "3", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "3", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", "a", -1.0, 0.1, 100.0); } } { @@ -102,13 +102,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Maximum, numberOfMaxima, maxima, "0", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Minimum, numberOfMinima, minima, "0", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", "a", -1.0, 0.1, 100.0); } } } @@ -120,32 +120,32 @@ QUIZ_CASE(poincare_function_root) { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "cos(a)", "a", 0.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", "a", 0.0, 0.1, 500.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-2.0, 0.0), Coordinate2D(2.0, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "a^2-4", "a", -5.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", "a", -5.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "3", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; - assert_next_extrema_are(ExtremumType::Root, numberOfRoots, roots, "0", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", "a", -1.0, 0.1, 100.0); } } From 0a6af26162cd262160e872613e8fb5540f80f00d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 16:56:05 +0100 Subject: [PATCH 043/117] [poincare/test/function_solver] Factor helper functions --- poincare/test/function_solver.cpp | 83 ++++++++++++------------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index a4011348c..5baabae04 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -6,7 +6,8 @@ using namespace Poincare; enum class PointOfInterestType { Maximum, Minimum, - Root + Root, + Intersection, }; bool doubles_are_approximately_equal(double d1, double d2) { @@ -24,7 +25,8 @@ void assert_points_of_interest_are( PointOfInterestType type, int numberOfPointsOfInterest, Coordinate2D * pointsOfInterest, - const char * expression, + const char * expression1, + const char * expression2, const char * symbol, double start, double step, @@ -33,21 +35,28 @@ void assert_points_of_interest_are( Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { Shared::GlobalContext context; - Poincare::Expression e = parse_expression(expression, &context, false); + Poincare::Expression e1 = parse_expression(expression1, &context, false); + Poincare::Expression e2; + if (expression2) { + assert(type == PointOfInterestType::Intersection); + e2 = parse_expression(expression2, &context, false); + } for (int i = 0; i < numberOfPointsOfInterest; i++) { - quiz_assert_log_if_failure(!std::isnan(start), e); + quiz_assert_log_if_failure(!std::isnan(start), e1); Coordinate2D nextPointOfInterest; if (type == PointOfInterestType::Maximum) { - nextPointOfInterest = e.nextMaximum(symbol, start, step, max, &context, complexFormat, angleUnit); + nextPointOfInterest = e1.nextMaximum(symbol, start, step, max, &context, complexFormat, angleUnit); } else if (type == PointOfInterestType::Minimum) { - nextPointOfInterest = e.nextMinimum(symbol, start, step, max, &context, complexFormat, angleUnit); + nextPointOfInterest = e1.nextMinimum(symbol, start, step, max, &context, complexFormat, angleUnit); } else if (type == PointOfInterestType::Root) { - nextPointOfInterest = Coordinate2D(e.nextRoot(symbol, start, step, max, &context, complexFormat, angleUnit), 0.0); + nextPointOfInterest = Coordinate2D(e1.nextRoot(symbol, start, step, max, &context, complexFormat, angleUnit), 0.0); + } else if (type == PointOfInterestType::Intersection) { + nextPointOfInterest = e1.nextIntersection(symbol, start, step, max, &context, complexFormat, angleUnit, e2); } quiz_assert_log_if_failure( doubles_are_approximately_equal(pointsOfInterest[i].x1(), nextPointOfInterest.x1()) && doubles_are_approximately_equal(pointsOfInterest[i].x2(), nextPointOfInterest.x2()), - e); + e1); start = nextPointOfInterest.x1() + step; } } @@ -60,13 +69,13 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0), Coordinate2D(NAN, NAN)}; - assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", "a", -1.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", nullptr, "a", -1.0, 0.1, 500.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; - assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", "a", 0.0, 0.1, 300.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", nullptr, "a", 0.0, 0.1, 300.0); } } { @@ -74,13 +83,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; - assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } } { @@ -88,13 +97,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; - assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; - assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", nullptr, "a", -1.0, 0.1, 100.0); } } { @@ -102,13 +111,13 @@ QUIZ_CASE(poincare_function_extremum) { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", nullptr, "a", -1.0, 0.1, 100.0); } } } @@ -120,58 +129,32 @@ QUIZ_CASE(poincare_function_root) { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", "a", 0.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", nullptr, "a", 0.0, 0.1, 500.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-2.0, 0.0), Coordinate2D(2.0, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", "a", -5.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", nullptr, "a", -5.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", "a", -1.0, 0.1, 100.0); + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; - assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", "a", -1.0, 0.1, 100.0); - } -} - -void assert_next_intersections_are( - const char * otherExpression, - int numberOfIntersections, - Coordinate2D * intersections, - const char * expression, - const char * symbol, - double start, - double step, - double max, - Preferences::ComplexFormat complexFormat = Preferences::ComplexFormat::Real, - Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) -{ - Shared::GlobalContext context; - Poincare::Expression e = parse_expression(expression, &context, false); - Poincare::Expression other = parse_expression(otherExpression, &context, false); - for (int i = 0; i < numberOfIntersections; i++) { - quiz_assert_log_if_failure(!std::isnan(start), e); - Coordinate2D nextIntersection = e.nextIntersection(symbol, start, step, max, &context, complexFormat, angleUnit, other); - quiz_assert_log_if_failure( - (doubles_are_approximately_equal(intersections[i].x1(), nextIntersection.x1())) - && (doubles_are_approximately_equal(intersections[i].x2(), nextIntersection.x2())), - e); - start = nextIntersection.x1() + step; + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", nullptr, "a", -1.0, 0.1, 100.0); } } @@ -180,14 +163,14 @@ QUIZ_CASE(poincare_function_intersection) { constexpr int numberOfIntersections = 1; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(NAN, NAN)}; - assert_next_intersections_are("2", numberOfIntersections, intersections, "cos(a)", "a", -1.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "2", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 2; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0)}; - assert_next_intersections_are("1", numberOfIntersections, intersections, "cos(a)", "a", -1.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "1", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 3; @@ -195,6 +178,6 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; - assert_next_intersections_are("0", numberOfIntersections, intersections, "cos(a)", "a", -1.0, 0.1, 500.0); + assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "0", "a", -1.0, 0.1, 500.0); } } From d727fb4cf87d1d8b5a53efaeca782a4ad393f835 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 27 Feb 2020 17:36:37 +0100 Subject: [PATCH 044/117] [poincare/test/function_solver] Run solver tests with negative steps --- poincare/test/function_solver.cpp | 104 ++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/poincare/test/function_solver.cpp b/poincare/test/function_solver.cpp index 5baabae04..4dee3c65f 100644 --- a/poincare/test/function_solver.cpp +++ b/poincare/test/function_solver.cpp @@ -71,12 +71,26 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", nullptr, "a", -1.0, 0.1, 500.0); } + { + constexpr int numberOfMaxima = 3; + Coordinate2D maxima[numberOfMaxima] = { + Coordinate2D(360.0, 1.0), + Coordinate2D(0.0, 1.0), + Coordinate2D(NAN, NAN)}; + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", nullptr, "a", 500.0, -0.1, -1.0); + } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", nullptr, "a", 0.0, 0.1, 300.0); } + { + constexpr int numberOfMinima = 1; + Coordinate2D minima[numberOfMinima] = { + Coordinate2D(180.0, -1.0)}; + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", nullptr, "a", 300.0, -0.1, 0.0); + } } { { @@ -85,12 +99,24 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfMaxima = 1; + Coordinate2D maxima[numberOfMaxima] = { + Coordinate2D(NAN, NAN)}; + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", nullptr, "a", 100.0, -0.1, -1.0); + } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfMinima = 1; + Coordinate2D minima[numberOfMinima] = { + Coordinate2D(0.0, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", nullptr, "a", 100.0, -0.1, -1.0); + } } { { @@ -99,12 +125,24 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(NAN, 3.0)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfMaxima = 1; + Coordinate2D maxima[numberOfMaxima] = { + Coordinate2D(NAN, 3.0)}; + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", nullptr, "a", 100.0, -0.1, -1.0); + } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfMinima = 1; + Coordinate2D minima[numberOfMinima] = { + Coordinate2D(NAN, 3.0)}; + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", nullptr, "a", 100.0, -0.1, -1.0); + } } { { @@ -113,12 +151,24 @@ QUIZ_CASE(poincare_function_extremum) { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfMaxima = 1; + Coordinate2D maxima[numberOfMaxima] = { + Coordinate2D(NAN, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", nullptr, "a", 100.0, -0.1, -1.0); + } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfMinima = 1; + Coordinate2D minima[numberOfMinima] = { + Coordinate2D(NAN, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", nullptr, "a", 100.0, -0.1, -1.0); + } } } @@ -131,12 +181,26 @@ QUIZ_CASE(poincare_function_root) { Coordinate2D(450.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", nullptr, "a", 0.0, 0.1, 500.0); } + { + constexpr int numberOfRoots = 3; + Coordinate2D roots[numberOfRoots] = { + Coordinate2D(450.0, 0.0), + Coordinate2D(270.0, 0.0), + Coordinate2D(90.0, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", nullptr, "a", 500.0, -0.1, 0.0); + } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfRoots = 1; + Coordinate2D roots[numberOfRoots] = { + Coordinate2D(0.0, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", nullptr, "a", 100.0, -0.1, -1.0); + } { constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { @@ -144,18 +208,37 @@ QUIZ_CASE(poincare_function_root) { Coordinate2D(2.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", nullptr, "a", -5.0, 0.1, 100.0); } + { + constexpr int numberOfRoots = 2; + Coordinate2D roots[numberOfRoots] = { + Coordinate2D(2.0, 0.0), + Coordinate2D(-2.0, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", nullptr, "a", 100.0, -0.1, -5.0); + } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfRoots = 1; + Coordinate2D roots[numberOfRoots] = { + Coordinate2D(NAN, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", nullptr, "a", 100.0, -0.1, -1.0); + } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", nullptr, "a", -1.0, 0.1, 100.0); } + { + constexpr int numberOfRoots = 1; + Coordinate2D roots[numberOfRoots] = { + Coordinate2D(99.8, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", nullptr, "a", 100.0, -0.1, -1.0); + } } QUIZ_CASE(poincare_function_intersection) { @@ -165,6 +248,12 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "2", "a", -1.0, 0.1, 500.0); } + { + constexpr int numberOfIntersections = 1; + Coordinate2D intersections[numberOfIntersections] = { + Coordinate2D(NAN, NAN)}; + assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "2", "a", 500.0, -0.1, -1.0); + } { constexpr int numberOfIntersections = 2; Coordinate2D intersections[numberOfIntersections] = { @@ -172,6 +261,13 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D(360.0, 1.0)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "1", "a", -1.0, 0.1, 500.0); } + { + constexpr int numberOfIntersections = 2; + Coordinate2D intersections[numberOfIntersections] = { + Coordinate2D(360.0, 1.0), + Coordinate2D(0.0, 1.0)}; + assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "1", "a", 500.0, -0.1, -1.0); + } { constexpr int numberOfIntersections = 3; Coordinate2D intersections[numberOfIntersections] = { @@ -180,4 +276,12 @@ QUIZ_CASE(poincare_function_intersection) { Coordinate2D(450.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "0", "a", -1.0, 0.1, 500.0); } + { + constexpr int numberOfIntersections = 3; + Coordinate2D intersections[numberOfIntersections] = { + Coordinate2D(450.0, 0.0), + Coordinate2D(270.0, 0.0), + Coordinate2D(90.0, 0.0)}; + assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "0", "a", 500.0, -0.1, -1.0); + } } From 9f1dc91cdeb188d8ade3546e514847cad80d011e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Fri, 28 Feb 2020 18:52:03 +0100 Subject: [PATCH 045/117] [GitHub] GitHub Actions --- .github/workflows/ci-workflow.yml | 45 +++++++------------------------ 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 01002e407..8033fcb17 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -6,6 +6,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 + with: + submodules: true - run: make -j2 PLATFORM=simulator TARGET=android - uses: actions/upload-artifact@master with: @@ -17,6 +19,8 @@ jobs: - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config - uses: numworks/setup-arm-toolchain@v1 - uses: actions/checkout@v1 + with: + submodules: true - run: make -j2 MODEL=n0100 epsilon.dfu - run: make -j2 MODEL=n0100 epsilon.onboarding.dfu - run: make -j2 MODEL=n0100 epsilon.onboarding.update.dfu @@ -34,6 +38,8 @@ jobs: - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config - uses: numworks/setup-arm-toolchain@v1 - uses: actions/checkout@v1 + with: + submodules: true - run: make -j2 epsilon.dfu - run: make -j2 epsilon.onboarding.dfu - run: make -j2 epsilon.onboarding.update.dfu @@ -47,19 +53,6 @@ jobs: name: epsilon-device-n0110.dfu path: output/release/device/n0110/epsilon.dfu - run: make -j2 test.elf - build-simulator-windows: - runs-on: windows-latest - steps: - - uses: numworks/setup-msys2@v1 - - uses: actions/checkout@v1 - - run: msys2do pacman -S --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-freetype mingw-w64-x86_64-pkg-config make mingw-w64-x86_64-python3 mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-libpng - - run: msys2do make -j2 PLATFORM=simulator - - uses: actions/upload-artifact@master - with: - name: epsilon-simulator-windows.exe - path: output/release/simulator/windows/epsilon.exe - - run: msys2do make -j2 PLATFORM=simulator test.headless.exe - - run: output\release\simulator\windows\test.headless.exe build-simulator-web: runs-on: ubuntu-latest steps: @@ -67,6 +60,8 @@ jobs: with: sdk: latest-fastcomp - uses: actions/checkout@v1 + with: + submodules: true - run: make -j2 PLATFORM=simulator TARGET=web - uses: actions/upload-artifact@master with: @@ -79,6 +74,8 @@ jobs: steps: - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config - uses: actions/checkout@v1 + with: + submodules: true - run: make -j2 PLATFORM=simulator - uses: actions/upload-artifact@master with: @@ -86,25 +83,3 @@ jobs: path: output/release/simulator/linux/epsilon.bin - run: make -j2 PLATFORM=simulator test.headless.bin - run: output/release/simulator/linux/test.headless.bin - build-simulator-macos: - runs-on: macOS-latest - steps: - - run: brew install numworks/tap/epsilon-sdk - - uses: actions/checkout@v1 - - run: make -j2 PLATFORM=simulator - - uses: actions/upload-artifact@master - with: - name: epsilon-simulator-macos.zip - path: output/release/simulator/macos/app/Payload - - run: make -j2 PLATFORM=simulator ARCH=x86_64 test.headless.bin - - run: output/release/simulator/macos/x86_64/test.headless.bin - build-simulator-ios: - runs-on: macOS-latest - steps: - - run: brew install numworks/tap/epsilon-sdk - - uses: actions/checkout@v1 - - run: make -j2 PLATFORM=simulator TARGET=ios EPSILON_TELEMETRY=0 - - uses: actions/upload-artifact@master - with: - name: epsilon-simulator-ios.ipa - path: output/release/simulator/ios/app/epsilon.ipa From f04c75583c0de0a03534e0fcb0c2475cdb641889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Fri, 28 Feb 2020 19:22:47 +0100 Subject: [PATCH 046/117] [GitHub/Fix] GitHub Actions --- .github/workflows/ci-workflow.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 8033fcb17..04d3ef1f5 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -68,7 +68,6 @@ jobs: name: epsilon-simulator-web.zip path: output/release/simulator/web/simulator.zip - run: make -j2 PLATFORM=simulator TARGET=web test.headless.js - - run: node output/release/simulator/web/test.headless.js build-simulator-linux: runs-on: ubuntu-latest steps: @@ -82,4 +81,3 @@ jobs: name: epsilon-simulator-linux.bin path: output/release/simulator/linux/epsilon.bin - run: make -j2 PLATFORM=simulator test.headless.bin - - run: output/release/simulator/linux/test.headless.bin From 7bf3cd377c65c4018000e84f54298497e24e0538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Sat, 29 Feb 2020 10:57:29 +0100 Subject: [PATCH 047/117] [Fix] Allow to compile only the code app --- apps/settings/base.de.i18n | 13 ------------- apps/settings/base.en.i18n | 13 ------------- apps/settings/base.es.i18n | 13 ------------- apps/settings/base.fr.i18n | 13 ------------- apps/settings/base.hu.i18n | 13 ------------- apps/settings/base.pt.i18n | 13 ------------- apps/shared.de.i18n | 13 +++++++++++++ apps/shared.en.i18n | 13 +++++++++++++ apps/shared.es.i18n | 13 +++++++++++++ apps/shared.fr.i18n | 13 +++++++++++++ apps/shared.hu.i18n | 13 +++++++++++++ apps/shared.pt.i18n | 13 +++++++++++++ 12 files changed, 78 insertions(+), 78 deletions(-) diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 7be14ce0e..8eea03c7b 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -45,19 +45,6 @@ SmallFont = "Kleine " SerialNumber = "Seriennummer" UpdatePopUp = "Erinnerung: Update" BetaPopUp = "Beta pop-up" -LEDColor = "LEDs farbe" -ExamModeMode = "Modus" -ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "Ohne symbolisch " -ExamModeModeNoSymNoText = "No sym no text " -ExamModeModeDutch = "Niederländisch " -ColorRed = "Rot " -ColorWhite = "Weiss " -ColorBlue = "Blau " -ColorGreen = "Grün " -ColorYellow = "Gelb " -ColorPurple = "Lila " -ColorOrange = "Orange " Contributors = "Beiträger" Accessibility = "Barrierefreiheit" AccessibilityInvertColors = "Farbumkehrung" diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 9fb8c3617..e09b048fa 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -45,19 +45,6 @@ SmallFont = "Small " SerialNumber = "Serial number" UpdatePopUp = "Update pop-up" BetaPopUp = "Beta pop-up" -LEDColor = "LED color" -ExamModeMode = "Mode" -ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "No sym " -ExamModeModeNoSymNoText = "No sym no text " -ExamModeModeDutch = "Dutch " -ColorRed = "Red " -ColorWhite = "White " -ColorBlue = "Blue " -ColorGreen = "Green " -ColorYellow = "Yellow " -ColorPurple = "Purple " -ColorOrange = "Orange " Contributors = "Contributors" Accessibility = "Accessibility" AccessibilityInvertColors = "Invert colors" diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index b476d7378..c8d4a88a1 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -45,19 +45,6 @@ SmallFont = "Pequeño " SerialNumber = "Número serie" UpdatePopUp = "Pop-up de actualización" BetaPopUp = "Beta pop-up" -LEDColor = "Color del LED" -ExamModeMode = "Modo" -ExamModeModeStandard = "Estándar " -ExamModeModeNoSym = "Sin simbólico " -ExamModeModeNoSymNoText = "sin simbolismo sin texto " -ExamModeModeDutch = "Holandés " -ColorRed = "Rojo " -ColorWhite = "Blanco " -ColorBlue = "Azul " -ColorGreen = "Verde " -ColorYellow = "Amarillo " -ColorPurple = "Púrpura " -ColorOrange = "Naranja " Contributors = "Contribuyentes" Accessibility = "Accesibilidad" AccessibilityInvertColors = "Colores invertidos" diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 4e413d057..a23f8a0b9 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -45,19 +45,6 @@ SmallFont = "Petit " SerialNumber = "Numéro série" UpdatePopUp = "Rappel mise à jour" BetaPopUp = "Rappel version bêta" -LEDColor = "Couleur LED" -ExamModeMode = "Mode" -ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "Sans symbolique " -ExamModeModeNoSymNoText = "Sans symbolique ni texte " -ExamModeModeDutch = "Néerlandais " -ColorRed = "Rouge " -ColorWhite = "Blanc " -ColorBlue = "Bleu " -ColorGreen = "Vert " -ColorYellow = "Jaune " -ColorPurple = "Mauve " -ColorOrange = "Orange " Contributors = "Contributeurs" Accessibility = "Accessibilité" AccessibilityInvertColors = "Inverser couleurs" diff --git a/apps/settings/base.hu.i18n b/apps/settings/base.hu.i18n index 6361dbec8..b3828759e 100644 --- a/apps/settings/base.hu.i18n +++ b/apps/settings/base.hu.i18n @@ -45,19 +45,6 @@ SmallFont = "Kicsi " SerialNumber = "Sorozatszám" UpdatePopUp = "Elöugró ablak frissítése" BetaPopUp = "Béta pop-up" -LEDColor = "LED szín" -ExamModeMode = "Üzemmód" -ExamModeModeStandard = "Normál" -ExamModeModeNoSym = "Nincs sym" -ExamModeModeNoSymNoText = "Nincs szimbolikus, nincs szöveg " -ExamModeModeDutch = "Holland " -ColorRed = "Piros " -ColorWhite = "Fehér " -ColorBlue = "Kék " -ColorGreen = "Zöld " -ColorYellow = "Sárga " -ColorPurple = "Lila " -ColorOrange = "Narancssárga " Contributors = "Közremüködök" Accessibility = "Hozzáférhetöség" AccessibilityInvertColors = "Invertált színek" diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 0e5218695..c3fb57e31 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -45,19 +45,6 @@ SmallFont = "Pequeno " SerialNumber = "Número serie" UpdatePopUp = "Alertas de atualização" BetaPopUp = "Beta pop-up" -LEDColor = "Cor LED" -ExamModeMode = "Modo" -ExamModeModeStandard = "Padrão " -ExamModeModeNoSym = "Sem simbólico " -ExamModeModeNoSymNoText = "Sem simbólico sem texto " -ExamModeModeDutch = "Holandês " -ColorRed = "Vermelho " -ColorWhite = "Branco " -ColorBlue = "Azul " -ColorGreen = "Verde " -ColorYellow = "Amarelo " -ColorPurple = "Roxo " -ColorOrange = "Caranja " Contributors = "Contribuidores" Accessibility = "Acessibilidade" AccessibilityInvertColors = "Cores invertidas" diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index 12a529e80..cb1886715 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -82,3 +82,16 @@ XStart = "X Startwert" Zoom = "Zoom" Developers = "Entwickler" BetaTesters = "Beta-Tester" +LEDColor = "LEDs farbe" +ExamModeMode = "Modus" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "Ohne symbolisch " +ExamModeModeNoSymNoText = "No sym no text " +ExamModeModeDutch = "Niederländisch " +ColorRed = "Rot " +ColorWhite = "Weiss " +ColorBlue = "Blau " +ColorGreen = "Grün " +ColorYellow = "Gelb " +ColorPurple = "Lila " +ColorOrange = "Orange " diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index 5e62daa44..bbef03c83 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -82,3 +82,16 @@ XStart = "X start" Zoom = "Zoom" Developers = "Developers" BetaTesters = "Beta testers" +LEDColor = "LED color" +ExamModeMode = "Mode" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "No sym " +ExamModeModeNoSymNoText = "No sym no text " +ExamModeModeDutch = "Dutch " +ColorRed = "Red " +ColorWhite = "White " +ColorBlue = "Blue " +ColorGreen = "Green " +ColorYellow = "Yellow " +ColorPurple = "Purple " +ColorOrange = "Orange " diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index ff7a855bd..2ac9ff491 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -82,3 +82,16 @@ XStart = "X inicio" Zoom = "Zoom" Developers = "Desarrolladores" BetaTesters = "Probadores beta" +LEDColor = "Color del LED" +ExamModeMode = "Modo" +ExamModeModeStandard = "Estándar " +ExamModeModeNoSym = "Sin simbólico " +ExamModeModeNoSymNoText = "sin simbolismo sin texto " +ExamModeModeDutch = "Holandés " +ColorRed = "Rojo " +ColorWhite = "Blanco " +ColorBlue = "Azul " +ColorGreen = "Verde " +ColorYellow = "Amarillo " +ColorPurple = "Púrpura " +ColorOrange = "Naranja " diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index 821b9c26c..f711cbbec 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -82,3 +82,16 @@ XStart = "X début" Zoom = "Zoom" Developers = "Développeurs" BetaTesters = "Beta testeurs" +LEDColor = "Couleur LED" +ExamModeMode = "Mode" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "Sans symbolique " +ExamModeModeNoSymNoText = "Sans symbolique ni texte " +ExamModeModeDutch = "Néerlandais " +ColorRed = "Rouge " +ColorWhite = "Blanc " +ColorBlue = "Bleu " +ColorGreen = "Vert " +ColorYellow = "Jaune " +ColorPurple = "Mauve " +ColorOrange = "Orange " diff --git a/apps/shared.hu.i18n b/apps/shared.hu.i18n index b44acba08..4862d64f7 100644 --- a/apps/shared.hu.i18n +++ b/apps/shared.hu.i18n @@ -82,3 +82,16 @@ XStart = "X kezdete" Zoom = "Zoom" Developers = "Fejlesztök" BetaTesters = "Béta tesztelök" +LEDColor = "LED szín" +ExamModeMode = "Üzemmód" +ExamModeModeStandard = "Normál" +ExamModeModeNoSym = "Nincs sym" +ExamModeModeNoSymNoText = "Nincs szimbolikus, nincs szöveg " +ExamModeModeDutch = "Holland " +ColorRed = "Piros " +ColorWhite = "Fehér " +ColorBlue = "Kék " +ColorGreen = "Zöld " +ColorYellow = "Sárga " +ColorPurple = "Lila " +ColorOrange = "Narancssárga " diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 2dc5f6e5f..7ffa4a8b0 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -82,3 +82,16 @@ XStart = "X inicio" Zoom = "Zoom" Developers = "Desenvolvedores" BetaTesters = "Testadores beta" +LEDColor = "Cor LED" +ExamModeMode = "Modo" +ExamModeModeStandard = "Padrão " +ExamModeModeNoSym = "Sem simbólico " +ExamModeModeNoSymNoText = "Sem simbólico sem texto " +ExamModeModeDutch = "Holandês " +ColorRed = "Vermelho " +ColorWhite = "Branco " +ColorBlue = "Azul " +ColorGreen = "Verde " +ColorYellow = "Amarelo " +ColorPurple = "Roxo " +ColorOrange = "Caranja " From d589107e01a6e9c5e7413f1fb2442767a105dcba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Sat, 29 Feb 2020 12:36:33 +0100 Subject: [PATCH 048/117] Fix conflicts --- apps/code/catalog.de.i18n | 9 --------- apps/settings/base.de.i18n | 6 ------ 2 files changed, 15 deletions(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 554eb3c6c..f8a651596 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -28,20 +28,11 @@ PythonComplex = "a+ib zurückgeben" PythonCopySign = "x mit dem Vorzeichen von y" PythonCos = "Kosinus" PythonCosh = "Hyperbolic cosine" -<<<<<<< HEAD -PythonCount = "Count the occurrences of x" -PythonDegrees = "Convert x from radians to degrees" -PythonDivMod = "Quotient and remainder" -PythonDrawString = "Display a text from pixel (x,y)" -PythonErf = "Error function" -======= PythonCount = "Zählt wie oft x vorkommt" PythonDegrees = "x von Radian zu Grad umwandeln" PythonDivMod = "Quotient und Rest" PythonDrawString = "Schreibt Text bei (x,y)" -PythonConstantE = "2.718281828459046" PythonErf = "Fehlerfunktion" ->>>>>>> acb71d29759a3dadac9221570058159adedb7da6 PythonErfc = "Complementary error function" PythonEval = "Return the evaluated expression" PythonExp = "Exponentialfunktion" diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 2e0c48b25..bc10bd120 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -7,13 +7,7 @@ EditionLinear = "Linear " Edition2D = "Natürlich " ComplexFormat = "Komplex" ExamMode = "Testmodus" -<<<<<<< HEAD -ExamModeActive = "Wieder starten Testmodus" -======= -ActivateExamMode = "Testmodus starten" ExamModeActive = "Testmodus neustarten" -ActivateDutchExamMode = "Niederländischen Testmodus starten" ->>>>>>> acb71d29759a3dadac9221570058159adedb7da6 ToDeactivateExamMode1 = "Um den Testmodus auszuschalten," ToDeactivateExamMode2 = "schließen Sie den Rechner an einen" ToDeactivateExamMode3 = "Computer oder eine Steckdose an." From ac75bfd0fc074d04d6e1cee9062ef4d9cece24da Mon Sep 17 00:00:00 2001 From: M4x1m3 Date: Sat, 29 Feb 2020 14:22:11 +0100 Subject: [PATCH 049/117] Allow simulator to be loaded with multiple scripts. --- apps/code/app.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/code/app.cpp b/apps/code/app.cpp index 665a09ce4..10d372183 100644 --- a/apps/code/app.cpp +++ b/apps/code/app.cpp @@ -49,8 +49,10 @@ bool App::Snapshot::lockOnConsole() const { } void App::Snapshot::setOpt(const char * name, const char * value) { - if (strcmp(name, "script") == 0) { + if (strcmp(name, "wipe") == 0) { m_scriptStore.deleteAllScripts(); + } + if (strcmp(name, "script") == 0) { char * separator = const_cast(UTF8Helper::CodePointSearch(value, ':')); if (*separator == 0) { return; From 33060d80c81227145089200f613937d083230866 Mon Sep 17 00:00:00 2001 From: Maxime FRIESS Date: Sat, 29 Feb 2020 18:55:19 +0100 Subject: [PATCH 050/117] [Fix] Bring Alpha+Up/Down/Left/Right scrolls to top/bottom/left/right --- escher/src/text_area.cpp | 12 ++++++++---- ion/include/ion/events.h | 5 +++++ ion/include/ion/keyboard/layout_B2/layout_events.h | 4 ++-- ion/include/ion/keyboard/layout_B3/layout_events.h | 4 ++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/escher/src/text_area.cpp b/escher/src/text_area.cpp index e549b9dc5..837e341b7 100644 --- a/escher/src/text_area.cpp +++ b/escher/src/text_area.cpp @@ -116,14 +116,18 @@ bool TextArea::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::ShiftUp || event == Ion::Events::ShiftDown) { selectUpDown(event == Ion::Events::ShiftUp); return true; - } else if (event == Ion::Events::ShiftLeft) { + } else if (event == Ion::Events::AlphaLeft) { contentView()->moveCursorGeo(-INT_MAX/2, 0); - } else if (event == Ion::Events::ShiftRight) { + TextInput::scrollToCursor(); + } else if (event == Ion::Events::AlphaRight) { contentView()->moveCursorGeo(INT_MAX/2, 0); - } else if (event == Ion::Events::ShiftUp) { + TextInput::scrollToCursor(); + } else if (event == Ion::Events::AlphaUp) { contentView()->moveCursorGeo(0, -INT_MAX/2); - } else if (event == Ion::Events::ShiftDown) { + TextInput::scrollToCursor(); + } else if (event == Ion::Events::AlphaDown) { contentView()->moveCursorGeo(0, INT_MAX/2); + TextInput::scrollToCursor(); } else if (event == Ion::Events::Left) { if (contentView()->resetSelection()) { return true; diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index 1d4cee1b8..def5dfe56 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -182,6 +182,11 @@ constexpr Event ShiftThree = Event::ShiftKey(Keyboard::Key::Three); // Alpha +constexpr Event AlphaLeft = Event::AlphaKey(Keyboard::Key::Left); +constexpr Event AlphaRight = Event::AlphaKey(Keyboard::Key::Right); +constexpr Event AlphaUp = Event::AlphaKey(Keyboard::Key::Up); +constexpr Event AlphaDown = Event::AlphaKey(Keyboard::Key::Down); + constexpr Event Colon = Event::AlphaKey(Keyboard::Key::XNT); constexpr Event SemiColon = Event::AlphaKey(Keyboard::Key::Var); constexpr Event DoubleQuotes = Event::AlphaKey(Keyboard::Key::Toolbox); diff --git a/ion/include/ion/keyboard/layout_B2/layout_events.h b/ion/include/ion/keyboard/layout_B2/layout_events.h index f6c773b79..b67988907 100644 --- a/ion/include/ion/keyboard/layout_B2/layout_events.h +++ b/ion/include/ion/keyboard/layout_B2/layout_events.h @@ -30,7 +30,7 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { TL(), TL(), TL(), TL(), TL(), U(), TL(), TL(), TL(), TL(), U(), U(), // Alpha - U(), U(), U(), U(), U(), U(), + TL(), TL(), TL(), TL(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), T(":"), T(";"), T("\""), T("%"), T("a"), T("b"), T("c"), T("d"), T("e"), T("f"), @@ -75,7 +75,7 @@ static constexpr const char * s_nameForEvent[255] = { nullptr, nullptr, nullptr, "BrightnessPlus", "BrightnessMinus", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //Alpha, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "AlphaLeft", "AlphaUp", "AlphaDown", "AlphaRight", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "Colon", "SemiColon", "DoubleQuotes", "Percent", "LowerA", "LowerB", "LowerC", "LowerD", "LowerE", "LowerF", diff --git a/ion/include/ion/keyboard/layout_B3/layout_events.h b/ion/include/ion/keyboard/layout_B3/layout_events.h index 447881bfc..8124c3e9d 100644 --- a/ion/include/ion/keyboard/layout_B3/layout_events.h +++ b/ion/include/ion/keyboard/layout_B3/layout_events.h @@ -30,7 +30,7 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { TL(), TL(), TL(), TL(), TL(), U(), TL(), TL(), TL(), TL(), U(), U(), // Alpha - U(), U(), U(), U(), U(), U(), + TL(), TL(), TL(), TL(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), T(":"), T(";"), T("\""), T("%"), T("a"), T("b"), T("c"), T("d"), T("e"), T("f"), @@ -75,7 +75,7 @@ static constexpr const char * s_nameForEvent[255] = { nullptr, nullptr, nullptr, "BrightnessPlus", "BrightnessMinus", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //Alpha, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "AlphaLeft", "AlphaUp", "AlphaDown", "AlphaRight", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "Colon", "SemiColon", "DoubleQuotes", "Percent", "LowerA", "LowerB", "LowerC", "LowerD", "LowerE", "LowerF", From 175e38711e69db2fbf976d24a82e75ea9e4c3c39 Mon Sep 17 00:00:00 2001 From: M4x1m3 Date: Sun, 1 Mar 2020 16:45:53 +0100 Subject: [PATCH 051/117] Removed duplicate binpack rule. --- build/targets.device.n0110.mak | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 5b5078ac5..456da622a 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -20,28 +20,3 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex fi $(Q) $(PYTHON) build/device/dfu.py -u $(word 1,$^) -.PHONY: %.two_binaries -%.two_binaries: %.elf - @echo "Building an internal and an external binary for $<" - $(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin - $(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin - @echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin" - $(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).external.bin - $(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).internal.bin - -.PHONY: binpack -binpack: - rm -rf output/binpack - mkdir -p output/binpack - $(MAKE) clean - $(MAKE) $(BUILD_DIR)/flasher.light.bin - cp $(BUILD_DIR)/flasher.light.bin output/binpack - $(MAKE) $(BUILD_DIR)/bench.flash.bin - $(MAKE) $(BUILD_DIR)/bench.ram.bin - cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack - $(MAKE) epsilon.official.onboarding.update.two_binaries - cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack - $(MAKE) clean - cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done - cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack - rm -rf output/binpack From 8a4e9520f398f938fa5b2cce8cb026aa3d4d9f4f Mon Sep 17 00:00:00 2001 From: M4x1m3 Date: Sun, 1 Mar 2020 16:48:36 +0100 Subject: [PATCH 052/117] Removed .gradle, added it to gitignore. --- .gitignore | 3 ++- .../.gradle/5.2.1/fileChanges/last-build.bin | Bin 1 -> 0 bytes .../.gradle/5.2.1/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .../simulator/android/.gradle/5.2.1/gc.properties | 0 4 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 ion/src/simulator/android/.gradle/5.2.1/fileChanges/last-build.bin delete mode 100644 ion/src/simulator/android/.gradle/5.2.1/fileHashes/fileHashes.lock delete mode 100644 ion/src/simulator/android/.gradle/5.2.1/gc.properties diff --git a/.gitignore b/.gitignore index c8a0d0c92..7212d2758 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ build/device/**/*.pyc epsilon.elf .vscode -.DS_Store \ No newline at end of file +.DS_Store +.gradle diff --git a/ion/src/simulator/android/.gradle/5.2.1/fileChanges/last-build.bin b/ion/src/simulator/android/.gradle/5.2.1/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/ion/src/simulator/android/.gradle/5.2.1/fileHashes/fileHashes.lock b/ion/src/simulator/android/.gradle/5.2.1/fileHashes/fileHashes.lock deleted file mode 100644 index bc5ad9eb016d04ae87770bca2d8c9df2933ac4c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZSny6MP|^HaC8GC% Date: Fri, 28 Feb 2020 00:35:15 +0000 Subject: [PATCH 053/117] Remove useless uses of const for return types An integer or float value can not be assigned to, so there is no point in qualifying it as const. --- apps/shared/curve_view.cpp | 4 ++-- apps/shared/curve_view.h | 4 ++-- apps/shared/curve_view_range.h | 4 ++-- poincare/include/poincare/expression.h | 2 +- poincare/include/poincare/unit.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 50d16f06f..da15f9daa 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -106,11 +106,11 @@ void CurveView::setOkView(View * okView) { * m_frame.height() - 1 yMin() */ -const float CurveView::pixelWidth() const { +float CurveView::pixelWidth() const { return (m_curveViewRange->xMax() - m_curveViewRange->xMin()) / (m_frame.width() - 1); } -const float CurveView::pixelHeight() const { +float CurveView::pixelHeight() const { return (m_curveViewRange->yMax() - m_curveViewRange->yMin()) / (m_frame.height() - 1); } diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 2637dc945..2512ec432 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -38,8 +38,8 @@ public: void setBannerView(View * bannerView); void setOkView(View * okView); void setForceOkDisplay(bool force) { m_forceOkDisplay = force; } - const float pixelWidth() const; - const float pixelHeight() const; + float pixelWidth() const; + float pixelHeight() const; protected: CurveViewRange * curveViewRange() const { return m_curveViewRange; } void setCurveViewRange(CurveViewRange * curveViewRange); diff --git a/apps/shared/curve_view_range.h b/apps/shared/curve_view_range.h index 8cda5fdfe..caa1d9ab0 100644 --- a/apps/shared/curve_view_range.h +++ b/apps/shared/curve_view_range.h @@ -17,8 +17,8 @@ public: virtual float xMax() const = 0; virtual float yMin() const = 0; virtual float yMax() const = 0; - const float xCenter() const { return (xMin() + xMax()) / 2; } - const float yCenter() const { return (yMin() + yMax()) / 2; } + float xCenter() const { return (xMin() + xMax()) / 2; } + float yCenter() const { return (yMin() + yMax()) / 2; } virtual float xGridUnit() const { return computeGridUnit(k_minNumberOfXGridUnits, k_maxNumberOfXGridUnits, xMax() - xMin()); } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index dea1fe006..9d4b3c084 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -274,7 +274,7 @@ public: m_numberOfChildren(numberOfChildren), m_untypedBuilder(builder) {} const char * name() const { return m_name; } - const int numberOfChildren() const { return m_numberOfChildren; } + int numberOfChildren() const { return m_numberOfChildren; } Expression build(Expression children) const { return (*m_untypedBuilder)(children); } private: const char * m_name; diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 3b0716ae3..ed1e8e0f8 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -29,7 +29,7 @@ public: m_exponent(exponent) {} const char * symbol() const { return m_symbol; } - const int8_t exponent() const { return m_exponent; } + int8_t exponent() const { return m_exponent; } int serialize(char * buffer, int bufferSize) const; private: const char * m_symbol; From a06660ee25cdf8b010c7fa93ae3d871b2335c4df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 27 Feb 2020 14:50:19 +0100 Subject: [PATCH 054/117] [poincare/vert_off_lay] Subscript layout serializes without _ This way there is no parsing confusion when copy pasting the subscript of a subscript layout --- poincare/src/parsing/parser.cpp | 59 +++++++++++++------------ poincare/src/parsing/parser.h | 2 +- poincare/src/vertical_offset_layout.cpp | 6 +-- poincare/test/parsing.cpp | 2 +- poincare/test/simplification.cpp | 8 ++-- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index c5671b602..2475a7583 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -370,6 +370,25 @@ void Parser::parseUnit(Expression & leftHandSide, Token::Type stoppingType) { void Parser::parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper) { const char * name = (**functionHelper).name(); + + if (strcmp(name, "log") == 0 && popTokenIfType(Token::LeftBrace)) { + // Special case for the log function (e.g. "log{2}(8)") + Expression base = parseUntil(Token::RightBrace); + if (m_status != Status::Progress) { + } else if (!popTokenIfType(Token::RightBrace)) { + m_status = Status::Error; // Right brace missing. + } else { + Expression parameter = parseFunctionParameters(); + if (m_status != Status::Progress) { + } else if (parameter.numberOfChildren() != 1) { + m_status = Status::Error; // Unexpected number of many parameters. + } else { + leftHandSide = Logarithm::Builder(parameter.childAtIndex(0), base); + } + } + return; + } + Expression parameters = parseFunctionParameters(); if (m_status != Status::Progress) { return; @@ -393,10 +412,12 @@ void Parser::parseReservedFunction(Expression & leftHandSide, const Expression:: } } -void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter) { - if (!popTokenIfType(leftDelimiter)) { +void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter1, Token::Type rightDelimiter1, Token::Type leftDelimiter2, Token::Type rightDelimiter2) { + bool delimiterTypeIsOne = popTokenIfType(leftDelimiter1); + if (!delimiterTypeIsOne && !popTokenIfType(leftDelimiter2)) { m_status = Status::Error; // Left delimiter missing. } else { + Token::Type rightDelimiter = delimiterTypeIsOne ? rightDelimiter1 : rightDelimiter2; Expression rank = parseUntil(rightDelimiter); if (m_status != Status::Progress) { } else if (!popTokenIfType(rightDelimiter)) { @@ -424,32 +445,14 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) { leftHandSide = Undefined::Builder(); } else if (m_currentToken.compareTo(Unreal::Name()) == 0) { leftHandSide = Unreal::Builder(); - } else if (m_currentToken.compareTo("u_") == 0 || m_currentToken.compareTo("v_") == 0 || m_currentToken.compareTo("w_") == 0) { // Special case for sequences (e.g. "u_{n}") - /* We now that m_currentToken.text()[0] is either 'u' or 'v', so we do not - * need to pass a code point to parseSequence. */ - parseSequence(leftHandSide, m_currentToken.text()[0], Token::LeftBrace, Token::RightBrace); - } else if (m_currentToken.compareTo("u") == 0 || m_currentToken.compareTo("v") == 0|| m_currentToken.compareTo("w") == 0) { // Special case for sequences (e.g. "u(n)") - /* We now that m_currentToken.text()[0] is either 'u' or 'v', so we do not - * need to pass a code point to parseSequence. */ - parseSequence(leftHandSide, m_currentToken.text()[0], Token::LeftParenthesis, Token::RightParenthesis); - } else if (m_currentToken.compareTo("log_") == 0) { // Special case for the log function (e.g. "log_{2}(8)") - if (!popTokenIfType(Token::LeftBrace)) { - m_status = Status::Error; // Left brace missing. - } else { - Expression base = parseUntil(Token::RightBrace); - if (m_status != Status::Progress) { - } else if (!popTokenIfType(Token::RightBrace)) { - m_status = Status::Error; // Right brace missing. - } else { - Expression parameter = parseFunctionParameters(); - if (m_status != Status::Progress) { - } else if (parameter.numberOfChildren() != 1) { - m_status = Status::Error; // Unexpected number of many parameters. - } else { - leftHandSide = Logarithm::Builder(parameter.childAtIndex(0), base); - } - } - } + } else if (m_currentToken.compareTo("u") == 0 + || m_currentToken.compareTo("v") == 0 + || m_currentToken.compareTo("w") == 0) + { + /* Special case for sequences (e.g. "u(n)", "u{n}", ...) + * We know that m_currentToken.text()[0] is either 'u', 'v' or 'w', so we do + * not need to pass a code point to parseSequence. */ + parseSequence(leftHandSide, m_currentToken.text()[0], Token::LeftParenthesis, Token::RightParenthesis, Token::LeftBrace, Token::RightBrace); } } diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index f0b41cf63..08e04a211 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -74,7 +74,7 @@ private: Expression parseCommaSeparatedList(); void parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper); void parseSpecialIdentifier(Expression & leftHandSide); - void parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter); + void parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter1, Token::Type rightDelimiter1, Token::Type leftDelimiter2, Token::Type rightDelimiter2); void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions); void defaultParseLeftParenthesis(bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType); diff --git a/poincare/src/vertical_offset_layout.cpp b/poincare/src/vertical_offset_layout.cpp index 538855a04..df163f402 100644 --- a/poincare/src/vertical_offset_layout.cpp +++ b/poincare/src/vertical_offset_layout.cpp @@ -156,11 +156,9 @@ int VerticalOffsetLayoutNode::serialize(char * buffer, int bufferSize, Preferenc if (bufferSize == 1) { return 0; } - // If the layout is a subscript, write "_{indice}" - int numberOfChar = SerializationHelper::CodePoint(buffer, bufferSize, '_'); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - numberOfChar += SerializationHelper::CodePoint(buffer+numberOfChar, bufferSize-numberOfChar, '{'); + // If the layout is a subscript, write "{indice}" + int numberOfChar = SerializationHelper::CodePoint(buffer, bufferSize, '{'); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } numberOfChar += const_cast(this)->indiceLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); diff --git a/poincare/test/parsing.cpp b/poincare/test/parsing.cpp index bc673d76b..328d50661 100644 --- a/poincare/test/parsing.cpp +++ b/poincare/test/parsing.cpp @@ -385,7 +385,7 @@ QUIZ_CASE(poincare_parsing_identifiers) { assert_parsed_expression_is("ln(1)", NaperianLogarithm::Builder(BasedInteger::Builder(1))); assert_parsed_expression_is("log(1)", CommonLogarithm::Builder(BasedInteger::Builder(1))); assert_parsed_expression_is("log(1,2)", Logarithm::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2))); - assert_parsed_expression_is("log_{2}(1)", Logarithm::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2))); + assert_parsed_expression_is("log{2}(1)", Logarithm::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2))); assert_parsed_expression_is("permute(2,1)", PermuteCoefficient::Builder(BasedInteger::Builder(2),BasedInteger::Builder(1))); assert_parsed_expression_is("prediction95(1,2)", PredictionInterval::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2))); assert_parsed_expression_is("prediction(1,2)", SimplePredictionInterval::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2))); diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 8808bda1e..0dd49cc10 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1025,10 +1025,10 @@ QUIZ_CASE(poincare_simplification_unit_convert) { assert_parsed_expression_simplify_to("1→u(n+1)", Undefined::Name()); assert_parsed_expression_simplify_to("1→v(n)", Undefined::Name()); assert_parsed_expression_simplify_to("1→v(n+1)", Undefined::Name()); - assert_parsed_expression_simplify_to("1→u_{n}", Undefined::Name()); - assert_parsed_expression_simplify_to("1→u_{n+1}", Undefined::Name()); - assert_parsed_expression_simplify_to("1→v_{n}", Undefined::Name()); - assert_parsed_expression_simplify_to("1→v_{n+1}", Undefined::Name()); + assert_parsed_expression_simplify_to("1→u{n}", Undefined::Name()); + assert_parsed_expression_simplify_to("1→u{n+1}", Undefined::Name()); + assert_parsed_expression_simplify_to("1→v{n}", Undefined::Name()); + assert_parsed_expression_simplify_to("1→v{n+1}", Undefined::Name()); assert_parsed_expression_simplify_to("1→inf", Undefined::Name()); assert_parsed_expression_simplify_to("1→undef", Undefined::Name()); assert_parsed_expression_simplify_to("1→π", Undefined::Name()); From 4f76e4418fbeacfa17f603ae4f67a2a8df4cdf9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 2 Mar 2020 10:49:13 +0100 Subject: [PATCH 055/117] [apps/console_edit_cell] Fix input result copying --- apps/code/console_edit_cell.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/code/console_edit_cell.cpp b/apps/code/console_edit_cell.cpp index 30e0472fb..f938f52dc 100644 --- a/apps/code/console_edit_cell.cpp +++ b/apps/code/console_edit_cell.cpp @@ -7,6 +7,8 @@ namespace Code { +static inline int minInt(int x, int y) { return x < y ? x : y; } + ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) : HighlightCell(), Responder(parentResponder), @@ -65,9 +67,12 @@ void ConsoleEditCell::clearAndReduceSize() { const char * ConsoleEditCell::shiftCurrentTextAndClear() { size_t previousBufferSize = m_textField.draftTextBufferSize(); m_textField.setDraftTextBufferSize(previousBufferSize + 1); - char * textFieldBuffer = m_textField.draftTextBuffer(); + char * textFieldBuffer = const_cast(m_textField.text()); char * newTextPosition = textFieldBuffer + 1; - strlcpy(newTextPosition, textFieldBuffer, previousBufferSize); + assert(previousBufferSize > 0); + size_t copyLength = minInt(previousBufferSize - 1, strlen(textFieldBuffer)); + memmove(newTextPosition, textFieldBuffer, copyLength); + newTextPosition[copyLength] = 0; textFieldBuffer[0] = 0; return newTextPosition; } From 035a0377bd33f10d9eff5a281c20d8f0b336df87 Mon Sep 17 00:00:00 2001 From: redgl0w <43498612+RedGl0w@users.noreply.github.com> Date: Wed, 4 Mar 2020 07:05:09 +0100 Subject: [PATCH 056/117] Updated the month definition --- poincare/include/poincare/unit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index ed1e8e0f8..81e93e64c 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -235,7 +235,7 @@ public: Representative("week", "7*24*60*60*_s", Representative::Prefixable::No, NoPrefix), - Representative("month", "30*7*24*60*60*_s", + Representative("month", "30*24*60*60*_s", Representative::Prefixable::No, NoPrefix), Representative("year", "365.25*24*60*60*_s", From dfe51df3218aadd43d725a67b9a00076c9e7f151 Mon Sep 17 00:00:00 2001 From: redgl0w <43498612+RedGl0w@users.noreply.github.com> Date: Wed, 4 Mar 2020 07:06:42 +0100 Subject: [PATCH 057/117] Updated the month definition --- poincare/include/poincare/unit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 81e93e64c..97021c50c 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -235,7 +235,7 @@ public: Representative("week", "7*24*60*60*_s", Representative::Prefixable::No, NoPrefix), - Representative("month", "30*24*60*60*_s", + Representative("month", "365.25/12*24*60*60*_s", Representative::Prefixable::No, NoPrefix), Representative("year", "365.25*24*60*60*_s", From 1dc6e77049780b11ea7c639cd02af84876a831a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 2 Mar 2020 16:14:14 +0100 Subject: [PATCH 058/117] [poincare/matrix] Forbid nested matrices Scenario: in calculation, 1/matrix(matrix(matrix(matrix(... matrix(1) ... )))) gave kind of a weird result. These kind of computations also broke the fuzzer. --- poincare/include/poincare/expression.h | 1 + poincare/include/poincare/matrix.h | 4 ++-- poincare/src/expression.cpp | 4 ++-- poincare/src/matrix.cpp | 16 ++++++++++++++-- poincare/src/multiplication.cpp | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 9d4b3c084..25ec2da9c 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -112,6 +112,7 @@ class Expression : public TreeHandle { friend class IntegralNode; template friend class LogarithmNode; + friend class MatrixNode; friend class NaperianLogarithmNode; friend class NAryExpressionNode; friend class StoreNode; diff --git a/poincare/include/poincare/matrix.h b/poincare/include/poincare/matrix.h index 487e9b872..96f6e73cf 100644 --- a/poincare/include/poincare/matrix.h +++ b/poincare/include/poincare/matrix.h @@ -11,7 +11,7 @@ public: m_numberOfRows(0), m_numberOfColumns(0) {} - + bool hasMatrixChild(Context * context) const; int numberOfRows() const { return m_numberOfRows; } int numberOfColumns() const { return m_numberOfColumns; } virtual void setNumberOfRows(int rows) { assert(rows >= 0); m_numberOfRows = rows; } @@ -87,7 +87,7 @@ public: static constexpr int k_maxNumberOfCoefficients = 100; // Expression - Expression shallowReduce(); + Expression shallowReduce(Context * context); private: MatrixNode * node() const { return static_cast(Expression::node()); } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 1bdfc8e71..602bd3663 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -684,7 +684,6 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre /* Case 1: the reduced expression is a matrix: We scan the matrix children to * beautify them with the right complex format. */ if (e.type() == ExpressionNode::Type::Matrix) { - // TODO: this method enables to take the complex format into account when the result is a matrix of scalar. It won't work for nested matrices... Find a more elegant and general solution? Matrix m = static_cast(e); *simplifiedExpression = Matrix::Builder(); if (approximateExpression) { @@ -694,6 +693,7 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre Expression simplifiedChild; Expression approximateChild = approximateExpression ? Expression() : nullptr; e.childAtIndex(i).beautifyAndApproximateScalar(&simplifiedChild, &approximateChild, userReductionContext, context, complexFormat, angleUnit); + assert(!simplifiedChild.deepIsMatrix(context)); static_cast(simplifiedExpression)->addChildAtIndexInPlace(simplifiedChild, i, i); if (approximateExpression) { static_cast(approximateExpression)->addChildAtIndexInPlace(approximateChild, i, i); @@ -770,7 +770,7 @@ Expression Expression::mapOnMatrixFirstChild(ExpressionNode::ReductionContext re } matrix.setDimensions(static_cast(c).numberOfRows(), static_cast(c).numberOfColumns()); replaceWithInPlace(matrix); - return matrix.shallowReduce(); + return matrix.shallowReduce(reductionContext.context()); } Expression Expression::radianToAngleUnit(Preferences::AngleUnit angleUnit) { diff --git a/poincare/src/matrix.cpp b/poincare/src/matrix.cpp index fc541db09..e34393aef 100644 --- a/poincare/src/matrix.cpp +++ b/poincare/src/matrix.cpp @@ -20,6 +20,15 @@ namespace Poincare { static inline int minInt(int x, int y) { return x < y ? x : y; } +bool MatrixNode::hasMatrixChild(Context * context) const { + for (ExpressionNode * c : children()) { + if (Expression(c).deepIsMatrix(context)) { + return true; + } + } + return false; +} + void MatrixNode::didAddChildAtIndex(int newNumberOfChildren) { setNumberOfRows(1); setNumberOfColumns(newNumberOfChildren); @@ -30,7 +39,7 @@ int MatrixNode::polynomialDegree(Context * context, const char * symbolName) con } Expression MatrixNode::shallowReduce(ReductionContext reductionContext) { - return Matrix(this).shallowReduce(); + return Matrix(this).shallowReduce(reductionContext.context()); } Layout MatrixNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { @@ -390,7 +399,7 @@ Expression Matrix::determinant(ExpressionNode::ReductionContext reductionContext return result; } -Expression Matrix::shallowReduce() { +Expression Matrix::shallowReduce(Context * context) { { Expression e = Expression::defaultShallowReduce(); e = e.defaultHandleUnitsInChildren(); @@ -398,6 +407,9 @@ Expression Matrix::shallowReduce() { return e; } } + if (node()->hasMatrixChild(context)) { + return replaceWithUndefinedInPlace(); + } return *this; } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index aca11123c..2bd6a536e 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -677,7 +677,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext } } replaceWithInPlace(resultMatrix); - return resultMatrix.shallowReduce(); + return resultMatrix.shallowReduce(reductionContext.context()); } /* Step 4: Gather like terms. For example, turn pi^2*pi^3 into pi^5. Thanks to From 5ca6b7dbf8839c9d4c3a03c753c9618d7616c26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 9 Mar 2020 16:26:24 +0100 Subject: [PATCH 059/117] [poincare/code_point_layout] Fix collapsing Scenario: Enter "(12/34 * 10)" then press "Divide" -> the numerator of the division was not the whole parenthesed expression --- poincare/src/code_point_layout.cpp | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/poincare/src/code_point_layout.cpp b/poincare/src/code_point_layout.cpp index b85913194..5d32863b1 100644 --- a/poincare/src/code_point_layout.cpp +++ b/poincare/src/code_point_layout.cpp @@ -58,22 +58,22 @@ bool CodePointLayoutNode::isCollapsable(int * numberOfOpenParenthesis, bool goin } return false; } - } - if (isMultiplicationCodePoint()) { - /* We want '*' to be collapsable only if the following brother is not a - * fraction, so that the user can write intuitively "1/2 * 3/4". */ - Layout thisRef = CodePointLayout(this); - Layout parent = thisRef.parent(); - if (!parent.isUninitialized()) { - int indexOfThis = parent.indexOfChild(thisRef); - Layout brother; - if (indexOfThis > 0 && goingLeft) { - brother = parent.childAtIndex(indexOfThis-1); - } else if (indexOfThis < parent.numberOfChildren() - 1 && !goingLeft) { - brother = parent.childAtIndex(indexOfThis+1); - } - if (!brother.isUninitialized() && brother.type() == LayoutNode::Type::FractionLayout) { - return false; + if (isMultiplicationCodePoint()) { + /* We want '*' to be collapsable only if the following brother is not a + * fraction, so that the user can write intuitively "1/2 * 3/4". */ + Layout thisRef = CodePointLayout(this); + Layout parent = thisRef.parent(); + if (!parent.isUninitialized()) { + int indexOfThis = parent.indexOfChild(thisRef); + Layout brother; + if (indexOfThis > 0 && goingLeft) { + brother = parent.childAtIndex(indexOfThis-1); + } else if (indexOfThis < parent.numberOfChildren() - 1 && !goingLeft) { + brother = parent.childAtIndex(indexOfThis+1); + } + if (!brother.isUninitialized() && brother.type() == LayoutNode::Type::FractionLayout) { + return false; + } } } } From ad672f9111989a7e90a7871a03cf146e12e7baf4 Mon Sep 17 00:00:00 2001 From: David <0b101@users.noreply.github.com> Date: Mon, 9 Mar 2020 15:44:22 -0500 Subject: [PATCH 060/117] [Fix] Display bug where "x=a(x)" got cutoff --- apps/calculation/calculation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index a7b7e0540..2421dcbc4 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -164,7 +164,7 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre singleLine = exactOutputWidth + inputWidth < maxWidth - 40; if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) { KDCoordinate exactOutputBaseline = exactLayout.baseline(); - result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline); + result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline) + singleLine; } else { if (allExpressionsInline) { KDCoordinate exactOutputBaseline = exactLayout.baseline(); From cf84a307680029fdfd1cbb2f4bf0791d9cf54f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 4 Mar 2020 10:17:00 +0100 Subject: [PATCH 061/117] [poincare/absolute_value] ShallowReduce done in double, not float This fixes abs(-2.3*10^-39) that returned a negative value --- poincare/src/absolute_value.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/poincare/src/absolute_value.cpp b/poincare/src/absolute_value.cpp index 18bbafe14..bf4aee0d1 100644 --- a/poincare/src/absolute_value.cpp +++ b/poincare/src/absolute_value.cpp @@ -50,21 +50,21 @@ Expression AbsoluteValue::shallowReduce(ExpressionNode::ReductionContext reducti } // |x| = ±x if x is real if (c.isReal(reductionContext.context())) { - float app = c.node()->approximate(float(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()).toScalar(); - if (!std::isnan(app) && - ((c.isNumber() && app >= 0) || app >= Expression::Epsilon())) { - /* abs(a) = a with a >= 0 - * To check that a > 0, if a is a number we can use float comparison; - * in other cases, we are more conservative and rather check that - * a > epsilon ~ 1E-7 to avoid potential error due to float precision. */ - replaceWithInPlace(c); - return c; - } else if (!std::isnan(app) && - ((c.isNumber() && app < 0.0f) || app <= -Expression::Epsilon())) { - // abs(a) = -a with a < 0 (same comment as above to check that a < 0) - Multiplication m = Multiplication::Builder(Rational::Builder(-1), c); - replaceWithInPlace(m); - return m.shallowReduce(reductionContext); + double app = c.node()->approximate(double(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()).toScalar(); + if (!std::isnan(app)) { + if ((c.isNumber() && app >= 0) || app >= Expression::Epsilon()) { + /* abs(a) = a with a >= 0 + * To check that a > 0, if a is a number we can use float comparison; + * in other cases, we are more conservative and rather check that + * a > epsilon ~ 1E-7 to avoid potential error due to float precision. */ + replaceWithInPlace(c); + return c; + } else if ((c.isNumber() && app < 0.0f) || app <= -Expression::Epsilon()) { + // abs(a) = -a with a < 0 (same comment as above to check that a < 0) + Multiplication m = Multiplication::Builder(Rational::Builder(-1), c); + replaceWithInPlace(m); + return m.shallowReduce(reductionContext); + } } } // |a+ib| = sqrt(a^2+b^2) From c1215063ee9f7a9c877a7e78d8ebccdf01c2c45f Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 9 Mar 2020 22:22:21 -0400 Subject: [PATCH 062/117] Small fixes to the documentation --- docs/build/index.md | 2 +- docs/index.md | 15 +++++++-------- docs/ion/index.md | 10 +++++----- .../{expression_tree.svg => expression-tree.svg} | 0 docs/poincare/index.md | 5 ++--- 5 files changed, 15 insertions(+), 17 deletions(-) rename docs/poincare/{expression_tree.svg => expression-tree.svg} (100%) diff --git a/docs/build/index.md b/docs/build/index.md index f704da2d1..b34fd48ca 100644 --- a/docs/build/index.md +++ b/docs/build/index.md @@ -54,7 +54,7 @@ git clone https://github.com/numworks/epsilon.git ## Run Epsilon on your computer -Once the SDK has been installed, just open your terminal (Msys2, Terminal.app, xterm, etc...) and type the following commands: +Once the SDK has been installed, just open your terminal (Msys2, Terminal.app, xterm…) and type the following commands: ``` make PLATFORM=simulator clean diff --git a/docs/index.md b/docs/index.md index 509364255..edc128688 100644 --- a/docs/index.md +++ b/docs/index.md @@ -46,12 +46,11 @@ The choice of a programming language is a controversial topic. Not all of them c - It is a [system](https://en.wikipedia.org/wiki/System_programming_language) programming language, which is something we need since we have to write some low-level code. - It has excellent tooling: several extremly high-quality compilers -- It is used for several high-profile projects LLVM, WebKit, MySQL, Photoshop, etc... This ensures a strong ecosystem of tools, code and documentation. +- It is used for several high-profile projects LLVM, WebKit, MySQL, Photoshop… This ensures a strong ecosystem of tools, code and documentation. - It easily allows Object-Oriented Programming, which is a convenient abstraction. - Of course knowing a tool means knowing its limits. C++ isn't exempt of defaults: -- It *is* a complicated language. The C++ 11 specification is 1300 pages long. +- It *is* a complicated language. The C++ 11 specification is 1'300 pages long. - It allows for a lot of abstractions, which is a double-edged sword. It can allow for some very tricky code, and it's very easy to have complex operations being run without noticing. If you want to contribute to Epsilon, you'll need to learn some C++. @@ -66,7 +65,7 @@ The stack memory is possibly the most used area of memory. It contains all local #### Heap memory -Unfortunately, local variables can't answer all use cases, and sometimes one need to allocate memory that lives longer than a function call. This is traditionally done by using a pair of *malloc* / *free* functions. +Unfortunately, local variables can't answer all use cases, and sometimes one need to allocate memory that lives longer than a function call. This is traditionally done by using a pair of `malloc` / `free` functions. This raises a lot of potential problems that can trigger unpredictable dynamic behaviors: @@ -77,7 +76,7 @@ This raises a lot of potential problems that can trigger unpredictable dynamic b
Memory allocation has to be contiguous. So the allocation algorithm has to use a smart heuristic to ensure that it will not fragment its allocated space too much.
-Some automatic memory management solutions do exist (garbage collection, smart pointers), but they all come with a cost. We decided to manually manage dynamic memory, but to use it as sparingly as possible. +We decided to avoid `malloc` altogether and to use a mix of static allocation and a pool of relocatable garbage-collected nodes for manipulating mathematical expressions. ### Writing code that runs on the bare metal @@ -90,8 +89,8 @@ In practice, this means that the firmware will need to know in advance how the m - Where will we store read-only variables? - Where will the code live in memory? -The firmware will also need to take special care of the system initialization. There is no such thing as a "main" function on a firmware. Instead, on Cortex-M4 devices, after reset the CPU simply jumps to the address contained at address 0x00000000 (which happens to be the first bytes of flash memory). So if your firmware starts by 0x12345678, code execution will start at address 0x12345678. +The firmware will also need to take special care of the system initialization. There is no such thing as a "main" function on a firmware. Instead, on Cortex-M devices, after reset the CPU simply jumps to the address contained at address 0x00000000 (which happens to be the first bytes of flash memory). So if your firmware starts by 0x12345678, code execution will start at address 0x12345678. -Enforcing such a careful memory layout would be an impossible job without the proper tool. Fortunately, embedded linkers can be scripted and allow this kind of tailor-made configuration. You'll find Epsilon's linker script in "ion/src/device/boot/flash.ld" - it is heavily commented and should be self-explanatory. +Enforcing such a careful memory layout would be an impossible job without the proper tool. Fortunately, embedded linkers can be scripted and allow this kind of tailor-made configuration. You'll find Epsilon's linker script in [ion/src/device/n0110/flash.ld](https://github.com/numworks/epsilon/blob/master/ion/src/device/n0110/flash.ld) - it is heavily commented and should be self-explanatory. -That being said, there are additional things the OS usually takes care of which we need to do ourselves : for example, initialize global variables to zero. This is done in the "ion/src/device/boot/rt0.cpp" file, which is worth reading too. +That being said, there are additional things the OS usually takes care of which we need to do ourselves : for example, initialize global variables to zero. This is done in the [ion/src/device/shared/boot/rt0.cpp](https://github.com/numworks/epsilon/blob/master/ion/src/device/shared/boot/rt0.cpp) file, which is worth reading too. diff --git a/docs/ion/index.md b/docs/ion/index.md index 9d87c5458..c09205d95 100644 --- a/docs/ion/index.md +++ b/docs/ion/index.md @@ -11,25 +11,25 @@ By providing multiple implementations of the Ion functions, we therefore can get ## Device -This is the reference platform corresponding to the actual device. To really understand what the code is doing, you'll need to refer to our Electrical Engineering pages. Among other thing, Ion is responsible for handling the boot process and the memory layout of the code on the device: +This is the reference platform corresponding to the actual device. To really understand what the code is doing, you'll need to refer to our [Electrical Engineering](https://www.numworks.com/resources/engineering/hardware/electrical/) pages. Among other thing, Ion is responsible for handling the boot process and the memory layout of the code on the device: ### Boot -On boot, the Cortex core interprets the beginning of Flash memory as an array of addresses, each having a specific meaning. For example, the first value gives the address of the stack and the second one the address the processor jumps to right after reset. This list of addresses is called the ISR table. +On boot, the Cortex core interprets the beginning of Flash memory as an array of addresses, each having a specific meaning. For example, the first value gives the address of the stack and the second one the address the processor jumps to right after reset. This list of addresses is called the [ISR table](https://github.com/numworks/epsilon/blob/master/ion/src/device/shared/boot/isr.c). ### Memory layout -Like we saw in the previous paragraph, the MCU has a specific memory layout (for example, Flash starts at address 0x08000000) and expects certain values at certain addresses. To ensure the firmware is laid out in memory exactly how the processor expects it, we use a custom linker script. +Like we saw in the previous paragraph, the MCU has a specific memory layout (for example, Flash starts at address 0x08000000) and expects certain values at certain addresses. To ensure the firmware is laid out in memory exactly how the processor expects it, we use a custom [linker script](https://github.com/numworks/epsilon/blob/master/ion/src/device/n0110/flash.ld). ## Simulator -The simulator platform implements Ion calls using the FLTK library. The result is a native GUI program that can run under a variety of operating systems such as Windows, macOS or most Linux distributions. +The simulator platform implements Ion calls using the [SDL](https://www.libsdl.org/) library. The result is a native GUI program that can run under a variety of operating systems such as Windows, macOS or most Linux distributions. It's very practical to code using the simulator, but one has to pay attention to the differences from an actual device: it'll be significantly faster, and will have a lot more memory. So code written using the simulator should always be thoroughly tested on an actual device. ## Emscripten -The emscripten platform implements Ion calls for a Web browser. This lets us build a version of Epsilon that can run directly in a browser, as shown in our online simulator. The C++ code is transpiled to JavaScript using Emscripten, and then packaged in a webpage. +The emscripten platform implements Ion calls for a Web browser. This lets us build a version of Epsilon that can run directly in a browser, as shown in our [online simulator](https://www.numworks.com/simulator/). The C++ code is transpiled to JavaScript using Emscripten, and then packaged in a webpage. Building on Emscripten takes quite a lot of time so you will most likely not want to use it for development purposes. But obviously it's a very neat feature for end users who can give the calculator a spin straight from their browser. diff --git a/docs/poincare/expression_tree.svg b/docs/poincare/expression-tree.svg similarity index 100% rename from docs/poincare/expression_tree.svg rename to docs/poincare/expression-tree.svg diff --git a/docs/poincare/index.md b/docs/poincare/index.md index f1ada84eb..0e08b9cb2 100644 --- a/docs/poincare/index.md +++ b/docs/poincare/index.md @@ -1,5 +1,5 @@ --- -title: Poincare +title: Poincaré --- # Poincaré @@ -9,7 +9,7 @@ Poincare takes text input such as `1+2*3` and turns it into a tree structure, th Each node of a tree represents either an operator or a value. All nodes have a type (`Type::Addition`, `Type::Multiplication`...) and some also store a value (ie `Type::Rational`). -![A example expression tree of Epsilon software](<%= p "expression_tree.svg" %>){:class="img-right"} +![A example expression tree of Epsilon software](<%= p "expression-tree.svg" %>){:class="img-right"} According to their types, expressions are childless (`Type::Rational`) or store pointers to their children (we call those children operands). To ease tree traversal, each node also keeps a pointer to its parent: that information is somewhat redundant but makes dealing with the expression tree much easier. `Multiplication` and `Addition` are the only type that can hold an infinite number of operands. Other expressions have a fixed number of operands: for instance, an `AbsoluteValue` will only ever have one child. ## RTTI: Run-time type information @@ -43,7 +43,6 @@ To sort those operands, we defined an order on expressions with the following fe * The order relationship is depth-first recursive: if two expressions are equal in type and values, we compare their operands starting with the last. * To compare two expressions, we first sort their commutative children to ensure the unicity of expression representations. This guarantees that the order is total on expressions. - ![Order relationship on expressions](<%= p "order.svg" %>){:class="img-responsive"} In the example, both root nodes are r so we compare their last operands. Both are equal to $$\pi$$ so we compare the next operands. As 3 > 2, we can conclude on the order relation between the expressions. From fccd72b7573f10531637fc2042e0f231e8fb458d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 2 Mar 2020 14:54:37 +0100 Subject: [PATCH 063/117] [apps/sequence/sequence] Do not memoize nameLayout Fixes the following bug: In the graph tab of the Sequence app, compute the sum of the terms of a sequence from 1 to 9 and then from 1 to 10. The Layout is memoized after the first time and mispositioned the second time since it is not recomputed. --- apps/sequence/sequence.cpp | 12 ++++-------- apps/sequence/sequence.h | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index e97f8d390..64643ace1 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -28,7 +28,6 @@ void Sequence::tidy() { m_firstInitialCondition.tidyName(); m_secondInitialCondition.tidy(); m_secondInitialCondition.tidyName(); - m_nameLayout = Layout(); } Sequence::Type Sequence::type() const { @@ -81,13 +80,10 @@ void Sequence::setInitialRank(int rank) { } Poincare::Layout Sequence::nameLayout() { - if (m_nameLayout.isUninitialized()) { - m_nameLayout = HorizontalLayout::Builder( - CodePointLayout::Builder(fullName()[0], KDFont::SmallFont), - VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript) - ); - } - return m_nameLayout; + return HorizontalLayout::Builder( + CodePointLayout::Builder(fullName()[0], KDFont::SmallFont), + VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript) + ); } bool Sequence::isDefined() { diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index e7901de68..d5b5c56a5 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -24,8 +24,9 @@ public: DoubleRecurrence = 2 }; Sequence(Ion::Storage::Record record = Record()) : - Function(record), - m_nameLayout() {} + Function(record) + { + } I18n::Message parameterMessageName() const override; CodePoint symbol() const override { return 'n'; } void tidy() override; @@ -153,7 +154,6 @@ private: DefinitionModel m_definition; FirstInitialConditionModel m_firstInitialCondition; SecondInitialConditionModel m_secondInitialCondition; - Poincare::Layout m_nameLayout; }; } From 7a633b1e7591ac298c5325ca452feac9c590394e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 2 Mar 2020 15:04:45 +0100 Subject: [PATCH 064/117] [apps/sequence/sequence] SequenceModel's name method need not be virtual --- apps/sequence/sequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index d5b5c56a5..d8e2a5f6d 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -112,7 +112,7 @@ private: public: SequenceModel() : Shared::ExpressionModel(), m_name() {} void tidyName() { m_name = Poincare::Layout(); } - virtual Poincare::Layout name(Sequence * sequence); + Poincare::Layout name(Sequence * sequence); protected: virtual void buildName(Sequence * sequence) = 0; Poincare::Layout m_name; From e1624c79aaab5288fd449476df331e9673a12f91 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 10:55:15 +0100 Subject: [PATCH 065/117] [apps/shared/sum_graph_controller] Class doesn't need to hold m_sumLayout --- apps/shared/sum_graph_controller.cpp | 14 +++++++------- apps/shared/sum_graph_controller.h | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index f7a72048a..2db803aad 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -157,7 +157,6 @@ void SumGraphController::reloadBannerView() { SumGraphController::LegendView::LegendView(SumGraphController * controller, InputEventHandlerDelegate * inputEventHandlerDelegate, CodePoint sumSymbol) : m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_sumLayout(), m_legend(k_font, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), m_editableZone(controller, m_textBuffer, k_editableZoneBufferSize, TextField::maxBufferSize(), inputEventHandlerDelegate, controller, k_font, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), m_sumSymbol(sumSymbol) @@ -190,14 +189,15 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; + Poincare::Layout sumLayout; if (step == Step::FirstParameter) { - m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); + sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); } else if (step == Step::SecondParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); - m_sumLayout = CondensedSumLayout::Builder( + sumLayout = CondensedSumLayout::Builder( LayoutHelper::CodePointString(sigma, sigmaLength), LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); @@ -210,18 +210,18 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); - m_sumLayout = CondensedSumLayout::Builder( + sumLayout = CondensedSumLayout::Builder( LayoutHelper::CodePointString(sigma, sigmaLength), start, end); strlcpy(buffer, "= ", 3); PoincareHelpers::ConvertFloatToText(result, buffer+2, bufferSize-2, precision); - m_sumLayout = HorizontalLayout::Builder( - m_sumLayout, + sumLayout = HorizontalLayout::Builder( + sumLayout, functionLayout, LayoutHelper::String(buffer, strlen(buffer), k_font)); } - m_sum.setLayout(m_sumLayout); + m_sum.setLayout(sumLayout); if (step == Step::Result) { m_sum.setAlignment(0.5f, 0.5f); } else { diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 8042117b2..c8ba87936 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -69,7 +69,6 @@ private: void layoutSubviews(bool force = false) override; void layoutSubviews(Step step, bool force); ExpressionView m_sum; - Poincare::Layout m_sumLayout; MessageTextView m_legend; TextField m_editableZone; char m_textBuffer[k_editableZoneBufferSize]; From 6b527d3b00e6aa7806dccb2bc5c010cd1bffca2a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 11:47:12 +0100 Subject: [PATCH 066/117] [apps/shared/sum_graph_controller] Rename setSumSymbol to setSumLayout --- apps/shared/sum_graph_controller.cpp | 4 ++-- apps/shared/sum_graph_controller.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 2db803aad..06b8ed49a 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -150,7 +150,7 @@ void SumGraphController::reloadBannerView() { m_legendView.setEditableZone(m_cursor->x()); result = NAN; } - m_legendView.setSumSymbol(m_step, m_startSum, endSum, result, functionLayout); + m_legendView.setSumLayout(m_step, m_startSum, endSum, result, functionLayout); } /* Legend View */ @@ -185,7 +185,7 @@ void SumGraphController::LegendView::setEditableZone(double d) { m_editableZone.setText(buffer); } -void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, Layout functionLayout) { +void SumGraphController::LegendView::setSumLayout(Step step, double start, double end, double result, Layout functionLayout) { assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index c8ba87936..de57d7691 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -55,7 +55,7 @@ private: void drawRect(KDContext * ctx, KDRect rect) const override; void setLegendMessage(I18n::Message message, Step step); void setEditableZone(double d); - void setSumSymbol(Step step, double start, double end, double result, Poincare::Layout functionLayout); + void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; constexpr static KDCoordinate k_legendHeight = 35; From 24fa8b28a9fd3ff58f85363ab2acc6351dc32e38 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 11:47:51 +0100 Subject: [PATCH 067/117] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor m_sum.setAlignment --- apps/shared/sum_graph_controller.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 06b8ed49a..26d487733 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -222,11 +222,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl LayoutHelper::String(buffer, strlen(buffer), k_font)); } m_sum.setLayout(sumLayout); - if (step == Step::Result) { - m_sum.setAlignment(0.5f, 0.5f); - } else { - m_sum.setAlignment(0.0f, 0.5f); - } + m_sum.setAlignment(0.5f * (step == Step::Result), 0.5f); layoutSubviews(step, false); } From 7ee8c31c7019a281ccadca3e53490b41d3f29e3f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 13:57:17 +0100 Subject: [PATCH 068/117] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor sum symbol layout --- apps/shared/sum_graph_controller.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 26d487733..6314f9e51 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -189,16 +189,15 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; - Poincare::Layout sumLayout; + Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); if (step == Step::FirstParameter) { - sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); } else if (step == Step::SecondParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); sumLayout = CondensedSumLayout::Builder( - LayoutHelper::CodePointString(sigma, sigmaLength), + sumLayout, LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { @@ -211,7 +210,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); sumLayout = CondensedSumLayout::Builder( - LayoutHelper::CodePointString(sigma, sigmaLength), + sumLayout, start, end); strlcpy(buffer, "= ", 3); From 04794dd26f2d6ede003eccdc2925343eb7d8f203 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 14:00:38 +0100 Subject: [PATCH 069/117] [apps/shared/sum_graph_controller] Uniformize number of significant digits --- apps/shared/sum_graph_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 6314f9e51..dfc0e32c5 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -201,7 +201,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { - constexpr int precision = Preferences::LargeNumberOfSignificantDigits; + constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision); constexpr int bufferSize = 2 + sizeForPrecision; char buffer[bufferSize]; From 0a92579571dcf529dca92ee7996055b1ff0ebd0a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 14:07:59 +0100 Subject: [PATCH 070/117] [apps/shared/sum_graph_controller] Fix variable type --- apps/shared/sum_graph_controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index de57d7691..3119d9577 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -57,7 +57,7 @@ private: void setEditableZone(double d); void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: - constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; + constexpr static size_t k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; constexpr static KDCoordinate k_legendHeight = 35; constexpr static const KDFont * k_font = KDFont::SmallFont; static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); } From 55bb3f677aa3c246b7fc658c3b3e823782fde675 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 14:51:27 +0100 Subject: [PATCH 071/117] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, simplify equal sign --- apps/shared/sum_graph_controller.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index dfc0e32c5..ff3e13a39 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -202,8 +202,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision); - constexpr int bufferSize = 2 + sizeForPrecision; + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); @@ -213,11 +212,11 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl sumLayout, start, end); - strlcpy(buffer, "= ", 3); - PoincareHelpers::ConvertFloatToText(result, buffer+2, bufferSize-2, precision); + PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); sumLayout = HorizontalLayout::Builder( sumLayout, functionLayout, + LayoutHelper::String("= ", 2, k_font), LayoutHelper::String(buffer, strlen(buffer), k_font)); } m_sum.setLayout(sumLayout); From f0ef84b3bc1385862b76aa5c7f9750aeed5ec864 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 15:56:04 +0100 Subject: [PATCH 072/117] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor Layout building --- apps/shared/sum_graph_controller.cpp | 38 +++++++++++++--------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index ff3e13a39..6f9797c97 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -190,34 +190,30 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); - if (step == Step::FirstParameter) { - } else if (step == Step::SecondParameter) { + if (step != Step::FirstParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; + Layout endLayout; + if (step == Step::SecondParameter) { + endLayout = EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false); + } else { + PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + endLayout = LayoutHelper::String(buffer, strlen(buffer), k_font); + } PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); sumLayout = CondensedSumLayout::Builder( sumLayout, LayoutHelper::String(buffer, strlen(buffer), k_font), - EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); - } else { - constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); - char buffer[bufferSize]; - PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); - Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); - PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); - Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); - sumLayout = CondensedSumLayout::Builder( - sumLayout, - start, - end); - PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); - sumLayout = HorizontalLayout::Builder( - sumLayout, - functionLayout, - LayoutHelper::String("= ", 2, k_font), - LayoutHelper::String(buffer, strlen(buffer), k_font)); + endLayout); + if (step == Step::Result) { + PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); + sumLayout = HorizontalLayout::Builder( + sumLayout, + functionLayout, + LayoutHelper::String("= ", 2, k_font), + LayoutHelper::String(buffer, strlen(buffer), k_font)); + } } m_sum.setLayout(sumLayout); m_sum.setAlignment(0.5f * (step == Step::Result), 0.5f); From afb1d18d65af767cac392c9fa23e40f298e981b1 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 2 Mar 2020 18:00:19 +0100 Subject: [PATCH 073/117] [apps/shared/sum_graph_controller] Factor constexpr --- apps/shared/sum_graph_controller.cpp | 17 ++++++----------- apps/shared/sum_graph_controller.h | 2 ++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 6f9797c97..ac5ce035e 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "poincare_helpers.h" #include @@ -178,10 +177,8 @@ void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Ste } void SumGraphController::LegendView::setEditableZone(double d) { - constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); - char buffer[bufferSize]; - PoincareHelpers::ConvertFloatToTextWithDisplayMode(d, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + char buffer[k_valuesBufferSize]; + PoincareHelpers::ConvertFloatToTextWithDisplayMode(d, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal); m_editableZone.setText(buffer); } @@ -191,23 +188,21 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); if (step != Step::FirstParameter) { - constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); - char buffer[bufferSize]; + char buffer[k_valuesBufferSize]; Layout endLayout; if (step == Step::SecondParameter) { endLayout = EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false); } else { - PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal); endLayout = LayoutHelper::String(buffer, strlen(buffer), k_font); } - PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal); sumLayout = CondensedSumLayout::Builder( sumLayout, LayoutHelper::String(buffer, strlen(buffer), k_font), endLayout); if (step == Step::Result) { - PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); + PoincareHelpers::ConvertFloatToText(result, buffer, k_valuesBufferSize, k_valuesPrecision); sumLayout = HorizontalLayout::Builder( sumLayout, functionLayout, diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 3119d9577..e876f23c8 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -58,6 +58,8 @@ private: void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: constexpr static size_t k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; + constexpr static int k_valuesPrecision = Poincare::Preferences::MediumNumberOfSignificantDigits; + constexpr static int k_valuesBufferSize = Poincare::PrintFloat::charSizeForFloatsWithPrecision(k_valuesPrecision); constexpr static KDCoordinate k_legendHeight = 35; constexpr static const KDFont * k_font = KDFont::SmallFont; static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); } From aa4a33d84940252e511dc83fe3281fcf05f39a7d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 3 Mar 2020 10:11:01 +0100 Subject: [PATCH 074/117] [poincare/layout_node] Remove unused method --- poincare/include/poincare/layout_node.h | 1 - poincare/src/layout_node.cpp | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/poincare/include/poincare/layout_node.h b/poincare/include/poincare/layout_node.h index 5ec8855c3..afad9aae1 100644 --- a/poincare/include/poincare/layout_node.h +++ b/poincare/include/poincare/layout_node.h @@ -61,7 +61,6 @@ public: // Rendering void draw(KDContext * ctx, KDPoint p, KDColor expressionColor = KDColorBlack, KDColor backgroundColor = KDColorWhite, Layout * selectionStart = nullptr, Layout * selectionEnd = nullptr, KDColor selectionColor = KDColorRed); - KDPoint origin(); KDPoint absoluteOrigin(); KDSize layoutSize(); KDCoordinate baseline(); diff --git a/poincare/src/layout_node.cpp b/poincare/src/layout_node.cpp index 2c50dd9a6..7c33a2f3d 100644 --- a/poincare/src/layout_node.cpp +++ b/poincare/src/layout_node.cpp @@ -39,16 +39,6 @@ void LayoutNode::draw(KDContext * ctx, KDPoint p, KDColor expressionColor, KDCol } } -KDPoint LayoutNode::origin() { - LayoutNode * p = parent(); - if (p == nullptr) { - return absoluteOrigin(); - } else { - return KDPoint(absoluteOrigin().x() - p->absoluteOrigin().x(), - absoluteOrigin().y() - p->absoluteOrigin().y()); - } -} - KDPoint LayoutNode::absoluteOrigin() { LayoutNode * p = parent(); if (!m_positioned) { From ed98218e7bb4e911eaa934024610de57347f2264 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 3 Mar 2020 14:05:58 +0100 Subject: [PATCH 075/117] [poincare/grid_layout] Explicit the making of a protected member as public --- poincare/include/poincare/grid_layout.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/poincare/include/poincare/grid_layout.h b/poincare/include/poincare/grid_layout.h index 91890c5b0..8a7534386 100644 --- a/poincare/include/poincare/grid_layout.h +++ b/poincare/include/poincare/grid_layout.h @@ -95,9 +95,7 @@ public: static GridLayout Builder() { return TreeHandle::NAryBuilder(); } void setDimensions(int rows, int columns); - void addChildAtIndex(Layout l, int index, int currentNumberOfChildren, LayoutCursor * cursor) { - Layout::addChildAtIndex(l, index, currentNumberOfChildren, cursor); - } + using Layout::addChildAtIndex; int numberOfRows() const { return node()->numberOfRows(); } int numberOfColumns() const { return node()->numberOfColumns(); } private: From 8337e36f46f9d1a0f55c5698e683440d084ff310 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 4 Mar 2020 14:48:20 +0100 Subject: [PATCH 076/117] [apps/shared/*_cursor_view] CursorView inherits from TransparentView so that CursorView tells its superview to redrawn in the background, except the RoundCursorView. --- apps/shared/cursor_view.h | 4 ++-- apps/shared/round_cursor_view.cpp | 4 ++++ apps/shared/round_cursor_view.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/shared/cursor_view.h b/apps/shared/cursor_view.h index 4590950b2..c0f5c6062 100644 --- a/apps/shared/cursor_view.h +++ b/apps/shared/cursor_view.h @@ -1,11 +1,11 @@ #ifndef SHARED_CURSOR_VIEW_H #define SHARED_CURSOR_VIEW_H -#include +#include namespace Shared { -class CursorView : public View { +class CursorView : public TransparentView { public: virtual void setCursorFrame(KDRect frame, bool force) { View::setFrame(frame, force); } void drawRect(KDContext * ctx, KDRect rect) const override; diff --git a/apps/shared/round_cursor_view.cpp b/apps/shared/round_cursor_view.cpp index 5355f544b..ecc0fad09 100644 --- a/apps/shared/round_cursor_view.cpp +++ b/apps/shared/round_cursor_view.cpp @@ -49,6 +49,10 @@ void RoundCursorView::setCursorFrame(KDRect f, bool force) { CursorView::setCursorFrame(f, force); } +void RoundCursorView::markRectAsDirty(KDRect rect) { + View::markRectAsDirty(rect); +} + #ifdef GRAPH_CURSOR_SPEEDUP bool RoundCursorView::eraseCursorIfPossible() { if (!m_underneathPixelBufferLoaded) { diff --git a/apps/shared/round_cursor_view.h b/apps/shared/round_cursor_view.h index 001113406..eff1f93c3 100644 --- a/apps/shared/round_cursor_view.h +++ b/apps/shared/round_cursor_view.h @@ -24,6 +24,7 @@ public: void resetMemoization() const { m_underneathPixelBufferLoaded = false; } #endif private: + void markRectAsDirty(KDRect rect) override; #ifdef GRAPH_CURSOR_SPEEDUP bool eraseCursorIfPossible(); #endif From d64e58b9dc5490d0e4ac23b65af11ec62eb414af Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 4 Mar 2020 14:50:57 +0100 Subject: [PATCH 077/117] [escher/transparent_view] Remove redundancy --- escher/src/transparent_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/transparent_view.cpp b/escher/src/transparent_view.cpp index 9f85ecd80..631910362 100644 --- a/escher/src/transparent_view.cpp +++ b/escher/src/transparent_view.cpp @@ -2,7 +2,7 @@ void TransparentView::markRectAsDirty(KDRect rect) { if (m_superview) { - m_superview->markRectAsDirty(KDRect(rect.translatedBy(m_frame.origin()))); + m_superview->markRectAsDirty(rect.translatedBy(m_frame.origin())); } View::markRectAsDirty(rect); } From 037fa088e986ac57a7ef1ca7022683c2ddeb5698 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 4 Mar 2020 14:51:45 +0100 Subject: [PATCH 078/117] [escher/transparent_view] markRectAsDirty is protected as it is in View. --- escher/include/escher/transparent_view.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/include/escher/transparent_view.h b/escher/include/escher/transparent_view.h index 582e20eac..6f7865f54 100644 --- a/escher/include/escher/transparent_view.h +++ b/escher/include/escher/transparent_view.h @@ -4,7 +4,7 @@ #include class TransparentView : public View { -public: +protected: void markRectAsDirty(KDRect rect) override; }; From 1ca902c129f400051a7d57a73b571b72ea0a61da Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 10 Mar 2020 10:43:51 +0100 Subject: [PATCH 079/117] [apps/shared/round_cursor_view] Comment about markRectAsDirty --- apps/shared/round_cursor_view.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/shared/round_cursor_view.cpp b/apps/shared/round_cursor_view.cpp index ecc0fad09..790817b7d 100644 --- a/apps/shared/round_cursor_view.cpp +++ b/apps/shared/round_cursor_view.cpp @@ -50,6 +50,10 @@ void RoundCursorView::setCursorFrame(KDRect f, bool force) { } void RoundCursorView::markRectAsDirty(KDRect rect) { + /* The CursorView class inherits from TransparentView, so does + * RoundCursorView. The method markRectAsDirty is thus overriden to avoid + * marking as dirty the background of the RoundCursorView in its superview. + */ View::markRectAsDirty(rect); } From 79f3ee43bc8a38b97ff395f3d3620ef64369ad42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Mar 2020 10:59:21 +0100 Subject: [PATCH 080/117] [poincare/parser] log_ is not a special identifier anymore The change was made a few commits ago, but this was forgotten --- poincare/src/parsing/parser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 2475a7583..a015c7104 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -51,8 +51,7 @@ bool Parser::IsSpecialIdentifierName(const char * name, size_t nameLength) { Token::CompareNonNullTerminatedName(name, nameLength, "w_") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "u") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "v") == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "w") == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "log_") == 0 + Token::CompareNonNullTerminatedName(name, nameLength, "w") == 0 ); } From ef249b0bdbd9e7e218e2e41afd0cd36d6c06af19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Mar 2020 11:10:49 +0100 Subject: [PATCH 081/117] [poincare/parser] parseSpecialId must go through one of the subcases Otherwise we might go through the method without creating leftHandSide --- poincare/src/parsing/parser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index a015c7104..5329e8141 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -444,10 +444,10 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) { leftHandSide = Undefined::Builder(); } else if (m_currentToken.compareTo(Unreal::Name()) == 0) { leftHandSide = Unreal::Builder(); - } else if (m_currentToken.compareTo("u") == 0 - || m_currentToken.compareTo("v") == 0 - || m_currentToken.compareTo("w") == 0) - { + } else { + assert(m_currentToken.compareTo("u") == 0 + || m_currentToken.compareTo("v") == 0 + || m_currentToken.compareTo("w") == 0); /* Special case for sequences (e.g. "u(n)", "u{n}", ...) * We know that m_currentToken.text()[0] is either 'u', 'v' or 'w', so we do * not need to pass a code point to parseSequence. */ From 2bf83c43a84c8f7624e34bb62b44ccc568e13a46 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 10 Mar 2020 18:29:01 -0400 Subject: [PATCH 082/117] [apps/shared] Factorize CurveView::label There was a lot of code duplication. I removed the initialization of xLabel{} and yLabels{} because those are scratch buffers that shouldn't be accessed before being written to anyway. --- .../additional_outputs/complex_graph_cell.cpp | 2 +- .../additional_outputs/complex_graph_cell.h | 9 +---- .../trigonometry_graph_cell.h | 1 - apps/regression/graph_view.cpp | 15 +------- apps/regression/graph_view.h | 7 +--- apps/shared/Makefile | 1 + apps/shared/curve_view.h | 2 +- apps/shared/function_graph_view.cpp | 8 +--- apps/shared/function_graph_view.h | 7 +--- apps/shared/labeled_curve_view.cpp | 31 ++++++++++++++++ apps/shared/labeled_curve_view.h | 37 +++++++++++++++++++ apps/statistics/box_axis_view.cpp | 4 -- apps/statistics/box_axis_view.h | 9 ++--- apps/statistics/box_view.h | 1 - apps/statistics/histogram_view.cpp | 7 +--- apps/statistics/histogram_view.h | 5 +-- 16 files changed, 86 insertions(+), 60 deletions(-) create mode 100644 apps/shared/labeled_curve_view.cpp create mode 100644 apps/shared/labeled_curve_view.h diff --git a/apps/calculation/additional_outputs/complex_graph_cell.cpp b/apps/calculation/additional_outputs/complex_graph_cell.cpp index aabe9b630..e4249e8f2 100644 --- a/apps/calculation/additional_outputs/complex_graph_cell.cpp +++ b/apps/calculation/additional_outputs/complex_graph_cell.cpp @@ -6,7 +6,7 @@ using namespace Poincare; namespace Calculation { ComplexGraphView::ComplexGraphView(ComplexModel * complexModel) : - CurveView(complexModel), + LabeledCurveView(complexModel), m_complex(complexModel) { } diff --git a/apps/calculation/additional_outputs/complex_graph_cell.h b/apps/calculation/additional_outputs/complex_graph_cell.h index bf440202f..7777c9991 100644 --- a/apps/calculation/additional_outputs/complex_graph_cell.h +++ b/apps/calculation/additional_outputs/complex_graph_cell.h @@ -1,24 +1,19 @@ #ifndef CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H #define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H -#include "../../shared/curve_view.h" +#include "../../shared/labeled_curve_view.h" #include "complex_model.h" #include "illustration_cell.h" namespace Calculation { -class ComplexGraphView : public Shared::CurveView { +class ComplexGraphView : public Shared::LabeledCurveView { public: ComplexGraphView(ComplexModel * complexModel); void drawRect(KDContext * ctx, KDRect rect) const override; private: - char * label(Axis axis, int index) const override { - return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]); - } // '-' + significant digits + ".E-" + 2 digits (the represented dot is a float, so it is bounded by 1E38 and 1E-38 size_t labelMaxGlyphLengthSize() const override { return 1 + Poincare::Preferences::VeryShortNumberOfSignificantDigits + 3 + 2; } - char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; - char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; ComplexModel * m_complex; }; diff --git a/apps/calculation/additional_outputs/trigonometry_graph_cell.h b/apps/calculation/additional_outputs/trigonometry_graph_cell.h index 1bf126707..aea81926a 100644 --- a/apps/calculation/additional_outputs/trigonometry_graph_cell.h +++ b/apps/calculation/additional_outputs/trigonometry_graph_cell.h @@ -12,7 +12,6 @@ public: TrigonometryGraphView(TrigonometryModel * model); void drawRect(KDContext * ctx, KDRect rect) const override; private: - char * label(Axis axis, int index) const override { return nullptr; } TrigonometryModel * m_model; }; diff --git a/apps/regression/graph_view.cpp b/apps/regression/graph_view.cpp index afdbdab0c..3b7b1371a 100644 --- a/apps/regression/graph_view.cpp +++ b/apps/regression/graph_view.cpp @@ -9,10 +9,8 @@ using namespace Shared; namespace Regression { GraphView::GraphView(Store * store, CurveViewCursor * cursor, BannerView * bannerView, Shared::CursorView * cursorView) : - CurveView(store, cursor, bannerView, cursorView), - m_store(store), - m_xLabels{}, - m_yLabels{} + LabeledCurveView(store, cursor, bannerView, cursorView), + m_store(store) { } @@ -41,13 +39,4 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { } } -char * GraphView::label(Axis axis, int index) const { - if (axis == Axis::Vertical) { - assert(index < k_maxNumberOfXLabels); - return (char *)m_yLabels[index]; - } - assert(index < k_maxNumberOfYLabels); - return (char *)m_xLabels[index]; -} - } diff --git a/apps/regression/graph_view.h b/apps/regression/graph_view.h index 17269ad1c..22db0b635 100644 --- a/apps/regression/graph_view.h +++ b/apps/regression/graph_view.h @@ -3,19 +3,16 @@ #include "store.h" #include "../constant.h" -#include "../shared/curve_view.h" +#include "../shared/labeled_curve_view.h" namespace Regression { -class GraphView : public Shared::CurveView { +class GraphView : public Shared::LabeledCurveView { public: GraphView(Store * store, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, Shared::CursorView * cursorView); void drawRect(KDContext * ctx, KDRect rect) const override; private: - char * label(Axis axis, int index) const override; Store * m_store; - char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; - char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; }; } diff --git a/apps/shared/Makefile b/apps/shared/Makefile index e97b68ed0..98e4a8fe6 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -45,6 +45,7 @@ app_shared_src = $(addprefix apps/shared/,\ interactive_curve_view_controller.cpp \ interval.cpp \ interval_parameter_controller.cpp \ + labeled_curve_view.cpp \ language_controller.cpp \ layout_field_delegate.cpp \ list_parameter_controller.cpp \ diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 2512ec432..99d4ddd07 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -100,7 +100,7 @@ private: float min(Axis axis) const; float max(Axis axis) const; float gridUnit(Axis axis) const; - virtual char * label(Axis axis, int index) const = 0; + virtual char * label(Axis axis, int index) const { return nullptr; } virtual size_t labelMaxGlyphLengthSize() const { return k_labelBufferMaxGlyphLength; } int numberOfLabels(Axis axis) const; /* Recursively join two dots (dichotomy). The method stops when the diff --git a/apps/shared/function_graph_view.cpp b/apps/shared/function_graph_view.cpp index ee8cd73fc..587a49fcb 100644 --- a/apps/shared/function_graph_view.cpp +++ b/apps/shared/function_graph_view.cpp @@ -8,13 +8,11 @@ namespace Shared { FunctionGraphView::FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, BannerView * bannerView, CursorView * cursorView) : - CurveView(graphRange, cursor, bannerView, cursorView), + LabeledCurveView(graphRange, cursor, bannerView, cursorView), m_selectedRecord(), m_highlightedStart(NAN), m_highlightedEnd(NAN), m_shouldColorHighlighted(false), - m_xLabels{}, - m_yLabels{}, m_context(nullptr) { } @@ -67,10 +65,6 @@ void FunctionGraphView::setAreaHighlightColor(bool highlightColor) { } } -char * FunctionGraphView::label(Axis axis, int index) const { - return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]); -} - void FunctionGraphView::reloadBetweenBounds(float start, float end) { if (start == end) { return; diff --git a/apps/shared/function_graph_view.h b/apps/shared/function_graph_view.h index 0ec2f11cf..4e3f0a55a 100644 --- a/apps/shared/function_graph_view.h +++ b/apps/shared/function_graph_view.h @@ -2,14 +2,14 @@ #define SHARED_FUNCTION_GRAPH_VIEW_H #include -#include "curve_view.h" +#include "labeled_curve_view.h" #include "function.h" #include "../constant.h" #include "interactive_curve_view_range.h" namespace Shared { -class FunctionGraphView : public CurveView { +class FunctionGraphView : public LabeledCurveView { public: FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, BannerView * bannerView, CursorView * cursorView); @@ -26,9 +26,6 @@ protected: float m_highlightedEnd; bool m_shouldColorHighlighted; private: - char * label(Axis axis, int index) const override; - char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; - char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; Poincare::Context * m_context; }; diff --git a/apps/shared/labeled_curve_view.cpp b/apps/shared/labeled_curve_view.cpp new file mode 100644 index 000000000..2a10c6655 --- /dev/null +++ b/apps/shared/labeled_curve_view.cpp @@ -0,0 +1,31 @@ +#include "labeled_curve_view.h" + +namespace Shared { + +char * HorizontallyLabeledCurveView::label(Axis axis, int index) const { + if (axis == Axis::Horizontal) { + assert(index < k_maxNumberOfXLabels); + return m_xLabels[index]; + } + return nullptr; +} + +char * VerticallyLabeledCurveView::label(Axis axis, int index) const { + if (axis == Axis::Vertical) { + assert(index < k_maxNumberOfYLabels); + return m_yLabels[index]; + } + return nullptr; +} + +char * LabeledCurveView::label(Axis axis, int index) const { + if (axis == Axis::Horizontal) { + assert(index < k_maxNumberOfXLabels); + return m_xLabels[index]; + } else { + assert(index < k_maxNumberOfYLabels); + return m_yLabels[index]; + } +} + +} diff --git a/apps/shared/labeled_curve_view.h b/apps/shared/labeled_curve_view.h new file mode 100644 index 000000000..cc094702b --- /dev/null +++ b/apps/shared/labeled_curve_view.h @@ -0,0 +1,37 @@ +#ifndef SHARED_LABELED_CURVE_VIEW_H +#define SHARED_LABELED_CURVE_VIEW_H + +#include "curve_view.h" + +/* This CurveView subclass provides label storage for common use cases */ + +namespace Shared { + +class HorizontallyLabeledCurveView : public CurveView { +public: + using CurveView::CurveView; +private: + char * label(Axis axis, int index) const override; + mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; +}; + +class VerticallyLabeledCurveView : public CurveView { +public: + using CurveView::CurveView; +private: + char * label(Axis axis, int index) const override; + mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; +}; + +class LabeledCurveView : public CurveView { +public: + using CurveView::CurveView; +private: + char * label(Axis axis, int index) const override; + mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; + mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; +}; + +} + +#endif diff --git a/apps/statistics/box_axis_view.cpp b/apps/statistics/box_axis_view.cpp index 61ecfd092..3d898c738 100644 --- a/apps/statistics/box_axis_view.cpp +++ b/apps/statistics/box_axis_view.cpp @@ -12,8 +12,4 @@ void BoxAxisView::drawRect(KDContext * ctx, KDRect rect) const { drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, false, true, k_axisMargin); } -char * BoxAxisView::label(Axis axis, int index) const { - return axis == Axis::Vertical ? nullptr : (char *)m_labels[index]; -} - } diff --git a/apps/statistics/box_axis_view.h b/apps/statistics/box_axis_view.h index 2fbfe0df8..b3caef60d 100644 --- a/apps/statistics/box_axis_view.h +++ b/apps/statistics/box_axis_view.h @@ -3,24 +3,21 @@ #include "box_range.h" #include "store.h" -#include "../shared/curve_view.h" +#include "../shared/labeled_curve_view.h" #include "../constant.h" #include namespace Statistics { -class BoxAxisView : public Shared::CurveView { +class BoxAxisView : public Shared::HorizontallyLabeledCurveView { public: BoxAxisView(Store * store) : - CurveView(&m_boxRange), - m_labels{}, + HorizontallyLabeledCurveView(&m_boxRange), m_boxRange(BoxRange(store)) {} void drawRect(KDContext * ctx, KDRect rect) const override; private: constexpr static KDCoordinate k_axisMargin = 3; - char * label(Axis axis, int index) const override; - char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; BoxRange m_boxRange; }; diff --git a/apps/statistics/box_view.h b/apps/statistics/box_view.h index 6ce1a9275..b95cbbc29 100644 --- a/apps/statistics/box_view.h +++ b/apps/statistics/box_view.h @@ -37,7 +37,6 @@ private: static constexpr KDCoordinate k_quantileBarWidth = 2; KDCoordinate boxLowerBoundPixel() const; KDCoordinate boxUpperBoundPixel() const; - char * label(Axis axis, int index) const override { return nullptr; } Store * m_store; BoxRange m_boxRange; int m_series; diff --git a/apps/statistics/histogram_view.cpp b/apps/statistics/histogram_view.cpp index 5f0caa14d..9b1d028f4 100644 --- a/apps/statistics/histogram_view.cpp +++ b/apps/statistics/histogram_view.cpp @@ -8,10 +8,9 @@ using namespace Shared; namespace Statistics { HistogramView::HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor, KDColor notSelectedHistogramColor, KDColor selectedBarColor) : - CurveView(store, nullptr, bannerView, nullptr), + HorizontallyLabeledCurveView(store, nullptr, bannerView, nullptr), m_controller(controller), m_store(store), - m_labels{}, m_highlightedBarStart(NAN), m_highlightedBarEnd(NAN), m_series(series), @@ -63,10 +62,6 @@ void HistogramView::setHighlight(float start, float end) { } } -char * HistogramView::label(Axis axis, int index) const { - return axis == Axis::Vertical ? nullptr : (char *)m_labels[index]; -} - float HistogramView::EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context) { Store * store = (Store *)model; float totalSize = ((float *)context)[0]; diff --git a/apps/statistics/histogram_view.h b/apps/statistics/histogram_view.h index 32117ffde..c6859097c 100644 --- a/apps/statistics/histogram_view.h +++ b/apps/statistics/histogram_view.h @@ -5,13 +5,13 @@ #include #include "store.h" #include "../constant.h" -#include "../shared/curve_view.h" +#include "../shared/labeled_curve_view.h" namespace Statistics { class HistogramController; -class HistogramView : public Shared::CurveView { +class HistogramView : public Shared::HorizontallyLabeledCurveView { public: HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor = Palette::Select, KDColor notSelectedHistogramColor = Palette::GreyMiddle, KDColor selectedBarColor = Palette::YellowDark); int series() const { return m_series; } @@ -21,7 +21,6 @@ public: void setHighlight(float start, float end); void setDisplayLabels(bool display) { m_displayLabels = display; } private: - char * label(Axis axis, int index) const override; HistogramController * m_controller; Store * m_store; char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; From aab89749349a74a0e066972db93f3fe1b3599586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 4 Mar 2020 13:23:29 +0100 Subject: [PATCH 083/117] [apps] Memoize five model checksums --- apps/graph/app.cpp | 2 +- apps/graph/graph/graph_controller.cpp | 4 ++-- apps/graph/graph/graph_controller.h | 2 +- apps/regression/app.cpp | 4 +++- apps/regression/app.h | 3 +++ apps/regression/graph_controller.cpp | 4 ++-- apps/regression/graph_controller.h | 2 +- apps/sequence/app.cpp | 2 +- apps/sequence/graph/graph_controller.cpp | 4 ++-- apps/sequence/graph/graph_controller.h | 2 +- apps/shared/function_app.cpp | 2 ++ apps/shared/function_app.h | 3 +++ apps/shared/function_graph_controller.cpp | 4 ++-- apps/shared/function_graph_controller.h | 2 +- apps/shared/interactive_curve_view_controller.cpp | 3 ++- apps/shared/interactive_curve_view_controller.h | 3 ++- 16 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp index 510b133f5..227aa1c0e 100644 --- a/apps/graph/app.cpp +++ b/apps/graph/app.cpp @@ -54,7 +54,7 @@ App::App(Snapshot * snapshot) : m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController), m_listStackViewController(&m_tabViewController, &m_listHeader), - m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp index 9f45f3eff..74cc400dc 100644 --- a/apps/graph/graph/graph_controller.cpp +++ b/apps/graph/graph/graph_controller.cpp @@ -11,8 +11,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; } static inline double minDouble(double x, double y) { return x < y ? x : y; } static inline double maxDouble(double x, double y) { return x > y ? x : y; } -GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : - FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), +GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : + FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion), m_bannerView(this, inputEventHandlerDelegate, this), m_view(curveViewRange, m_cursor, &m_bannerView, &m_cursorView), m_graphRange(curveViewRange), diff --git a/apps/graph/graph/graph_controller.h b/apps/graph/graph/graph_controller.h index 8860dd245..84240fcd3 100644 --- a/apps/graph/graph/graph_controller.h +++ b/apps/graph/graph/graph_controller.h @@ -15,7 +15,7 @@ namespace Graph { class GraphController : public Shared::FunctionGraphController, public GraphControllerHelper { public: - GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); + GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); I18n::Message emptyMessage() override; void viewWillAppear() override; bool displayDerivativeInBanner() const { return m_displayDerivativeInBanner; } diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index 26058d22b..bfe05df33 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -27,6 +27,7 @@ App::Snapshot::Snapshot() : m_rangeVersion(0), m_selectedSeriesIndex(-1) { + assert(m_previousModelsVersions[0] == 0); } App * App::Snapshot::unpack(Container * container) { @@ -36,6 +37,7 @@ App * App::Snapshot::unpack(Container * container) { void App::Snapshot::reset() { m_store.deleteAllPairs(); m_modelVersion = 0; + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); m_rangeVersion = 0; setActiveTab(0); } @@ -55,7 +57,7 @@ App::App(Snapshot * snapshot, Poincare::Context * parentContext) : m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, snapshot->store()), m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController), m_calculationHeader(&m_tabViewController, &m_calculationAlternateEmptyViewController, &m_calculationController), - m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()), + m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), diff --git a/apps/regression/app.h b/apps/regression/app.h index 698479abb..460e63f3a 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -21,6 +21,7 @@ public: }; class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: + static constexpr size_t sNumberOfMemoizedModelVersions = 5; // TODO LEA factorize with Shared::FunctionApp Snapshot(); App * unpack(Container * container) override; void reset() override; @@ -30,6 +31,7 @@ public: int * graphSelectedDotIndex() { return &m_graphSelectedDotIndex; } int * selectedSeriesIndex() { return &m_selectedSeriesIndex; } uint32_t * modelVersion() { return &m_modelVersion; } + uint32_t * previousModelsVersions() { return m_previousModelsVersions; } uint32_t * rangeVersion() { return &m_rangeVersion; } private: void tidy() override; @@ -37,6 +39,7 @@ public: Shared::CurveViewCursor m_cursor; int m_graphSelectedDotIndex; uint32_t m_modelVersion; + uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; int m_selectedSeriesIndex; }; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index b59809bca..973c90734 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -14,8 +14,8 @@ static inline int maxInt(int x, int y) { return x > y ? x : y; } namespace Regression { -GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) : - InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, rangeVersion), +GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) : + InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, previousModelsVersions, rangeVersion), m_crossCursorView(), m_roundCursorView(), m_bannerView(this, inputEventHandlerDelegate, this), diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index f1c257a12..6926854c5 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -16,7 +16,7 @@ namespace Regression { class GraphController : public Shared::InteractiveCurveViewController { public: - GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); + GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); ViewController * initialisationParameterController() override; bool isEmpty() const override; I18n::Message emptyMessage() override; diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index 40b27f0fb..505f0c9fe 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -51,7 +51,7 @@ App::App(Snapshot * snapshot) : m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(nullptr, &m_listFooter, &m_listController), m_listStackViewController(&m_tabViewController, &m_listHeader), - m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), diff --git a/apps/sequence/graph/graph_controller.cpp b/apps/sequence/graph/graph_controller.cpp index c2c4b8fea..8e14c64c8 100644 --- a/apps/sequence/graph/graph_controller.cpp +++ b/apps/sequence/graph/graph_controller.cpp @@ -11,8 +11,8 @@ namespace Sequence { static inline int minInt(int x, int y) { return (x < y ? x : y); } static inline int maxInt(int x, int y) { return (x > y ? x : y); } -GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : - FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), +GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : + FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion), m_bannerView(this, inputEventHandlerDelegate, this), m_view(sequenceStore, graphRange, m_cursor, &m_bannerView, &m_cursorView), m_graphRange(graphRange), diff --git a/apps/sequence/graph/graph_controller.h b/apps/sequence/graph/graph_controller.h index da0e64006..2177bc230 100644 --- a/apps/sequence/graph/graph_controller.h +++ b/apps/sequence/graph/graph_controller.h @@ -14,7 +14,7 @@ namespace Sequence { class GraphController final : public Shared::FunctionGraphController { public: - GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); + GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); I18n::Message emptyMessage() override; void viewWillAppear() override; TermSumController * termSumController() { return &m_termSumController; } diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 7cede0ee8..3861d0b3e 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -11,11 +11,13 @@ FunctionApp::Snapshot::Snapshot() : m_rangeVersion(0), m_angleUnitVersion(Preferences::AngleUnit::Radian) { + assert(m_previousModelsVersions[0] == 0); } void FunctionApp::Snapshot::reset() { m_indexFunctionSelectedByCursor = 0; m_modelVersion = 0; + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index ffec00c31..9fc842d8d 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -12,9 +12,11 @@ class FunctionApp : public ExpressionFieldDelegateApp { public: class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: + static constexpr size_t sNumberOfMemoizedModelVersions = 5; Snapshot(); CurveViewCursor * cursor() { return &m_cursor; } uint32_t * modelVersion() { return &m_modelVersion; } + uint32_t * previousModelsVersions() { return m_previousModelsVersions; } uint32_t * rangeVersion() { return &m_rangeVersion; } Poincare::Preferences::AngleUnit * angleUnitVersion() { return &m_angleUnitVersion; } virtual FunctionStore * functionStore() = 0; @@ -26,6 +28,7 @@ public: private: int m_indexFunctionSelectedByCursor; uint32_t m_modelVersion; + uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; Poincare::Preferences::AngleUnit m_angleUnitVersion; }; diff --git a/apps/shared/function_graph_controller.cpp b/apps/shared/function_graph_controller.cpp index cf70f677d..0f2b57d7f 100644 --- a/apps/shared/function_graph_controller.cpp +++ b/apps/shared/function_graph_controller.cpp @@ -15,8 +15,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; } static inline double minDouble(double x, double y) { return x < y ? x : y; } static inline double maxDouble(double x, double y) { return x > y ? x : y; } -FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) : - InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, rangeVersion), +FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) : + InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, previousModelsVersions, rangeVersion), m_initialisationParameterController(this, interactiveRange), m_angleUnitVersion(angleUnitVersion), m_indexFunctionSelectedByCursor(indexFunctionSelectedByCursor) diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h index e111c4234..af3d0dd61 100644 --- a/apps/shared/function_graph_controller.h +++ b/apps/shared/function_graph_controller.h @@ -13,7 +13,7 @@ namespace Shared { class FunctionGraphController : public InteractiveCurveViewController, public FunctionBannerDelegate { public: - FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion); + FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion); bool isEmpty() const override; ViewController * initialisationParameterController() override; void didBecomeFirstResponder() override; diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index f1bc67391..f0ba3448b 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -7,10 +7,11 @@ using namespace Poincare; namespace Shared { -InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion) : +InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion) : SimpleInteractiveCurveViewController(parentResponder, cursor), ButtonRowDelegate(header, nullptr), m_modelVersion(modelVersion), + m_previousModelsVersions(previousModelsVersions), m_rangeVersion(rangeVersion), m_rangeParameterController(this, inputEventHandlerDelegate, interactiveRange), m_zoomParameterController(this, interactiveRange, curveView), diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index 58a72a792..bda9f2e76 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -12,7 +12,7 @@ namespace Shared { class InteractiveCurveViewController : public SimpleInteractiveCurveViewController, public InteractiveCurveViewRangeDelegate, public ButtonRowDelegate, public AlternateEmptyViewDefaultDelegate { public: - InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion); + InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion); const char * title() override; bool handleEvent(Ion::Events::Event event) override; @@ -67,6 +67,7 @@ private: virtual bool shouldSetDefaultOnModelChange() const { return false; } uint32_t * m_modelVersion; + uint32_t * m_previousModelsVersions; uint32_t * m_rangeVersion; RangeParameterController m_rangeParameterController; ZoomParameterController m_zoomParameterController; From 53705fb33338c215af558d341854b4a8bcaf2c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 4 Mar 2020 14:41:18 +0100 Subject: [PATCH 084/117] [apps/graph_ctrlr] Reload range if no previous model is present We memoize the checksum of the x first models, and we check that one of these models is still present when the graph view appears. If so, we do not reload the range, other wise we reload it. Scenario: f(t) = [t^2 t+1] in parametric Display the graph f(x) = 1 on ]-inf;0] g(x) = 2 on [0;inf[ Display the graph -> the range did not change --- apps/regression/app.cpp | 3 +- apps/regression/app.h | 3 +- apps/regression/graph_controller.cpp | 4 +++ apps/regression/graph_controller.h | 3 ++ apps/regression/store.h | 4 +++ apps/shared/function_app.cpp | 3 +- apps/shared/function_app.h | 4 +-- apps/shared/function_graph_controller.cpp | 4 +++ apps/shared/function_graph_controller.h | 3 ++ apps/shared/function_store.cpp | 7 ++++ apps/shared/function_store.h | 1 + .../interactive_curve_view_controller.cpp | 34 ++++++++++++++++++- .../interactive_curve_view_controller.h | 4 +++ 13 files changed, 70 insertions(+), 7 deletions(-) diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index bfe05df33..de483ded2 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -37,7 +37,8 @@ App * App::Snapshot::unpack(Container * container) { void App::Snapshot::reset() { m_store.deleteAllPairs(); m_modelVersion = 0; - memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); + assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * GraphController::sNumberOfMemoizedModelVersions); + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions)); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/regression/app.h b/apps/regression/app.h index 460e63f3a..f697d4a49 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -21,7 +21,6 @@ public: }; class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: - static constexpr size_t sNumberOfMemoizedModelVersions = 5; // TODO LEA factorize with Shared::FunctionApp Snapshot(); App * unpack(Container * container) override; void reset() override; @@ -39,7 +38,7 @@ public: Shared::CurveViewCursor m_cursor; int m_graphSelectedDotIndex; uint32_t m_modelVersion; - uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; + uint32_t m_previousModelsVersions[GraphController::sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; int m_selectedSeriesIndex; }; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 973c90734..afa38abfe 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -351,6 +351,10 @@ uint32_t GraphController::modelVersion() { return m_store->storeChecksum(); } +uint32_t GraphController::modelVersionAtIndex(size_t i) { + return m_store->seriesChecksumAtIndex(i); +} + uint32_t GraphController::rangeVersion() { return m_store->rangeChecksum(); } diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 6926854c5..6d434f500 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -16,6 +16,7 @@ namespace Regression { class GraphController : public Shared::InteractiveCurveViewController { public: + static constexpr size_t sNumberOfMemoizedModelVersions = Store::k_numberOfSeries; GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); ViewController * initialisationParameterController() override; bool isEmpty() const override; @@ -43,7 +44,9 @@ private: // InteractiveCurveViewController void initCursorParameters() override; uint32_t modelVersion() override; + uint32_t modelVersionAtIndex(size_t i) override; uint32_t rangeVersion() override; + size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; } int selectedCurveIndex() const override { return *m_selectedSeriesIndex; } bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override; Poincare::Coordinate2D xyValues(int curveIndex, double x, Poincare::Context * context) const override; diff --git a/apps/regression/store.h b/apps/regression/store.h index dfdc682c1..757ed2b95 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -35,6 +35,10 @@ public: assert((int)m_regressionTypes[series] >= 0 && (int)m_regressionTypes[series] < Model::k_numberOfModels); return regressionModel((int)m_regressionTypes[series]); } + uint32_t seriesChecksumAtIndex(size_t i) { + assert(i < k_numberOfSeries); + return m_seriesChecksum[i]; + } // Dots /* Return the closest dot to abscissa x above the regression curve if diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 3861d0b3e..0b7a95454 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -17,7 +17,8 @@ FunctionApp::Snapshot::Snapshot() : void FunctionApp::Snapshot::reset() { m_indexFunctionSelectedByCursor = 0; m_modelVersion = 0; - memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); + assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * FunctionGraphController::sNumberOfMemoizedModelVersions); + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions)); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index 9fc842d8d..d15e4c5e8 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -2,6 +2,7 @@ #define SHARED_FUNCTION_APP_H #include "expression_field_delegate_app.h" +#include "function_graph_controller.h" #include "function_store.h" #include "curve_view_cursor.h" #include "values_controller.h" @@ -12,7 +13,6 @@ class FunctionApp : public ExpressionFieldDelegateApp { public: class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: - static constexpr size_t sNumberOfMemoizedModelVersions = 5; Snapshot(); CurveViewCursor * cursor() { return &m_cursor; } uint32_t * modelVersion() { return &m_modelVersion; } @@ -28,7 +28,7 @@ public: private: int m_indexFunctionSelectedByCursor; uint32_t m_modelVersion; - uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; + uint32_t m_previousModelsVersions[FunctionGraphController::sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; Poincare::Preferences::AngleUnit m_angleUnitVersion; }; diff --git a/apps/shared/function_graph_controller.cpp b/apps/shared/function_graph_controller.cpp index 0f2b57d7f..f851f65ef 100644 --- a/apps/shared/function_graph_controller.cpp +++ b/apps/shared/function_graph_controller.cpp @@ -183,6 +183,10 @@ uint32_t FunctionGraphController::modelVersion() { return functionStore()->storeChecksum(); } +uint32_t FunctionGraphController::modelVersionAtIndex(size_t i) { + return functionStore()->storeChecksumAtIndex(i); +} + uint32_t FunctionGraphController::rangeVersion() { return interactiveCurveViewRange()->rangeChecksum(); } diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h index af3d0dd61..fcb15ae57 100644 --- a/apps/shared/function_graph_controller.h +++ b/apps/shared/function_graph_controller.h @@ -13,6 +13,7 @@ namespace Shared { class FunctionGraphController : public InteractiveCurveViewController, public FunctionBannerDelegate { public: + static constexpr size_t sNumberOfMemoizedModelVersions = 5; FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion); bool isEmpty() const override; ViewController * initialisationParameterController() override; @@ -49,7 +50,9 @@ private: // InteractiveCurveViewController bool moveCursorVertically(int direction) override; uint32_t modelVersion() override; + uint32_t modelVersionAtIndex(size_t i) override; uint32_t rangeVersion() override; + size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; } InitialisationParameterController m_initialisationParameterController; Poincare::Preferences::AngleUnit * m_angleUnitVersion; diff --git a/apps/shared/function_store.cpp b/apps/shared/function_store.cpp index 77ed25132..7a05715a2 100644 --- a/apps/shared/function_store.cpp +++ b/apps/shared/function_store.cpp @@ -6,4 +6,11 @@ uint32_t FunctionStore::storeChecksum() { return Ion::Storage::sharedStorage()->checksum(); } +uint32_t FunctionStore::storeChecksumAtIndex(size_t i) { + if (numberOfActiveFunctions() <= i) { + return 0; + } + return activeRecordAtIndex(i).checksum(); +} + } diff --git a/apps/shared/function_store.h b/apps/shared/function_store.h index 2790f6703..03e57ef58 100644 --- a/apps/shared/function_store.h +++ b/apps/shared/function_store.h @@ -13,6 +13,7 @@ class FunctionStore : public ExpressionModelStore { public: FunctionStore() : ExpressionModelStore() {} uint32_t storeChecksum(); + uint32_t storeChecksumAtIndex(size_t i); int numberOfActiveFunctions() const { return numberOfModelsSatisfyingTest(&isFunctionActive, nullptr); } diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index f0ba3448b..997149852 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -133,11 +133,43 @@ Responder * InteractiveCurveViewController::defaultController() { return tabController(); } +bool InteractiveCurveViewController::previousModelsWereAllDeleted() { + bool result = true; + const int modelsCount = numberOfCurves(); + const int memoizationCount = numberOfMemoizedVersions(); + + // Look for a current model that is the same as in the previous version + for (int i = 0; i < modelsCount; i++) { + uint32_t currentVersion = modelVersionAtIndex(i); + for (int j = 0; j < memoizationCount; j++) { + uint32_t * previousVersion = m_previousModelsVersions + j; + if (currentVersion == *previousVersion) { + result = false; + break; + } + } + if (!result) { + break; + } + } + + // Update the memoization + for (int i = 0; i < memoizationCount; i++) { + uint32_t * previousVersion = m_previousModelsVersions + i; + uint32_t newVersion = modelVersionAtIndex(i); + if (*previousVersion != newVersion) { + *previousVersion = newVersion; + } + } + return result; +} + void InteractiveCurveViewController::viewWillAppear() { SimpleInteractiveCurveViewController::viewWillAppear(); uint32_t newModelVersion = modelVersion(); if (*m_modelVersion != newModelVersion) { - if (*m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) { + // Put previousModelsWereAllDeleted first to update the model versions + if (previousModelsWereAllDeleted() || *m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) { interactiveCurveViewRange()->setDefault(); } *m_modelVersion = newModelVersion; diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index bda9f2e76..9ef048f18 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -28,6 +28,8 @@ public: Responder * defaultController() override; + bool previousModelsWereAllDeleted(); + void viewWillAppear() override; void viewDidDisappear() override; void willExitResponderChain(Responder * nextFirstResponder) override; @@ -39,6 +41,7 @@ protected: virtual void initCursorParameters() = 0; virtual bool moveCursorVertically(int direction) = 0; virtual uint32_t modelVersion() = 0; + virtual uint32_t modelVersionAtIndex(size_t i) = 0; virtual uint32_t rangeVersion() = 0; bool isCursorVisible(); @@ -66,6 +69,7 @@ private: float addMargin(float x, float range, bool isVertical, bool isMin) override; virtual bool shouldSetDefaultOnModelChange() const { return false; } + virtual size_t numberOfMemoizedVersions() const = 0; uint32_t * m_modelVersion; uint32_t * m_previousModelsVersions; uint32_t * m_rangeVersion; From 702772a7c96301a1a0d6a06d7a3bc58c0943ee1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Mar 2020 15:13:22 +0100 Subject: [PATCH 085/117] [apps/reg] Store::m_seriesChecksum is Snapshot::m_prevModelsVersions Share these objects instead of duplicating them --- apps/regression/app.cpp | 5 +---- apps/regression/app.h | 3 +-- apps/regression/graph_controller.cpp | 3 ++- apps/regression/graph_controller.h | 3 +-- apps/regression/store.cpp | 18 +++++++++++++----- apps/regression/store.h | 7 +++---- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index de483ded2..9331fdefc 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -27,7 +27,6 @@ App::Snapshot::Snapshot() : m_rangeVersion(0), m_selectedSeriesIndex(-1) { - assert(m_previousModelsVersions[0] == 0); } App * App::Snapshot::unpack(Container * container) { @@ -35,10 +34,8 @@ App * App::Snapshot::unpack(Container * container) { } void App::Snapshot::reset() { - m_store.deleteAllPairs(); + m_store.reset(); m_modelVersion = 0; - assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * GraphController::sNumberOfMemoizedModelVersions); - memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions)); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/regression/app.h b/apps/regression/app.h index f697d4a49..2c529af77 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -30,7 +30,7 @@ public: int * graphSelectedDotIndex() { return &m_graphSelectedDotIndex; } int * selectedSeriesIndex() { return &m_selectedSeriesIndex; } uint32_t * modelVersion() { return &m_modelVersion; } - uint32_t * previousModelsVersions() { return m_previousModelsVersions; } + uint32_t * previousModelsVersions() { return m_store.seriesChecksum(); } uint32_t * rangeVersion() { return &m_rangeVersion; } private: void tidy() override; @@ -38,7 +38,6 @@ public: Shared::CurveViewCursor m_cursor; int m_graphSelectedDotIndex; uint32_t m_modelVersion; - uint32_t m_previousModelsVersions[GraphController::sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; int m_selectedSeriesIndex; }; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index afa38abfe..b6b54aaf1 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -352,7 +352,8 @@ uint32_t GraphController::modelVersion() { } uint32_t GraphController::modelVersionAtIndex(size_t i) { - return m_store->seriesChecksumAtIndex(i); + assert(i < numberOfMemoizedVersions()); + return *(m_store->seriesChecksum() + i); } uint32_t GraphController::rangeVersion() { diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 6d434f500..30e722552 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -16,7 +16,6 @@ namespace Regression { class GraphController : public Shared::InteractiveCurveViewController { public: - static constexpr size_t sNumberOfMemoizedModelVersions = Store::k_numberOfSeries; GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); ViewController * initialisationParameterController() override; bool isEmpty() const override; @@ -46,7 +45,7 @@ private: uint32_t modelVersion() override; uint32_t modelVersionAtIndex(size_t i) override; uint32_t rangeVersion() override; - size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; } + size_t numberOfMemoizedVersions() const override { return Store::k_numberOfSeries; } int selectedCurveIndex() const override { return *m_selectedSeriesIndex; } bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override; Poincare::Coordinate2D xyValues(int curveIndex, double x, Poincare::Context * context) const override; diff --git a/apps/regression/store.cpp b/apps/regression/store.cpp index 0afd7941a..98f703bd5 100644 --- a/apps/regression/store.cpp +++ b/apps/regression/store.cpp @@ -19,13 +19,14 @@ static_assert(Store::k_numberOfSeries == 3, "Number of series changed, Regressio Store::Store() : InteractiveCurveViewRange(), DoublePairStore(), - m_seriesChecksum{0, 0, 0}, m_angleUnit(Poincare::Preferences::AngleUnit::Degree) { - for (int i = 0; i < k_numberOfSeries; i++) { - m_regressionTypes[i] = Model::Type::Linear; - m_regressionChanged[i] = false; - } + resetMemoization(); +} + +void Store::reset() { + deleteAllPairs(); + resetMemoization(); } void Store::tidy() { @@ -188,6 +189,13 @@ double Store::doubleCastedNumberOfPairsOfSeries(int series) const { return DoublePairStore::numberOfPairsOfSeries(series); } +void Store::resetMemoization() { + assert(((int)Model::Type::Linear) == 0); + memset(m_seriesChecksum, 0, sizeof(m_seriesChecksum)); + memset(m_regressionTypes, 0, sizeof(m_regressionTypes)); + memset(m_regressionChanged, 0, sizeof(m_regressionChanged)); +} + float Store::maxValueOfColumn(int series, int i) const { float maxColumn = -FLT_MAX; for (int k = 0; k < numberOfPairsOfSeries(series); k++) { diff --git a/apps/regression/store.h b/apps/regression/store.h index 757ed2b95..2cc6f600f 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -22,6 +22,7 @@ class Store : public Shared::InteractiveCurveViewRange, public Shared::DoublePai public: Store(); + void reset(); // Clean pool void tidy(); @@ -35,10 +36,7 @@ public: assert((int)m_regressionTypes[series] >= 0 && (int)m_regressionTypes[series] < Model::k_numberOfModels); return regressionModel((int)m_regressionTypes[series]); } - uint32_t seriesChecksumAtIndex(size_t i) { - assert(i < k_numberOfSeries); - return m_seriesChecksum[i]; - } + uint32_t * seriesChecksum() { return m_seriesChecksum; } // Dots /* Return the closest dot to abscissa x above the regression curve if @@ -74,6 +72,7 @@ public: double squaredCorrelationCoefficient(int series) const; private: constexpr static float k_displayHorizontalMarginRatio = 0.05f; + void resetMemoization(); float maxValueOfColumn(int series, int i) const; //TODO LEA why float ? float minValueOfColumn(int series, int i) const; //TODO LEA why float ? Model * regressionModel(int index); From 8168a125e6739772ef9aaf89d5b41701e116f9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Mar 2020 12:01:45 +0100 Subject: [PATCH 086/117] [apps/statistics] Remove unused variable in HistogramView It is unused as HistogramView now inherits Shared::HorizontallyLabeledCurveView --- apps/statistics/histogram_view.h | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/statistics/histogram_view.h b/apps/statistics/histogram_view.h index c6859097c..f72cbac1a 100644 --- a/apps/statistics/histogram_view.h +++ b/apps/statistics/histogram_view.h @@ -23,7 +23,6 @@ public: private: HistogramController * m_controller; Store * m_store; - char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; static float EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context); float m_highlightedBarStart; float m_highlightedBarEnd; From a7d419c4bd7e0a1d8c5eceed23e023ae339d8712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 11 Feb 2020 10:49:49 +0100 Subject: [PATCH 087/117] [ion/emscripten] Get physical keyboard events in scan() --- ion/src/simulator/shared/keyboard_sdl.cpp | 43 +++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 4940c2c98..4d3b1a928 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -22,6 +22,36 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { namespace Ion { namespace Keyboard { +#if EPSILON_SDL_SCREEN_ONLY + class KeySDLKeyPair { + public: + constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : + m_key(key), + m_SDLKey(SDLKey) + {} + Ion::Keyboard::Key key() const { return m_key; } + SDL_Scancode SDLKey() const { return m_SDLKey; } + private: + Ion::Keyboard::Key m_key; + SDL_Scancode m_SDLKey; + }; + + constexpr static KeySDLKeyPair sKeyPairs[] = { + KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), + KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), + KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), + KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), + KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), + KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), + KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) + }; + + constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +#endif + State scan() { // We need to tell SDL to get new state from the host OS SDL_PumpEvents(); @@ -33,8 +63,17 @@ State scan() { Simulator::Main::refresh(); #if EPSILON_SDL_SCREEN_ONLY - // In this case, keyboard states will be sent over another channel - return sKeyboardState; + /* In this case, keyboard states will be sent over another channel, but we + * still need to catch the physical keyboard events */ + const uint8_t * SDLstate = SDL_GetKeyboardState(NULL); + State state = sKeyboardState; + for (int i = 0; i < sNumberOfKeyPairs; i++) { + KeySDLKeyPair pair = sKeyPairs[i]; + if (SDLstate[pair.SDLKey()]) { + state.setKey(pair.key()); + } + } + return state; #else // Start with a "clean" state State state; From 18f3054b50923b38067568f4b42e97dc33731ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 20 Feb 2020 14:41:40 +0100 Subject: [PATCH 088/117] [ion/simulator/web] Do not duplicate events in scan and getPlatformEvent Some events were caught by bith scan() and getPlatformEvent() --- ion/src/simulator/shared/events_keyboard.cpp | 5 ++ ion/src/simulator/shared/keyboard_sdl.cpp | 67 ++++++++++++-------- ion/src/simulator/shared/platform.h | 2 + 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 02bd8b4a1..2a581a574 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -204,6 +204,11 @@ Event getPlatformEvent() { return Termination; } if (event.type == SDL_KEYDOWN) { +#if EPSILON_SDL_SCREEN_ONLY + if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { + continue; + } +#endif return eventFromSDLKeyboardEvent(event.key); } if (event.type == SDL_TEXTINPUT) { diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 4d3b1a928..589d21a49 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -17,41 +17,54 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { Ion::Keyboard::Key key = static_cast(keyNumber); sKeyboardState.clearKey(key); } -#endif namespace Ion { namespace Keyboard { -#if EPSILON_SDL_SCREEN_ONLY - class KeySDLKeyPair { - public: - constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : - m_key(key), - m_SDLKey(SDLKey) - {} - Ion::Keyboard::Key key() const { return m_key; } - SDL_Scancode SDLKey() const { return m_SDLKey; } - private: - Ion::Keyboard::Key m_key; - SDL_Scancode m_SDLKey; - }; +class KeySDLKeyPair { +public: + constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : + m_key(key), + m_SDLKey(SDLKey) + {} + Ion::Keyboard::Key key() const { return m_key; } + SDL_Scancode SDLKey() const { return m_SDLKey; } +private: + Ion::Keyboard::Key m_key; + SDL_Scancode m_SDLKey; +}; - constexpr static KeySDLKeyPair sKeyPairs[] = { - KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), - KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), - KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), - KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), - KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), - KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), - KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), - KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), - KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), - KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) - }; +constexpr static KeySDLKeyPair sKeyPairs[] = { + KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), + KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), + KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), + KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), + KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), + KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), + KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) +}; - constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); + +} +} + +bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key) { + for (int i = 0; i < Ion::Keyboard::sNumberOfKeyPairs; i++) { + if (key == Ion::Keyboard::sKeyPairs[i].SDLKey()) { + return true; + } + } + return false; +} #endif +namespace Ion { +namespace Keyboard { + State scan() { // We need to tell SDL to get new state from the host OS SDL_PumpEvents(); diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index 0dcb4e74c..c6e27bbee 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -20,6 +20,8 @@ void IonSimulatorKeyboardKeyUp(int keyNumber); void IonSimulatorEventsPushEvent(int eventNumber); +bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); + #endif void IonSimulatorCallbackDidRefresh(); From 4a4ba52e385f7b645b978d5c18aef669cb9746e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 24 Feb 2020 11:41:18 +0100 Subject: [PATCH 089/117] [ion/events] Better handling of Shift on the web target --- ion/include/ion/events.h | 1 + ion/src/shared/events_modifier.cpp | 10 ++++++++++ ion/src/simulator/shared/events_keyboard.cpp | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index bba153a96..058bdfcbc 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -53,6 +53,7 @@ Event getEvent(int * timeout); ShiftAlphaStatus shiftAlphaStatus(); void setShiftAlphaStatus(ShiftAlphaStatus s); +void removeShift(); bool isShiftActive(); bool isAlphaActive(); void setLongRepetition(bool longRepetition); diff --git a/ion/src/shared/events_modifier.cpp b/ion/src/shared/events_modifier.cpp index 90fa01a97..f2bc8b61f 100644 --- a/ion/src/shared/events_modifier.cpp +++ b/ion/src/shared/events_modifier.cpp @@ -11,6 +11,16 @@ ShiftAlphaStatus shiftAlphaStatus() { return sShiftAlphaStatus; } +void removeShift() { + if (sShiftAlphaStatus == ShiftAlphaStatus::Shift) { + sShiftAlphaStatus = ShiftAlphaStatus::Default; + } else if (sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlpha ) { + sShiftAlphaStatus = ShiftAlphaStatus::Alpha; + } else if (sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlphaLock) { + sShiftAlphaStatus = ShiftAlphaStatus::AlphaLock; + } +} + bool isShiftActive() { return sShiftAlphaStatus == ShiftAlphaStatus::Shift || sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlpha || sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlphaLock; } diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 2a581a574..0ba9dff6a 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -64,6 +64,12 @@ namespace Ion { namespace Events { static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { + /* If an event is detected, we want to remove the Shift modifier to mimic the + * device behaviour. If no event was detected, we restore the previous + * ShiftAlphaStatus. */ + Ion::Events::ShiftAlphaStatus previousShiftAlphaStatus = Ion::Events::shiftAlphaStatus(); + Ion::Events::removeShift(); + if (event.keysym.mod & KMOD_CTRL) { switch (event.keysym.sym) { case SDLK_BACKSPACE: @@ -156,6 +162,8 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { case SDLK_AC_BACK: return Termination; } + // No event was detected, restore the previous ShiftAlphaStatus. + Ion::Events::setShiftAlphaStatus(previousShiftAlphaStatus); return None; } @@ -180,6 +188,14 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { } char character = event.text[0]; if (character >= 32 && character < 127) { +#if EPSILON_SDL_SCREEN_ONLY + /* We remove the shift, otherwise it might stay activated when it shouldn't. + * For instance on a French keyboard, to input "1", we first press "Shift" + * (which activates the Shift modifier on the calculator), then we press + * "&", transformed by eventFromSDLTextInputEvent into the text "1". If we + * do not remove the Shift here, it would still be pressed afterwards. */ + Ion::Events::removeShift(); +#endif return sEventForASCIICharAbove32[character-32]; } return None; From 124225899294723040ff0b4dc2805c6ff8902c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 25 Feb 2020 11:21:59 +0100 Subject: [PATCH 090/117] [ion] Handle key events in all simulators as in EPSILON_SDL_SCREEN_ONLY This way, physical keyboard events can be caught by python on all simulators --- ion/src/simulator/shared/events_keyboard.cpp | 4 - ion/src/simulator/shared/keyboard_sdl.cpp | 82 +++++++++----------- ion/src/simulator/shared/platform.h | 7 +- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 0ba9dff6a..81638970d 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -188,14 +188,12 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { } char character = event.text[0]; if (character >= 32 && character < 127) { -#if EPSILON_SDL_SCREEN_ONLY /* We remove the shift, otherwise it might stay activated when it shouldn't. * For instance on a French keyboard, to input "1", we first press "Shift" * (which activates the Shift modifier on the calculator), then we press * "&", transformed by eventFromSDLTextInputEvent into the text "1". If we * do not remove the Shift here, it would still be pressed afterwards. */ Ion::Events::removeShift(); -#endif return sEventForASCIICharAbove32[character-32]; } return None; @@ -220,11 +218,9 @@ Event getPlatformEvent() { return Termination; } if (event.type == SDL_KEYDOWN) { -#if EPSILON_SDL_SCREEN_ONLY if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { continue; } -#endif return eventFromSDLKeyboardEvent(event.key); } if (event.type == SDL_TEXTINPUT) { diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 589d21a49..a1b173719 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -17,6 +17,7 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { Ion::Keyboard::Key key = static_cast(keyNumber); sKeyboardState.clearKey(key); } +#endif namespace Ion { namespace Keyboard { @@ -49,6 +50,42 @@ constexpr static KeySDLKeyPair sKeyPairs[] = { constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +State scan() { + // We need to tell SDL to get new state from the host OS + SDL_PumpEvents(); + + // Notify callbacks in case we need to do something + IonSimulatorCallbackDidScanKeyboard(); + + // Grab this opportunity to refresh the display if needed + Simulator::Main::refresh(); + + // Start with a "clean" state + State state; +#if EPSILON_SDL_SCREEN_ONLY + // In this case, keyboard states are sent over another channel. + state = sKeyboardState; +#else + // Register a key for the mouse, if any + SDL_Point p; + Uint32 mouseState = SDL_GetMouseState(&p.x, &p.y); + if (mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) { + Key k = Simulator::Layout::keyAt(&p); + state.setKey(k); + } +#endif + + // Catch the physical keyboard events + const uint8_t * SDLstate = SDL_GetKeyboardState(NULL); + for (int i = 0; i < sNumberOfKeyPairs; i++) { + KeySDLKeyPair pair = sKeyPairs[i]; + if (SDLstate[pair.SDLKey()]) { + state.setKey(pair.key()); + } + } + return state; +} + } } @@ -60,48 +97,3 @@ bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key) { } return false; } -#endif - -namespace Ion { -namespace Keyboard { - -State scan() { - // We need to tell SDL to get new state from the host OS - SDL_PumpEvents(); - - // Notify callbacks in case we need to do something - IonSimulatorCallbackDidScanKeyboard(); - - // Grab this opportunity to refresh the display if needed - Simulator::Main::refresh(); - -#if EPSILON_SDL_SCREEN_ONLY - /* In this case, keyboard states will be sent over another channel, but we - * still need to catch the physical keyboard events */ - const uint8_t * SDLstate = SDL_GetKeyboardState(NULL); - State state = sKeyboardState; - for (int i = 0; i < sNumberOfKeyPairs; i++) { - KeySDLKeyPair pair = sKeyPairs[i]; - if (SDLstate[pair.SDLKey()]) { - state.setKey(pair.key()); - } - } - return state; -#else - // Start with a "clean" state - State state; - - // Register a key for the mouse, if any - SDL_Point p; - Uint32 mouseState = SDL_GetMouseState(&p.x, &p.y); - if (mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) { - Key k = Simulator::Layout::keyAt(&p); - state.setKey(k); - } - - return state; -#endif -} - -} -} diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index c6e27bbee..494c83c23 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -2,6 +2,7 @@ #define ION_SIMULATOR_PLATFORM_H #include +#include #ifdef __cplusplus extern "C" { @@ -14,16 +15,12 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi char * IonSimulatorGetLanguageCode(); #if EPSILON_SDL_SCREEN_ONLY - void IonSimulatorKeyboardKeyDown(int keyNumber); void IonSimulatorKeyboardKeyUp(int keyNumber); - void IonSimulatorEventsPushEvent(int eventNumber); - -bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); - #endif +bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); void IonSimulatorCallbackDidRefresh(); void IonSimulatorCallbackDidScanKeyboard(); From 9ab3558cfee43e1bc374169420a3f65b147eb884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 25 Feb 2020 15:03:45 +0100 Subject: [PATCH 091/117] [ion/events_keyboard] Remove unused cases --- ion/src/simulator/shared/events_keyboard.cpp | 36 -------------------- 1 file changed, 36 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 81638970d..913fd79e9 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -72,8 +72,6 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { if (event.keysym.mod & KMOD_CTRL) { switch (event.keysym.sym) { - case SDLK_BACKSPACE: - return Clear; case SDLK_x: return Cut; case SDLK_c: @@ -94,14 +92,8 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { } } switch (event.keysym.sym) { - case SDLK_ESCAPE: - return Home; - case SDLK_RETURN: - return OK; case SDLK_v: return Var; - case SDLK_BACKSPACE: - return Clear; case SDLK_x: return Exp; case SDLK_n: @@ -130,35 +122,7 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { return Ans; } } - if (event.keysym.mod & KMOD_SHIFT) { - switch(event.keysym.sym) { - case SDLK_UP: - return ShiftUp; - case SDLK_DOWN: - return ShiftDown; - case SDLK_LEFT: - return ShiftLeft; - case SDLK_RIGHT: - return ShiftRight; - } - } switch(event.keysym.sym) { - case SDLK_UP: - return Up; - case SDLK_DOWN: - return Down; - case SDLK_LEFT: - return Left; - case SDLK_RIGHT: - return Right; - case SDLK_RETURN: - return EXE; - case SDLK_ESCAPE: - return Back; - case SDLK_TAB: - return Toolbox; - case SDLK_BACKSPACE: - return Backspace; case SDLK_AC_BACK: return Termination; } From 90f2e5beed7f0a23db50b72e6de79a7fa147d03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 27 Feb 2020 11:26:07 +0100 Subject: [PATCH 092/117] [ion/sdl] Do not process more than one buffered event Scenario: Make an infinite loop script (while 1 : 1+1) and run it. Input 1234567 then press Back to interrupt the infinite loop -> the script execution stops, then 1234567 is input in the input line, which is quite weird. It is even weirder when the key pressed during the [script execution / a long computation] result in navigation inside the calculator apps. --- ion/src/simulator/shared/events_keyboard.cpp | 25 ++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 913fd79e9..61fe0f972 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -171,6 +171,7 @@ Event getPlatformEvent() { } #endif SDL_Event event; + Event result = None; while (SDL_PollEvent(&event)) { // The while is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { @@ -179,19 +180,35 @@ Event getPlatformEvent() { } } if (event.type == SDL_QUIT) { - return Termination; + result = Termination; + break; } if (event.type == SDL_KEYDOWN) { if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { continue; } - return eventFromSDLKeyboardEvent(event.key); + result = eventFromSDLKeyboardEvent(event.key); + break; } if (event.type == SDL_TEXTINPUT) { - return eventFromSDLTextInputEvent(event.text); + result = eventFromSDLTextInputEvent(event.text); + break; } } - return None; + if (result != None) { + /* When events are not being processed - for instance when a Python script + * is being executed - SDL puts all ingoing events in a queue. + * When events processing goes back to normal, all the queued events are + * processed, which can result in weird behaviours (for instance, really + * fast navigation in the calculator, "instantanate" text input, ...). + * These behaviours are even more visible if the script contains an infinite + * loop. + * To prevent that, we flush all queued events after encountering a non-null + * event -> the first event from the queue will still be processed, but not + * the subsequent ones. */ + SDL_FlushEvents(0, UINT32_MAX); + } + return result; } } From ebdac6368192dd55d17e384c8cb394d826d8972e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Mar 2020 19:19:13 +0100 Subject: [PATCH 093/117] [poincare/parser] u_ v_ w_ are not special identifiers anymore --- poincare/src/parsing/parser.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 5329e8141..1f7d63d90 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -46,9 +46,6 @@ bool Parser::IsSpecialIdentifierName(const char * name, size_t nameLength) { Token::CompareNonNullTerminatedName(name, nameLength, Infinity::Name()) == 0 || Token::CompareNonNullTerminatedName(name, nameLength, Undefined::Name()) == 0 || Token::CompareNonNullTerminatedName(name, nameLength, Unreal::Name()) == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "u_") == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "v_") == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "w_") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "u") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "v") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "w") == 0 From 515405a5df2ca6847f0e51799b4e5c01aed08618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 25 Feb 2020 14:39:29 +0100 Subject: [PATCH 094/117] [poincare] In Power::approximation and SquareRoot::approximation, the real (or imaginary) part negligence should depend on the argument value relatively to some other values (norms of the parameters) and not of its value absolutely! --- .../include/poincare/approximation_helper.h | 2 +- poincare/src/approximation_helper.cpp | 18 ++++++++++++------ poincare/src/power.cpp | 9 +++++++-- poincare/src/square_root.cpp | 8 ++++++-- poincare/test/approximation.cpp | 4 ++++ 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/poincare/include/poincare/approximation_helper.h b/poincare/include/poincare/approximation_helper.h index 169143faf..e284c18e7 100644 --- a/poincare/include/poincare/approximation_helper.h +++ b/poincare/include/poincare/approximation_helper.h @@ -10,7 +10,7 @@ namespace Poincare { namespace ApproximationHelper { template int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); - template std::complex TruncateRealOrImaginaryPartAccordingToArgument(std::complex c); + template std::complex TruncateRealOrImaginaryPartAccordingToArgument(std::complex c, T norm1, T norm2 = 1.0); template using ComplexCompute = Complex(*)(const std::complex, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); template Evaluation Map(const ExpressionNode * expression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ComplexCompute compute); diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 32f1f88ad..58b655d5d 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -15,6 +15,10 @@ template T absMod(T a, T b) { return result > b/2 ? b-result : result; } +template bool isNegligeable(T x, T precision, T norm1, T norm2) { + return x <= precision && x/norm1 <= precision && x/norm2 <= precision; +} + static inline int absInt(int x) { return x < 0 ? -x : x; } template int ApproximationHelper::PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { @@ -27,13 +31,15 @@ template int ApproximationHelper::PositiveIntegerApproximationIfPos return absInt((int)scalar); } -template std::complex ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex c) { +template std::complex ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex c, T norm1, T norm2) { T arg = std::arg(c); - T precision = 10*Expression::Epsilon(); - if (absMod(arg, (T)M_PI) <= precision) { + T precision = 10.0*Expression::Epsilon(); + T argModPi = absMod(arg, (T)M_PI); + T argModHalfPi = absMod(arg-(T)M_PI/2.0, (T)M_PI); + if (isNegligeable(argModPi, precision, norm1, norm2)) { c.imag(0); } - if (absMod(arg-(T)M_PI/2.0, (T)M_PI) <= precision) { + if (isNegligeable(argModHalfPi, precision, norm1, norm2)) { c.real(0); } return c; @@ -106,8 +112,8 @@ template MatrixComplex ApproximationHelper::ElementWiseOnComplexM template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); -template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex); -template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex); +template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex,float,float); +template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex,double,double); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); template Poincare::Evaluation Poincare::ApproximationHelper::MapReduce(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationHelper::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationHelper::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationHelper::MatrixAndMatrixReduction computeOnMatrices); diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 495aa697a..798de23ae 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -151,8 +151,13 @@ Complex PowerNode::compute(const std::complex c, const std::complex d, * The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to * avoid weird results as e(i*pi) = -1+6E-17*i, we compute the argument of * the result of c^d and if arg ~ 0 [Pi], we discard the residual imaginary - * part and if arg ~ Pi/2 [Pi], we discard the residual real part. */ - return Complex::Builder(ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(result)); + * part and if arg ~ Pi/2 [Pi], we discard the residual real part. + * Let's determine when the arg [Pi] (or arg [Pi/2]) is negligeable: + * With c = r*e^(iθ) and d = x+iy, c^d = r^x*e^(yθ)*e^i(yln(r)+xθ) + * so arg(c^d) = y*ln(r)+xθ. + * We consider that arg[π] is negligeable if it is negligeable compared to + * norm(d) = sqrt(x^2+y^2) and ln(r) = ln(norm(c)).*/ + return Complex::Builder(ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(result, std::log(std::abs(c)), std::abs(d))); } // Layout diff --git a/poincare/src/square_root.cpp b/poincare/src/square_root.cpp index ed0954476..360d6056d 100644 --- a/poincare/src/square_root.cpp +++ b/poincare/src/square_root.cpp @@ -35,8 +35,12 @@ Complex SquareRootNode::computeOnComplex(const std::complex c, Preferences * The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid * weird results as sqrt(-1) = 6E-16+i, we compute the argument of the result * of sqrt(c) and if arg ~ 0 [Pi], we discard the residual imaginary part and - * if arg ~ Pi/2 [Pi], we discard the residual real part.*/ - return Complex::Builder(ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(result)); + * if arg ~ Pi/2 [Pi], we discard the residual real part. + * Let's determine when the arg [Pi] (or arg [Pi/2]) is negligeable: + * With c = r*e^(iθ), so arg(sqrt(c)) = θ/2. + * We consider that arg[Pi] is negligeable if it is negligeable compared to + * θ. */ + return Complex::Builder(ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(result, std::arg(c))); } Expression SquareRootNode::shallowReduce(ReductionContext reductionContext) { diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 89bc3b8ac..0be56dd6a 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -149,6 +149,10 @@ QUIZ_CASE(poincare_approximation_power) { assert_expression_approximates_to_scalar("2^3", 8.0f); assert_expression_approximates_to_scalar("(3+𝐢)^(4+𝐢)", NAN); assert_expression_approximates_to_scalar("[[1,2][3,4]]^2", NAN); + + + assert_expression_approximates_to("(-10)^0.00000001", "unreal", Radian, Real); + assert_expression_approximates_to("(-10)^0.00000001", "1+3.141593ᴇ-8×𝐢", Radian, Cartesian); } QUIZ_CASE(poincare_approximation_subtraction) { From 540770979855668911556ca952ff1af029620cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 25 Feb 2020 15:33:36 +0100 Subject: [PATCH 095/117] [poincare] Add approximation tests that fails because of precision loss --- poincare/test/approximation.cpp | 2 ++ poincare/test/helper.cpp | 12 ++++++++++++ poincare/test/helper.h | 2 ++ 3 files changed, 16 insertions(+) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 0be56dd6a..ee6c1580a 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -153,6 +153,8 @@ QUIZ_CASE(poincare_approximation_power) { assert_expression_approximates_to("(-10)^0.00000001", "unreal", Radian, Real); assert_expression_approximates_to("(-10)^0.00000001", "1+3.141593ᴇ-8×𝐢", Radian, Cartesian); + assert_expression_simplifies_approximates_to("3.5^2.0000001", "12.25"); + assert_expression_simplifies_approximates_to("3.7^2.0000001", "13.69"); } QUIZ_CASE(poincare_approximation_subtraction) { diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index ecd631b65..619881ef0 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -108,6 +108,16 @@ void assert_expression_approximates_to(const char * expression, const char * app }, numberOfDigits); } +template +void assert_expression_simplifies_approximates_to(const char * expression, const char * approximation, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, int numberOfSignificantDigits) { + int numberOfDigits = sizeof(T) == sizeof(double) ? PrintFloat::k_numberOfStoredSignificantDigits : PrintFloat::k_numberOfPrintedSignificantDigits; + numberOfDigits = numberOfSignificantDigits > 0 ? numberOfSignificantDigits : numberOfDigits; + assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, [](Expression e, ExpressionNode::ReductionContext reductionContext) { + e = e.simplify(reductionContext); + return e.approximate(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + }, numberOfDigits); +} + void assert_layout_serialize_to(Poincare::Layout layout, const char * serialization) { constexpr int bufferSize = 255; char buffer[bufferSize]; @@ -122,3 +132,5 @@ void assert_expression_layouts_as(Poincare::Expression expression, Poincare::Lay template void assert_expression_approximates_to(char const*, char const *, Poincare::Preferences::AngleUnit, Poincare::Preferences::ComplexFormat, int); template void assert_expression_approximates_to(char const*, char const *, Poincare::Preferences::AngleUnit, Poincare::Preferences::ComplexFormat, int); +template void assert_expression_simplifies_approximates_to(char const*, char const *, Poincare::Preferences::AngleUnit, Poincare::Preferences::ComplexFormat, int); +template void assert_expression_simplifies_approximates_to(char const*, char const *, Poincare::Preferences::AngleUnit, Poincare::Preferences::ComplexFormat, int); diff --git a/poincare/test/helper.h b/poincare/test/helper.h index cdac8d201..574adc81d 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -43,6 +43,8 @@ void assert_parsed_expression_simplify_to(const char * expression, const char * template void assert_expression_approximates_to(const char * expression, const char * approximation, Poincare::Preferences::AngleUnit angleUnit = Degree, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, int numberOfSignificantDigits = -1); +template +void assert_expression_simplifies_approximates_to(const char * expression, const char * approximation, Poincare::Preferences::AngleUnit angleUnit = Degree, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, int numberOfSignificantDigits = -1); // Layout serializing From 12a5f5499ccf56e180578d19ee3207cb27d5183a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 26 Feb 2020 11:06:47 +0100 Subject: [PATCH 096/117] [poincare] Handle real root finding in Power and NthRoot in order to remove beautifying x^(p/q) -> root(x,q)^p. This triggered precision loss! --- poincare/include/poincare/power.h | 6 ++- poincare/src/nth_root.cpp | 16 +++---- poincare/src/power.cpp | 69 ++++++++++++++++++++++++------- poincare/test/approximation.cpp | 7 ++-- poincare/test/simplification.cpp | 4 +- 5 files changed, 70 insertions(+), 32 deletions(-) diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index c5860e77e..b2e161b85 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -34,6 +34,7 @@ public: int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; + template static Complex computeRealRootOfRationalPow(const std::complex c, T p, T q); template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat); private: @@ -59,11 +60,12 @@ private: template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex d, Preferences::ComplexFormat complexFormat); template static MatrixComplex computeOnMatrices(const MatrixComplex m, const MatrixComplex n, Preferences::ComplexFormat complexFormat); Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { - return ApproximationHelper::MapReduce(this, context, complexFormat, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + return templatedApproximate(context, complexFormat, angleUnit); } Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { - return ApproximationHelper::MapReduce(this, context, complexFormat, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + return templatedApproximate(context, complexFormat, angleUnit); } + template Evaluation templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; }; class Power final : public Expression { diff --git a/poincare/src/nth_root.cpp b/poincare/src/nth_root.cpp index 74ee32f52..b5081c1c0 100644 --- a/poincare/src/nth_root.cpp +++ b/poincare/src/nth_root.cpp @@ -46,18 +46,12 @@ Evaluation NthRootNode::templatedApproximate(Context * context, Preferences:: /* If the complexFormat is Real, we look for nthroot of form root(x,q) with * x real and q integer because they might have a real form which does not * correspond to the principale angle. */ - if (complexFormat == Preferences::ComplexFormat::Real) { + if (complexFormat == Preferences::ComplexFormat::Real && indexc.imag() == 0.0 && std::round(indexc.real()) == indexc.real()) { // root(x, q) with q integer and x real - if (basec.imag() == 0.0 && indexc.imag() == 0.0 && std::round(indexc.real()) == indexc.real()) { - std::complex absBasec = basec; - absBasec.real(std::fabs(absBasec.real())); - // compute root(|x|, q) - Complex absBasePowIndex = PowerNode::compute(absBasec, std::complex(1.0)/(indexc), complexFormat); - // q odd if (-1)^q = -1 - if (std::pow((T)-1.0, (T)indexc.real()) < 0.0) { - return basec.real() < 0 ? Complex::Builder(-absBasePowIndex.stdComplex()) : absBasePowIndex; - } - } + Complex result = PowerNode::computeRealRootOfRationalPow(basec, (T)1.0, indexc.real()); + if (!result.isUndefined()) { + return result; + } } result = PowerNode::compute(basec, std::complex(1.0)/(indexc), complexFormat); } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 798de23ae..29d25e7c4 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -127,6 +127,22 @@ bool PowerNode::childAtIndexNeedsUserParentheses(const Expression & child, int c // Private +template +Complex PowerNode::computeRealRootOfRationalPow(const std::complex c, T p, T q) { + // Compute real root of c^(p/q) with p, q integers if it has a real root + if (c.imag() == 0 && std::pow((T)-1.0, q) < 0.0) { + /* If c real and q odd integer (q odd if (-1)^q = -1), a real root does + * exist (which is not necessarily the principal root)! */ + std::complex absc = c; + absc.real(std::fabs(absc.real())); + // compute |c|^(p/q) which is a real + Complex absCPowD = PowerNode::compute(absc, std::complex(p/q), Preferences::ComplexFormat::Real); + // c^(p/q) = (sign(c)^p)*|c|^(p/q) = -|c|^(p/q) iff c < 0 and p odd + return c.real() < 0 && std::pow((T)-1.0, p) < 0.0 ? Complex::Builder(-absCPowD.stdComplex()) : absCPowD; + } + return Complex::Undefined(); +} + template Complex PowerNode::compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat) { std::complex result; @@ -262,6 +278,45 @@ template MatrixComplex PowerNode::computeOnMatrices(const MatrixC return MatrixComplex::Undefined(); } +template Evaluation PowerNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + /* Special case: c^(p/q) with p, q integers + * In real mode, c^(p/q) might have a real root which is not the principal + * root. We return this value in that case to avoid returning "unreal". */ + if (complexFormat == Preferences::ComplexFormat::Real) { + Evaluation base = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit); + if (base.type() != EvaluationNode::Type::Complex) { + goto defaultApproximation; + } + std::complex c = static_cast &>(base).stdComplex(); + T p = NAN; + T q = NAN; + if (childAtIndex(1)->type() == ExpressionNode::Type::Rational) { + const RationalNode * r = static_cast(childAtIndex(1)); + p = r->signedNumerator().approximate(); + q = r->denominator().approximate(); + } + // Spot form p/q with p, q integers + if (childAtIndex(1)->type() == ExpressionNode::Type::Division && childAtIndex(1)->childAtIndex(0)->type() == ExpressionNode::Type::Rational && childAtIndex(1)->childAtIndex(1)->type() == ExpressionNode::Type::Rational) { + const RationalNode * pRat = static_cast(childAtIndex(1)->childAtIndex(0)); + const RationalNode * qRat = static_cast(childAtIndex(1)->childAtIndex(1)); + if (!pRat->denominator().isOne() || !qRat->denominator().isOne()) { + goto defaultApproximation; + } + p = pRat->signedNumerator().approximate(); + q = qRat->signedNumerator().approximate(); + } + if (std::isnan(p) || std::isnan(q)) { + goto defaultApproximation; + } + Complex result = computeRealRootOfRationalPow(c, p, q); + if (!result.isUndefined()) { + return result; + } + } +defaultApproximation: + return ApproximationHelper::MapReduce(this, context, complexFormat, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); +} + // Power Expression Power::setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext) { @@ -901,20 +956,6 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont return result; } - /* Optional Step 3: if the ReductionTarget is the SystemForApproximation or - * SystemForAnalysis, turn a^(p/q) into (root(a, q))^p - * Indeed, root(a, q) can have a real root which is not the principale angle - * but that we want to return in real complex format. This special case is - * handled in NthRoot approximation but not in Power approximation. */ - if (reductionContext.target() != ExpressionNode::ReductionTarget::User && childAtIndex(1).type() == ExpressionNode::Type::Rational) { - Integer p = childAtIndex(1).convert().signedIntegerNumerator(); - Integer q = childAtIndex(1).convert().integerDenominator(); - Expression nthRoot = q.isOne() ? childAtIndex(0) : NthRoot::Builder(childAtIndex(0), Rational::Builder(q)); - Expression result = p.isOne() ? nthRoot : Power::Builder(nthRoot, Rational::Builder(p)); - replaceWithInPlace(result); - return result; - } - // Step 4: Force Float(1) in front of an orphan Power of Unit if (parent().isUninitialized() && childAtIndex(0).type() == ExpressionNode::Type::Unit) { Multiplication m = Multiplication::Builder(Float::Builder(1.0)); diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index ee6c1580a..362cd621f 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -837,11 +837,12 @@ QUIZ_CASE(poincare_approximation_complex_format) { assert_expression_approximates_to("√(-1)", "unreal", Radian, Real); assert_expression_approximates_to("√(-1)×√(-1)", "unreal", Radian, Real); assert_expression_approximates_to("ln(-2)", "unreal", Radian, Real); - assert_expression_approximates_to("(-8)^(1/3)", "unreal", Radian, Real); // Power always approximates to the principal root (even if unreal) + // Power/Root approximates to the first REAL root in Real mode + assert_expression_simplifies_approximates_to("(-8)^(1/3)", "-2", Radian, Real); // Power have to be simplified first in order to spot the right form c^(p/q) with p, q integers assert_expression_approximates_to("root(-8,3)", "-2", Radian, Real); // Root approximates to the first REAL root in Real mode assert_expression_approximates_to("8^(1/3)", "2", Radian, Real); - assert_expression_approximates_to("(-8)^(2/3)", "unreal", Radian, Real); // Power always approximates to the principal root (even if unreal) - assert_expression_approximates_to("root(-8, 3)^2", "4", Radian, Real); // Root approximates to the first REAL root in Real mode + assert_expression_simplifies_approximates_to("(-8)^(2/3)", "4", Radian, Real); // Power have to be simplified first (cf previous comment) + assert_expression_approximates_to("root(-8, 3)^2", "4", Radian, Real); assert_expression_approximates_to("root(-8,3)", "-2", Radian, Real); // Cartesian diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 0dd49cc10..cd5bd1c04 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1231,8 +1231,8 @@ QUIZ_CASE(poincare_simplification_reduction_target) { assert_parsed_expression_simplify_to("(1+x)/(1+x)", "1", User); // Apply rule x^(2/3) --> root(x,3)^2 for ReductionTarget = System - assert_parsed_expression_simplify_to("x^(2/3)", "root(x,3)^2", SystemForApproximation); - assert_parsed_expression_simplify_to("x^(2/3)", "root(x,3)^2", SystemForAnalysis); + assert_parsed_expression_simplify_to("x^(2/3)", "x^\u00122/3\u0013", SystemForApproximation); + assert_parsed_expression_simplify_to("x^(2/3)", "x^\u00122/3\u0013", SystemForAnalysis); assert_parsed_expression_simplify_to("x^(2/3)", "x^\u00122/3\u0013", User); assert_parsed_expression_simplify_to("x^(1/3)", "root(x,3)", SystemForApproximation); assert_parsed_expression_simplify_to("x^(1/3)", "root(x,3)", SystemForAnalysis); From 9936d9941189cd9b4f8e4c85b461b6af0ba0a20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 26 Feb 2020 14:51:06 +0100 Subject: [PATCH 097/117] [poincare] Add comment on Power::templatedApproximate --- poincare/src/power.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 29d25e7c4..b086e6b4f 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -290,12 +290,14 @@ template Evaluation PowerNode::templatedApproximate(Context * con std::complex c = static_cast &>(base).stdComplex(); T p = NAN; T q = NAN; + // If the power has been reduced, we look for a rational index if (childAtIndex(1)->type() == ExpressionNode::Type::Rational) { const RationalNode * r = static_cast(childAtIndex(1)); p = r->signedNumerator().approximate(); q = r->denominator().approximate(); } - // Spot form p/q with p, q integers + /* If the power has been simplified (reduced + beautified), we look for an + * index of the for Division(Rational,Rational). */ if (childAtIndex(1)->type() == ExpressionNode::Type::Division && childAtIndex(1)->childAtIndex(0)->type() == ExpressionNode::Type::Rational && childAtIndex(1)->childAtIndex(1)->type() == ExpressionNode::Type::Rational) { const RationalNode * pRat = static_cast(childAtIndex(1)->childAtIndex(0)); const RationalNode * qRat = static_cast(childAtIndex(1)->childAtIndex(1)); @@ -305,6 +307,9 @@ template Evaluation PowerNode::templatedApproximate(Context * con p = pRat->signedNumerator().approximate(); q = qRat->signedNumerator().approximate(); } + /* We don't handle power that haven't been reduced or simplified as the + * index can take to many forms and still be equivalent to p/q, + * with p, q integers. */ if (std::isnan(p) || std::isnan(q)) { goto defaultApproximation; } From a2e9d8efd6357d79c588b66a78a5bc8888744704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 5 Mar 2020 11:09:12 +0100 Subject: [PATCH 098/117] [poincare] Improve trigonometry functions and power functions approximations. We neglect the real or imaginary parts when it is neglectable compared to the input. --- .../include/poincare/approximation_helper.h | 2 +- poincare/include/poincare/trigonometry.h | 3 -- poincare/src/approximation_helper.cpp | 46 ++++++++++++------- poincare/src/arc_cosine.cpp | 2 +- poincare/src/arc_sine.cpp | 2 +- poincare/src/arc_tangent.cpp | 2 +- poincare/src/cosine.cpp | 2 +- poincare/src/hyperbolic_arc_cosine.cpp | 2 +- poincare/src/hyperbolic_arc_sine.cpp | 2 +- poincare/src/hyperbolic_arc_tangent.cpp | 2 +- poincare/src/hyperbolic_cosine.cpp | 2 +- poincare/src/hyperbolic_sine.cpp | 2 +- poincare/src/hyperbolic_tangent.cpp | 2 +- poincare/src/power.cpp | 2 +- poincare/src/sine.cpp | 2 +- poincare/src/square_root.cpp | 12 +---- poincare/src/tangent.cpp | 2 +- poincare/src/trigonometry.cpp | 25 ---------- 18 files changed, 44 insertions(+), 70 deletions(-) diff --git a/poincare/include/poincare/approximation_helper.h b/poincare/include/poincare/approximation_helper.h index e284c18e7..9b0b8ce17 100644 --- a/poincare/include/poincare/approximation_helper.h +++ b/poincare/include/poincare/approximation_helper.h @@ -10,7 +10,7 @@ namespace Poincare { namespace ApproximationHelper { template int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); - template std::complex TruncateRealOrImaginaryPartAccordingToArgument(std::complex c, T norm1, T norm2 = 1.0); + template std::complex NeglectRealOrImaginaryPartIfNeglectable(std::complex result, std::complex input1, std::complex input2 = 1.0); template using ComplexCompute = Complex(*)(const std::complex, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); template Evaluation Map(const ExpressionNode * expression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ComplexCompute compute); diff --git a/poincare/include/poincare/trigonometry.h b/poincare/include/poincare/trigonometry.h index 4b0e3fd6e..0eac9d5c2 100644 --- a/poincare/include/poincare/trigonometry.h +++ b/poincare/include/poincare/trigonometry.h @@ -23,9 +23,6 @@ public: static Expression table(const Expression e, ExpressionNode::Type type, ExpressionNode::ReductionContext reductionContext); // , Function f, bool inverse template static std::complex ConvertToRadian(const std::complex c, Preferences::AngleUnit angleUnit); template static std::complex ConvertRadianToAngleUnit(const std::complex c, Preferences::AngleUnit angleUnit); - template static std::complex RoundToMeaningfulDigits(const std::complex result, const std::complex input); -private: - template static T RoundToMeaningfulDigits(T result, T input); }; } diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 58b655d5d..d9b47f967 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -10,15 +10,19 @@ extern "C" { namespace Poincare { -template T absMod(T a, T b) { - T result = std::fmod(std::fabs(a), b); - return result > b/2 ? b-result : result; -} - template bool isNegligeable(T x, T precision, T norm1, T norm2) { return x <= precision && x/norm1 <= precision && x/norm2 <= precision; } +template < typename T> T minimalNonNullMagnitudeOfParts(std::complex c) { + T absRealInput = std::fabs(c.real()); + T absImagInput = std::fabs(c.imag()); + // If the magnitude of one part is null, ignore it + absRealInput = absRealInput > 0.0 ? absRealInput : absImagInput; + absImagInput = absImagInput > 0.0 ? absImagInput : absRealInput; + return absRealInput > absImagInput ? absImagInput : absRealInput; +} + static inline int absInt(int x) { return x < 0 ? -x : x; } template int ApproximationHelper::PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { @@ -31,18 +35,26 @@ template int ApproximationHelper::PositiveIntegerApproximationIfPos return absInt((int)scalar); } -template std::complex ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex c, T norm1, T norm2) { - T arg = std::arg(c); - T precision = 10.0*Expression::Epsilon(); - T argModPi = absMod(arg, (T)M_PI); - T argModHalfPi = absMod(arg-(T)M_PI/2.0, (T)M_PI); - if (isNegligeable(argModPi, precision, norm1, norm2)) { - c.imag(0); +template std::complex ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex result, std::complex input1, std::complex input2) { + /* Cheat: openbsd functions (cos, sin, tan, cosh, acos, pow...) are + * numerical implementation and thus are approximative. + * The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid + * weird results as acos(1) = 6E-17 or cos(π/2) = 4E-17, we round the result + * to its 1E-6 or 1E-14 precision when its ratio with the argument (π/2 in the + * example) is smaller than epsilon. This way, we have sin(π) ~ 0 and + * sin(1E-15)=1E-15. + * We can't do that for all evaluation as the user can operate on values as + * small as 1E-308 (in double) and most results still be correct. */ + T magnitude1 = minimalNonNullMagnitudeOfParts(input1); + T magnitude2 = minimalNonNullMagnitudeOfParts(input2); + T precision = 100.0*Expression::Epsilon(); + if (isNegligeable(std::fabs(result.imag()), precision, magnitude1, magnitude2)) { + result.imag(0); } - if (isNegligeable(argModHalfPi, precision, norm1, norm2)) { - c.real(0); + if (isNegligeable(std::fabs(result.real()), precision, magnitude1, magnitude2)) { + result.real(0); } - return c; + return result; } template Evaluation ApproximationHelper::Map(const ExpressionNode * expression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ComplexCompute compute) { @@ -112,8 +124,8 @@ template MatrixComplex ApproximationHelper::ElementWiseOnComplexM template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); -template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex,float,float); -template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex,double,double); +template std::complex Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex,std::complex,std::complex); +template std::complex Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex,std::complex,std::complex); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); template Poincare::Evaluation Poincare::ApproximationHelper::MapReduce(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationHelper::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationHelper::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationHelper::MatrixAndMatrixReduction computeOnMatrices); diff --git a/poincare/src/arc_cosine.cpp b/poincare/src/arc_cosine.cpp index 353c4b974..9f27e4f5d 100644 --- a/poincare/src/arc_cosine.cpp +++ b/poincare/src/arc_cosine.cpp @@ -44,7 +44,7 @@ Complex ArcCosineNode::computeOnComplex(const std::complex c, Preferences: result.imag(-result.imag()); // other side of the cut } } - result = Trigonometry::RoundToMeaningfulDigits(result, c); + result = ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c); return Complex::Builder(Trigonometry::ConvertRadianToAngleUnit(result, angleUnit)); } diff --git a/poincare/src/arc_sine.cpp b/poincare/src/arc_sine.cpp index 2ee8b0fd1..4d7100ac8 100644 --- a/poincare/src/arc_sine.cpp +++ b/poincare/src/arc_sine.cpp @@ -44,7 +44,7 @@ Complex ArcSineNode::computeOnComplex(const std::complex c, Preferences::C result.imag(-result.imag()); // other side of the cut } } - result = Trigonometry::RoundToMeaningfulDigits(result, c); + result = ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c); return Complex::Builder(Trigonometry::ConvertRadianToAngleUnit(result, angleUnit)); } diff --git a/poincare/src/arc_tangent.cpp b/poincare/src/arc_tangent.cpp index 2f8152411..19bb310bb 100644 --- a/poincare/src/arc_tangent.cpp +++ b/poincare/src/arc_tangent.cpp @@ -40,7 +40,7 @@ Complex ArcTangentNode::computeOnComplex(const std::complex c, Preferences result.real(-result.real()); // other side of the cut } } - result = Trigonometry::RoundToMeaningfulDigits(result, c); + result = ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c); return Complex::Builder(Trigonometry::ConvertRadianToAngleUnit(result, angleUnit)); } diff --git a/poincare/src/cosine.cpp b/poincare/src/cosine.cpp index 91414e60c..2e216ce8e 100644 --- a/poincare/src/cosine.cpp +++ b/poincare/src/cosine.cpp @@ -19,7 +19,7 @@ template Complex CosineNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { std::complex angleInput = Trigonometry::ConvertToRadian(c, angleUnit); std::complex res = std::cos(angleInput); - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(res, angleInput)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(res, angleInput)); } Layout CosineNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { diff --git a/poincare/src/hyperbolic_arc_cosine.cpp b/poincare/src/hyperbolic_arc_cosine.cpp index 8ea38dd6c..eb6f4b668 100644 --- a/poincare/src/hyperbolic_arc_cosine.cpp +++ b/poincare/src/hyperbolic_arc_cosine.cpp @@ -23,7 +23,7 @@ Complex HyperbolicArcCosineNode::computeOnComplex(const std::complex c, Pr * on this cut. We followed the convention chosen by the lib c++ of llvm on * ]-inf+0i, 1+0i] (warning: atanh takes the other side of the cut values on * ]-inf-0i, 1-0i[).*/ - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(result, c)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c)); } template Complex Poincare::HyperbolicArcCosineNode::computeOnComplex(std::complex, Preferences::ComplexFormat, Preferences::AngleUnit); diff --git a/poincare/src/hyperbolic_arc_sine.cpp b/poincare/src/hyperbolic_arc_sine.cpp index 7ee51048c..3952a4f29 100644 --- a/poincare/src/hyperbolic_arc_sine.cpp +++ b/poincare/src/hyperbolic_arc_sine.cpp @@ -27,7 +27,7 @@ Complex HyperbolicArcSineNode::computeOnComplex(const std::complex c, Pref if (c.real() == 0 && c.imag() < 1) { result.real(-result.real()); // other side of the cut } - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(result, c)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c)); } template Complex Poincare::HyperbolicArcSineNode::computeOnComplex(std::complex, Preferences::ComplexFormat, Preferences::AngleUnit); diff --git a/poincare/src/hyperbolic_arc_tangent.cpp b/poincare/src/hyperbolic_arc_tangent.cpp index 13c63bba5..09453d22a 100644 --- a/poincare/src/hyperbolic_arc_tangent.cpp +++ b/poincare/src/hyperbolic_arc_tangent.cpp @@ -27,7 +27,7 @@ Complex HyperbolicArcTangentNode::computeOnComplex(const std::complex c, P if (c.imag() == 0 && c.real() > 1) { result.imag(-result.imag()); // other side of the cut } - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(result, c)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c)); } template Complex Poincare::HyperbolicArcTangentNode::computeOnComplex(std::complex, Preferences::ComplexFormat, Preferences::AngleUnit); diff --git a/poincare/src/hyperbolic_cosine.cpp b/poincare/src/hyperbolic_cosine.cpp index c722ec209..c963ee4ad 100644 --- a/poincare/src/hyperbolic_cosine.cpp +++ b/poincare/src/hyperbolic_cosine.cpp @@ -16,7 +16,7 @@ int HyperbolicCosineNode::serialize(char * buffer, int bufferSize, Preferences:: template Complex HyperbolicCosineNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(std::cosh(c), c)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::cosh(c), c)); } template Complex Poincare::HyperbolicCosineNode::computeOnComplex(std::complex, Preferences::ComplexFormat, Preferences::AngleUnit); diff --git a/poincare/src/hyperbolic_sine.cpp b/poincare/src/hyperbolic_sine.cpp index 232bd8fcb..237804747 100644 --- a/poincare/src/hyperbolic_sine.cpp +++ b/poincare/src/hyperbolic_sine.cpp @@ -16,7 +16,7 @@ int HyperbolicSineNode::serialize(char * buffer, int bufferSize, Preferences::Pr template Complex HyperbolicSineNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(std::sinh(c), c)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::sinh(c), c)); } template Complex Poincare::HyperbolicSineNode::computeOnComplex(std::complex, Preferences::ComplexFormat, Preferences::AngleUnit); diff --git a/poincare/src/hyperbolic_tangent.cpp b/poincare/src/hyperbolic_tangent.cpp index 7c4ad545d..48a5e8830 100644 --- a/poincare/src/hyperbolic_tangent.cpp +++ b/poincare/src/hyperbolic_tangent.cpp @@ -16,7 +16,7 @@ int HyperbolicTangentNode::serialize(char * buffer, int bufferSize, Preferences: template Complex HyperbolicTangentNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(std::tanh(c), c)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::tanh(c), c)); } template Complex Poincare::HyperbolicTangentNode::computeOnComplex(std::complex, Preferences::ComplexFormat, Preferences::AngleUnit); diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index b086e6b4f..460437e3f 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -173,7 +173,7 @@ Complex PowerNode::compute(const std::complex c, const std::complex d, * so arg(c^d) = y*ln(r)+xθ. * We consider that arg[π] is negligeable if it is negligeable compared to * norm(d) = sqrt(x^2+y^2) and ln(r) = ln(norm(c)).*/ - return Complex::Builder(ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(result, std::log(std::abs(c)), std::abs(d))); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d)); } // Layout diff --git a/poincare/src/sine.cpp b/poincare/src/sine.cpp index a4701e0c6..3668d8a3a 100644 --- a/poincare/src/sine.cpp +++ b/poincare/src/sine.cpp @@ -19,7 +19,7 @@ template Complex SineNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { std::complex angleInput = Trigonometry::ConvertToRadian(c, angleUnit); std::complex res = std::sin(angleInput); - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(res, angleInput)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(res, angleInput)); } Layout SineNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { diff --git a/poincare/src/square_root.cpp b/poincare/src/square_root.cpp index 360d6056d..0c8361d1e 100644 --- a/poincare/src/square_root.cpp +++ b/poincare/src/square_root.cpp @@ -30,17 +30,7 @@ int SquareRootNode::serialize(char * buffer, int bufferSize, Preferences::PrintF template Complex SquareRootNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { std::complex result = std::sqrt(c); - /* Openbsd trigonometric functions are numerical implementation and thus are - * approximative. - * The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid - * weird results as sqrt(-1) = 6E-16+i, we compute the argument of the result - * of sqrt(c) and if arg ~ 0 [Pi], we discard the residual imaginary part and - * if arg ~ Pi/2 [Pi], we discard the residual real part. - * Let's determine when the arg [Pi] (or arg [Pi/2]) is negligeable: - * With c = r*e^(iθ), so arg(sqrt(c)) = θ/2. - * We consider that arg[Pi] is negligeable if it is negligeable compared to - * θ. */ - return Complex::Builder(ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(result, std::arg(c))); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, std::complex(std::log(std::abs(c)), std::arg(c)))); } Expression SquareRootNode::shallowReduce(ReductionContext reductionContext) { diff --git a/poincare/src/tangent.cpp b/poincare/src/tangent.cpp index 0d44b0a5a..e140a4992 100644 --- a/poincare/src/tangent.cpp +++ b/poincare/src/tangent.cpp @@ -30,7 +30,7 @@ template Complex TangentNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { std::complex angleInput = Trigonometry::ConvertToRadian(c, angleUnit); std::complex res = std::tan(angleInput); - return Complex::Builder(Trigonometry::RoundToMeaningfulDigits(res, angleInput)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(res, angleInput)); } Expression TangentNode::shallowReduce(ReductionContext reductionContext) { diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index dd802f97b..168f7e49d 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -412,34 +412,9 @@ std::complex Trigonometry::ConvertRadianToAngleUnit(const std::complex c, return c; } -template -T Trigonometry::RoundToMeaningfulDigits(T result, T input) { - /* Cheat: openbsd trigonometric functions are numerical implementation and - * thus are approximative. - * The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid - * weird results as acos(1) = 6E-17 or cos(π/2) = 4E-17, we round the result - * to its 1E-6 or 1E-14 precision when its ratio with the argument (π/2 in the - * example) is smaller than epsilon. This way, we have sin(π) ~ 0 and - * sin(1E-15)=1E-15. - * We can't do that for all evaluation as the user can operate on values as - * small as 1E-308 (in double) and most results still be correct. */ - if (input == 0.0 || std::fabs(result/input) <= Expression::Epsilon()) { - T precision = 10*Expression::Epsilon(); - result = std::round(result/precision)*precision; - } - return result; -} - -template -std::complex Trigonometry::RoundToMeaningfulDigits(const std::complex result, const std::complex input) { - return std::complex(RoundToMeaningfulDigits(result.real(), std::abs(input)), RoundToMeaningfulDigits(result.imag(), std::abs(input))); -} - template std::complex Trigonometry::ConvertToRadian(std::complex, Preferences::AngleUnit); template std::complex Trigonometry::ConvertToRadian(std::complex, Preferences::AngleUnit); template std::complex Trigonometry::ConvertRadianToAngleUnit(std::complex, Preferences::AngleUnit); template std::complex Trigonometry::ConvertRadianToAngleUnit(std::complex, Preferences::AngleUnit); -template std::complex Trigonometry::RoundToMeaningfulDigits(std::complex, std::complex); -template std::complex Trigonometry::RoundToMeaningfulDigits(std::complex, std::complex); } From d431642e60d1d75b3899249964fb535c89c7eebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 5 Mar 2020 17:47:00 +0100 Subject: [PATCH 099/117] [poincare] Add tests on atanh approximation --- poincare/test/approximation.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 362cd621f..541198c8b 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -778,6 +778,13 @@ QUIZ_CASE(poincare_approximation_trigonometry_functions) { assert_expression_approximates_to("atanh(𝐢-4)", "-0.238878+1.50862×𝐢", Radian, Cartesian, 6); assert_expression_approximates_to("atanh(𝐢-4)", "-0.238878+1.50862×𝐢", Degree, Cartesian, 6); + // Check that the complex part is not neglected + assert_expression_approximates_to("atanh(0.99999999999+1.0ᴇ-26×𝐢)", "13.01+5ᴇ-16×𝐢", Radian, Cartesian, 4); + assert_expression_approximates_to("atanh(0.99999999999+1.0ᴇ-60×𝐢)", "13.01+5ᴇ-50×𝐢", Radian, Cartesian, 4); + assert_expression_approximates_to("atanh(0.99999999999+1.0ᴇ-150×𝐢)", "13.01+5ᴇ-140×𝐢", Radian, Cartesian, 4); + assert_expression_approximates_to("atanh(0.99999999999+1.0ᴇ-250×𝐢)", "13.01+5ᴇ-240×𝐢", Radian, Cartesian, 4); + assert_expression_approximates_to("atanh(0.99999999999+1.0ᴇ-300×𝐢)", "13.01+5ᴇ-290×𝐢", Radian, Cartesian, 4); + // WARNING: evaluate on branch cut can be multivalued assert_expression_approximates_to("acos(2)", "1.3169578969248×𝐢", Radian); assert_expression_approximates_to("acos(2)", "75.456129290217×𝐢", Degree); From 879c1e3bf1856c80022c0f08e1b1df22435e74fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 6 Mar 2020 10:35:14 +0100 Subject: [PATCH 100/117] [poincare] ApproximationHelper: fix precision threshold of NeglectRealOrImaginaryPartIfNeglectable --- poincare/src/approximation_helper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index d9b47f967..b55a37260 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -11,7 +11,7 @@ extern "C" { namespace Poincare { template bool isNegligeable(T x, T precision, T norm1, T norm2) { - return x <= precision && x/norm1 <= precision && x/norm2 <= precision; + return x <= 10.0*precision && x/norm1 <= precision && x/norm2 <= precision; } template < typename T> T minimalNonNullMagnitudeOfParts(std::complex c) { @@ -47,7 +47,7 @@ template std::complex ApproximationHelper::NeglectRealOrImaginar * small as 1E-308 (in double) and most results still be correct. */ T magnitude1 = minimalNonNullMagnitudeOfParts(input1); T magnitude2 = minimalNonNullMagnitudeOfParts(input2); - T precision = 100.0*Expression::Epsilon(); + T precision = 10.0*Expression::Epsilon(); if (isNegligeable(std::fabs(result.imag()), precision, magnitude1, magnitude2)) { result.imag(0); } From 175af27ea9d83fb6984c21fb7c6472b254c6bab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 12 Mar 2020 13:50:28 +0100 Subject: [PATCH 101/117] [poincare/approximation_helper] Factorize some code --- poincare/src/approximation_helper.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index b55a37260..9c498f4ce 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -11,7 +11,8 @@ extern "C" { namespace Poincare { template bool isNegligeable(T x, T precision, T norm1, T norm2) { - return x <= 10.0*precision && x/norm1 <= precision && x/norm2 <= precision; + T absX = std::fabs(x); + return absX <= 10.0*precision && absX/norm1 <= precision && absX/norm2 <= precision; } template < typename T> T minimalNonNullMagnitudeOfParts(std::complex c) { @@ -48,10 +49,10 @@ template std::complex ApproximationHelper::NeglectRealOrImaginar T magnitude1 = minimalNonNullMagnitudeOfParts(input1); T magnitude2 = minimalNonNullMagnitudeOfParts(input2); T precision = 10.0*Expression::Epsilon(); - if (isNegligeable(std::fabs(result.imag()), precision, magnitude1, magnitude2)) { + if (isNegligeable(result.imag(), precision, magnitude1, magnitude2)) { result.imag(0); } - if (isNegligeable(std::fabs(result.real()), precision, magnitude1, magnitude2)) { + if (isNegligeable(result.real(), precision, magnitude1, magnitude2)) { result.real(0); } return result; From 576d1dcd6ba4e4284318efad9936041d97e7719f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 12 Mar 2020 14:10:16 +0100 Subject: [PATCH 102/117] [poincare/power] Rename and comment computeRealRootOfRationalPow --- poincare/include/poincare/power.h | 2 +- poincare/src/nth_root.cpp | 2 +- poincare/src/power.cpp | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index b2e161b85..1f40e978f 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -34,7 +34,7 @@ public: int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; - template static Complex computeRealRootOfRationalPow(const std::complex c, T p, T q); + template static Complex tryComputeRealRootOfRationalPow(const std::complex c, T p, T q); template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat); private: diff --git a/poincare/src/nth_root.cpp b/poincare/src/nth_root.cpp index b5081c1c0..3af471605 100644 --- a/poincare/src/nth_root.cpp +++ b/poincare/src/nth_root.cpp @@ -48,7 +48,7 @@ Evaluation NthRootNode::templatedApproximate(Context * context, Preferences:: * correspond to the principale angle. */ if (complexFormat == Preferences::ComplexFormat::Real && indexc.imag() == 0.0 && std::round(indexc.real()) == indexc.real()) { // root(x, q) with q integer and x real - Complex result = PowerNode::computeRealRootOfRationalPow(basec, (T)1.0, indexc.real()); + Complex result = PowerNode::tryComputeRealRootOfRationalPow(basec, (T)1.0, indexc.real()); if (!result.isUndefined()) { return result; } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 460437e3f..712c5ab79 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -128,16 +128,24 @@ bool PowerNode::childAtIndexNeedsUserParentheses(const Expression & child, int c // Private template -Complex PowerNode::computeRealRootOfRationalPow(const std::complex c, T p, T q) { - // Compute real root of c^(p/q) with p, q integers if it has a real root +Complex PowerNode::tryComputeRealRootOfRationalPow(const std::complex c, T p, T q) { + // Assert p and q are in fact integers + assert(std::round(p) == p); + assert(std::round(q) == q); + /* Try to find a real root of c^(p/q) with p, q integers. If none is found + * easily, return undefined -> this does not mean there is no real root. */ if (c.imag() == 0 && std::pow((T)-1.0, q) < 0.0) { /* If c real and q odd integer (q odd if (-1)^q = -1), a real root does - * exist (which is not necessarily the principal root)! */ + * exist (which is not necessarily the principal root)! + * For q even integer, a real root does not necessarily exist (example: + * -2 ^(1/2)). */ std::complex absc = c; absc.real(std::fabs(absc.real())); // compute |c|^(p/q) which is a real Complex absCPowD = PowerNode::compute(absc, std::complex(p/q), Preferences::ComplexFormat::Real); - // c^(p/q) = (sign(c)^p)*|c|^(p/q) = -|c|^(p/q) iff c < 0 and p odd + /* As q is odd, c^(p/q) = (sign(c)^(1/q))^p * |c|^(p/q) + * = sign(c)^p * |c|^(p/q) + * = -|c|^(p/q) iff c < 0 and p odd */ return c.real() < 0 && std::pow((T)-1.0, p) < 0.0 ? Complex::Builder(-absCPowD.stdComplex()) : absCPowD; } return Complex::Undefined(); @@ -313,7 +321,7 @@ template Evaluation PowerNode::templatedApproximate(Context * con if (std::isnan(p) || std::isnan(q)) { goto defaultApproximation; } - Complex result = computeRealRootOfRationalPow(c, p, q); + Complex result = tryComputeRealRootOfRationalPow(c, p, q); if (!result.isUndefined()) { return result; } From 13b2deb714c7c125ed07fa0acfe8000ea2acb2c8 Mon Sep 17 00:00:00 2001 From: LeaNumworks <32390188+LeaNumworks@users.noreply.github.com> Date: Thu, 12 Mar 2020 14:13:39 +0100 Subject: [PATCH 103/117] [poincare/approximation_helper] Clearer code This should do the same output. --- poincare/src/approximation_helper.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 9c498f4ce..61c5f8d20 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -19,9 +19,10 @@ template < typename T> T minimalNonNullMagnitudeOfParts(std::complex c) { T absRealInput = std::fabs(c.real()); T absImagInput = std::fabs(c.imag()); // If the magnitude of one part is null, ignore it - absRealInput = absRealInput > 0.0 ? absRealInput : absImagInput; - absImagInput = absImagInput > 0.0 ? absImagInput : absRealInput; - return absRealInput > absImagInput ? absImagInput : absRealInput; + if (absRealInput == 0.0 || (absImagInput > 0.0 && absImagInput < absRealInput)) { + return absImagInput; + } + return absRealInput; } static inline int absInt(int x) { return x < 0 ? -x : x; } From 97d94d9e56aad85a43901bc02f684b18cd4d7fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 12 Mar 2020 16:54:50 +0100 Subject: [PATCH 104/117] [poincare/test] Add failing test on multiplication simplification --- poincare/test/approximation.cpp | 3 +++ poincare/test/helper.cpp | 10 ++++++++++ poincare/test/helper.h | 1 + 3 files changed, 14 insertions(+) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 541198c8b..00b51a122 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -938,6 +938,9 @@ QUIZ_CASE(poincare_approximation_mix) { assert_expression_approximates_to("sin(3)2(4+2)", "1.6934400967184", Radian); assert_expression_approximates_to("4/2×(2+3)", "10"); assert_expression_approximates_to("4/2×(2+3)", "10"); + + assert_expression_simplifies_and_approximates_to("1.0092^(20)", "1.2010050593402"); + assert_expression_simplifies_and_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); } diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 619881ef0..67d035b41 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -108,6 +108,16 @@ void assert_expression_approximates_to(const char * expression, const char * app }, numberOfDigits); } +void assert_expression_simplifies_and_approximates_to(const char * expression, const char * approximation, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, int numberOfSignificantDigits) { + int numberOfDigits = numberOfSignificantDigits > 0 ? numberOfSignificantDigits : PrintFloat::k_numberOfStoredSignificantDigits; + assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, [](Expression e, ExpressionNode::ReductionContext reductionContext) { + Expression reduced; + Expression approximated; + e.simplifyAndApproximate(&reduced, &approximated, reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.symbolicComputation()); + return approximated; + }, numberOfDigits); +} + template void assert_expression_simplifies_approximates_to(const char * expression, const char * approximation, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, int numberOfSignificantDigits) { int numberOfDigits = sizeof(T) == sizeof(double) ? PrintFloat::k_numberOfStoredSignificantDigits : PrintFloat::k_numberOfPrintedSignificantDigits; diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 574adc81d..5e7f5942e 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -43,6 +43,7 @@ void assert_parsed_expression_simplify_to(const char * expression, const char * template void assert_expression_approximates_to(const char * expression, const char * approximation, Poincare::Preferences::AngleUnit angleUnit = Degree, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, int numberOfSignificantDigits = -1); +void assert_expression_simplifies_and_approximates_to(const char * expression, const char * approximation, Poincare::Preferences::AngleUnit angleUnit = Degree, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, int numberOfSignificantDigits = -1); template void assert_expression_simplifies_approximates_to(const char * expression, const char * approximation, Poincare::Preferences::AngleUnit angleUnit = Degree, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, int numberOfSignificantDigits = -1); From 313cbf676771bfc22349e01dc5d38edd6ff8669c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 12 Mar 2020 16:55:18 +0100 Subject: [PATCH 105/117] [poincare/arithmetic] Shortcut the LCM and GCD computation if equal This fixes: LCM(7.88861e+169, 7.88861e+169), which overflowed at some point during the computation --- poincare/src/arithmetic.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/poincare/src/arithmetic.cpp b/poincare/src/arithmetic.cpp index f4563db79..a7b50149b 100644 --- a/poincare/src/arithmetic.cpp +++ b/poincare/src/arithmetic.cpp @@ -7,6 +7,9 @@ Integer Arithmetic::LCM(const Integer & a, const Integer & b) { if (a.isZero() || b.isZero()) { return Integer(0); } + if (a.isEqualTo(b)) { + return a; + } Integer signResult = Integer::Division(Integer::Multiplication(a, b), GCD(a, b)).quotient; signResult.setNegative(false); return signResult; @@ -16,7 +19,9 @@ Integer Arithmetic::GCD(const Integer & a, const Integer & b) { if (a.isOverflow() || b.isOverflow()) { return Integer::Overflow(false); } - + if (a.isEqualTo(b)) { + return a; + } Integer i = a; Integer j = b; i.setNegative(false); From e636a2c315047a05bcc3b8c9ef936d890bd7a6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 10:56:40 +0100 Subject: [PATCH 106/117] [poincare/test] Add failing tests (commented but to fix later!) --- poincare/test/approximation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 00b51a122..ecf5ceedd 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -941,6 +941,14 @@ QUIZ_CASE(poincare_approximation_mix) { assert_expression_simplifies_and_approximates_to("1.0092^(20)", "1.2010050593402"); assert_expression_simplifies_and_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); + assert_expression_approximates_to("1.0092^(20)", "1.2010050593402"); + assert_expression_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); + assert_expression_simplifies_approximates_to("1.0092^(20)", "1.2010050593402"); + assert_expression_simplifies_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); + //assert_expression_approximates_to("1.0092^(20)", "1.201005"); TODO does not work + assert_expression_approximates_to("1.0092^(50)×ln(3/2)", "0.6409366"); + //assert_expression_simplifies_approximates_to("1.0092^(20)", "1.2010050593402"); TODO does not work + //assert_expression_simplifies_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); TODO does not work } From 1e11650122c360a0b0c4b5c0428b6c252dd07ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 11:14:34 +0100 Subject: [PATCH 107/117] [poincare/test] Fix precision in approximation test --- poincare/test/approximation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index ecf5ceedd..d30412d34 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -940,11 +940,11 @@ QUIZ_CASE(poincare_approximation_mix) { assert_expression_approximates_to("4/2×(2+3)", "10"); assert_expression_simplifies_and_approximates_to("1.0092^(20)", "1.2010050593402"); - assert_expression_simplifies_and_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); + assert_expression_simplifies_and_approximates_to("1.0092^(50)×ln(3/2)", "0.6409373488899", Degree, Cartesian, 13); assert_expression_approximates_to("1.0092^(20)", "1.2010050593402"); - assert_expression_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); + assert_expression_approximates_to("1.0092^(50)×ln(3/2)", "0.6409373488899", Degree, Cartesian, 13); assert_expression_simplifies_approximates_to("1.0092^(20)", "1.2010050593402"); - assert_expression_simplifies_approximates_to("1.0092^(50)×ln(3/2)", "6.4093734888993ᴇ-1"); + assert_expression_simplifies_approximates_to("1.0092^(50)×ln(3/2)", "0.6409373488899", Degree, Cartesian, 13); //assert_expression_approximates_to("1.0092^(20)", "1.201005"); TODO does not work assert_expression_approximates_to("1.0092^(50)×ln(3/2)", "0.6409366"); //assert_expression_simplifies_approximates_to("1.0092^(20)", "1.2010050593402"); TODO does not work From f00bd4d1c53e3f260911199156b19782126e3caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 13:38:40 +0100 Subject: [PATCH 108/117] [poincare/multiplication] Factorize code --- poincare/src/multiplication.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 2bd6a536e..0626833c6 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -588,8 +588,10 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * which also are multiplications themselves. */ mergeMultiplicationChildrenInPlace(); + Context * context = reductionContext.context(); + // Step 2: Sort the children - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); + sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); // Step 3: Handle matrices /* Thanks to the simplification order, all matrix children (if any) are the @@ -664,7 +666,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * interval). */ if (multiplicationChildIndex >= 0) { - if (childAtIndex(multiplicationChildIndex).deepIsMatrix(reductionContext.context())) { + if (childAtIndex(multiplicationChildIndex).deepIsMatrix(context)) { return *this; } removeChildInPlace(resultMatrix, resultMatrix.numberOfChildren()); @@ -677,7 +679,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext } } replaceWithInPlace(resultMatrix); - return resultMatrix.shallowReduce(reductionContext.context()); + return resultMatrix.shallowReduce(context); } /* Step 4: Gather like terms. For example, turn pi^2*pi^3 into pi^5. Thanks to @@ -687,7 +689,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext while (i < numberOfChildren()-1) { Expression oi = childAtIndex(i); Expression oi1 = childAtIndex(i+1); - if (oi.recursivelyMatches(Expression::IsRandom, reductionContext.context(), true)) { + if (oi.recursivelyMatches(Expression::IsRandom, context, true)) { // Do not factorize random or randint i++; continue; @@ -735,7 +737,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext /* Replacing sin/cos by tan factors may have mixed factors and factors are * guaranteed to be sorted (according ot SimplificationOrder) at the end of * shallowReduce */ - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); + sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); } /* Step 6: We remove rational children that appeared in the middle of sorted @@ -779,7 +781,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext const Expression c = childAtIndex(0); if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isZero()) { // Check that other children don't match inf or unit - bool infiniteOrUnitFactor = recursivelyMatches([](const Expression e, Context * context) { return Expression::IsInfinity(e,context) || e.type() == ExpressionNode::Type::Unit; }, reductionContext.context()); + bool infiniteOrUnitFactor = recursivelyMatches([](const Expression e, Context * context) { return Expression::IsInfinity(e,context) || e.type() == ExpressionNode::Type::Unit; }, context); if (!infiniteOrUnitFactor) { replaceWithInPlace(c); return c; @@ -798,7 +800,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * reduce expressions such as (x+y)^(-1)*(x+y)(a+b). * If there is a random somewhere, do not expand. */ Expression p = parent(); - bool hasRandom = recursivelyMatches(Expression::IsRandom, reductionContext.context(), true); + bool hasRandom = recursivelyMatches(Expression::IsRandom, context, true); if (shouldExpand && (p.isUninitialized() || p.type() != ExpressionNode::Type::Multiplication) && !hasRandom) @@ -825,7 +827,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * - All children are either real or ComplexCartesian (allChildrenAreReal == 0) * We can bubble up ComplexCartesian nodes. * Do not simplify if there are randoms !*/ - if (!hasRandom && allChildrenAreReal(reductionContext.context()) == 0) { + if (!hasRandom && allChildrenAreReal(context) == 0) { int nbChildren = numberOfChildren(); int i = nbChildren-1; // Children are sorted so ComplexCartesian nodes are at the end From da6306cb11b4cfc41e147a8c406316b6fe78fd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 13:39:39 +0100 Subject: [PATCH 109/117] [poincare/multiplication] Interrupt reduction if overflow When the overflow is due to the max size a rational can hold, stop the reduction, otherwise some false results can appear. For instance: 1.0092^50*ln(1.0092) was computed to 0 due to this problem --- poincare/src/multiplication.cpp | 8 ++++++++ poincare/test/approximation.cpp | 2 ++ 2 files changed, 10 insertions(+) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 0626833c6..63f2d35be 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -760,6 +760,14 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext if (childAtIndex(0).isNumber()) { Number o0 = childAtIndex(0).convert(); Number m = Number::Multiplication(o0, static_cast(o)); + if ((IsInfinity(m, context) || m.isUndefined()) + && !IsInfinity(o0, context) && !o0.isUndefined() + && !IsInfinity(o, context) && !o.isUndefined()) + { + // Stop the reduction due to a multiplication overflow + SetInterruption(true); + return *this; + } replaceChildAtIndexInPlace(0, m); removeChildAtIndexInPlace(i); } else { diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index d30412d34..723027d6e 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -941,8 +941,10 @@ QUIZ_CASE(poincare_approximation_mix) { assert_expression_simplifies_and_approximates_to("1.0092^(20)", "1.2010050593402"); assert_expression_simplifies_and_approximates_to("1.0092^(50)×ln(3/2)", "0.6409373488899", Degree, Cartesian, 13); + assert_expression_simplifies_and_approximates_to("1.0092^(50)×ln(1.0092)", "1.447637354655ᴇ-2", Degree, Cartesian, 13); assert_expression_approximates_to("1.0092^(20)", "1.2010050593402"); assert_expression_approximates_to("1.0092^(50)×ln(3/2)", "0.6409373488899", Degree, Cartesian, 13); + assert_expression_approximates_to("1.0092^(50)×ln(1.0092)", "1.447637354655ᴇ-2", Degree, Cartesian, 13); assert_expression_simplifies_approximates_to("1.0092^(20)", "1.2010050593402"); assert_expression_simplifies_approximates_to("1.0092^(50)×ln(3/2)", "0.6409373488899", Degree, Cartesian, 13); //assert_expression_approximates_to("1.0092^(20)", "1.201005"); TODO does not work From d222d131565d38a650b59c676dc34b53e9199733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 16 Mar 2020 11:20:25 +0100 Subject: [PATCH 110/117] [poincare] CHange name PowerNode::tryComputeRealRootOfRationalPow --> PowerNode::computeNotPrincipalRealRootOfRationalPow --- poincare/include/poincare/power.h | 2 +- poincare/src/nth_root.cpp | 2 +- poincare/src/power.cpp | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index 1f40e978f..77f2dda77 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -34,7 +34,7 @@ public: int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; - template static Complex tryComputeRealRootOfRationalPow(const std::complex c, T p, T q); + template static Complex computeNotPrincipalRealRootOfRationalPow(const std::complex c, T p, T q); template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat); private: diff --git a/poincare/src/nth_root.cpp b/poincare/src/nth_root.cpp index 3af471605..db4748a47 100644 --- a/poincare/src/nth_root.cpp +++ b/poincare/src/nth_root.cpp @@ -48,7 +48,7 @@ Evaluation NthRootNode::templatedApproximate(Context * context, Preferences:: * correspond to the principale angle. */ if (complexFormat == Preferences::ComplexFormat::Real && indexc.imag() == 0.0 && std::round(indexc.real()) == indexc.real()) { // root(x, q) with q integer and x real - Complex result = PowerNode::tryComputeRealRootOfRationalPow(basec, (T)1.0, indexc.real()); + Complex result = PowerNode::computeNotPrincipalRealRootOfRationalPow(basec, (T)1.0, indexc.real()); if (!result.isUndefined()) { return result; } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 712c5ab79..c7362383e 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -128,12 +128,14 @@ bool PowerNode::childAtIndexNeedsUserParentheses(const Expression & child, int c // Private template -Complex PowerNode::tryComputeRealRootOfRationalPow(const std::complex c, T p, T q) { +Complex PowerNode::computeNotPrincipalRealRootOfRationalPow(const std::complex c, T p, T q) { // Assert p and q are in fact integers assert(std::round(p) == p); assert(std::round(q) == q); - /* Try to find a real root of c^(p/q) with p, q integers. If none is found - * easily, return undefined -> this does not mean there is no real root. */ + /* Try to find a real root of c^(p/q) with p, q integers. We ignore cases + * where the principal root is real as these cases are handled generically + * later (for instance 1232^(1/8) which has a real principal root is not + * handled here). */ if (c.imag() == 0 && std::pow((T)-1.0, q) < 0.0) { /* If c real and q odd integer (q odd if (-1)^q = -1), a real root does * exist (which is not necessarily the principal root)! @@ -321,7 +323,7 @@ template Evaluation PowerNode::templatedApproximate(Context * con if (std::isnan(p) || std::isnan(q)) { goto defaultApproximation; } - Complex result = tryComputeRealRootOfRationalPow(c, p, q); + Complex result = computeNotPrincipalRealRootOfRationalPow(c, p, q); if (!result.isUndefined()) { return result; } From 5c70fdc7a604d68c60626f8a011db29e0777d0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 16 Mar 2020 10:05:22 +0100 Subject: [PATCH 111/117] [apps/probability] Handle a == b case in finite integral computation For non continuous distributions, P(a <= X <= a) is not necessarily null. --- apps/probability/distribution/distribution.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/probability/distribution/distribution.cpp b/apps/probability/distribution/distribution.cpp index ac0c8f517..20904073c 100644 --- a/apps/probability/distribution/distribution.cpp +++ b/apps/probability/distribution/distribution.cpp @@ -25,9 +25,12 @@ double Distribution::rightIntegralFromAbscissa(double x) const { } double Distribution::finiteIntegralBetweenAbscissas(double a, double b) const { - if (b <= a) { + if (b < a) { return 0.0; } + if (a == b) { + return evaluateAtDiscreteAbscissa(a); + } if (isContinuous()) { return cumulativeDistributiveFunctionAtAbscissa(b) - cumulativeDistributiveFunctionAtAbscissa(a); } From 29b4c7522737cd3ae37b83cca39a18c0cd7ac7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 16 Mar 2020 10:08:16 +0100 Subject: [PATCH 112/117] [apps/probability] Assert discrete distributions override evaluation --- apps/probability/distribution/distribution.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/probability/distribution/distribution.cpp b/apps/probability/distribution/distribution.cpp index 20904073c..aae3631d0 100644 --- a/apps/probability/distribution/distribution.cpp +++ b/apps/probability/distribution/distribution.cpp @@ -103,6 +103,7 @@ double Distribution::rightIntegralInverseForProbability(double * probability) { } double Distribution::evaluateAtDiscreteAbscissa(int k) const { + assert(isContinuous()); // Discrete distributions override this method return 0.0; } From e82849117187557e8b1aba04b0510e80666f0505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 16 Mar 2020 11:24:25 +0100 Subject: [PATCH 113/117] [apps/probability] Test on finite integral computations --- apps/probability/test/distributions.cpp | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/apps/probability/test/distributions.cpp b/apps/probability/test/distributions.cpp index 4cb4b5c84..20bd9d9f9 100644 --- a/apps/probability/test/distributions.cpp +++ b/apps/probability/test/distributions.cpp @@ -19,7 +19,13 @@ void assert_cumulative_distributive_function_direct_and_inverse_is(Probability:: quiz_assert(!std::isnan(r)); quiz_assert(!std::isinf(r)); quiz_assert(std::fabs(r-x) < FLT_EPSILON || std::fabs(r-x)/x < FLT_EPSILON); +} +void assert_finite_integral_between_abscissas_is(Probability::Distribution * distribution, double a, double b, double result) { + double r = distribution->finiteIntegralBetweenAbscissas(a, b); + quiz_assert(!std::isnan(r)); + quiz_assert(!std::isinf(r)); + quiz_assert(std::fabs(r-result) < FLT_EPSILON || std::fabs(r-result)/result < FLT_EPSILON); } //TODO other distributions @@ -37,6 +43,13 @@ QUIZ_CASE(binomial_distribution) { distribution.setParameterAtIndex(0.1, 1); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 0.0, 0.166771816996665822596668249389040283858776092529296875); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.0, 0.4817852491014791294077213024138472974300384521484375); + + // B(21, 0.2) + distribution.setParameterAtIndex(21.0, 0); + distribution.setParameterAtIndex(0.2, 1); + assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.21563235015849934848); + assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.398919847793223794688); } QUIZ_CASE(chi_squared_distribution) { @@ -58,6 +71,12 @@ QUIZ_CASE(chi_squared_distribution) { assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.3, 0.047059684573231390369851823152202996425330638885498046875); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.9874567, 0.250530060451470470983537097708904184401035308837890625); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 4.987, 0.53051693435084168459781039928202517330646514892578125); + + // Chi Squared distribution with 6 degrees of freedom + distribution.setParameterAtIndex(6.0, 0); + assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.1328633002997339414718); } QUIZ_CASE(student_distribution) { @@ -79,6 +98,12 @@ QUIZ_CASE(student_distribution) { assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, -4.987, 0.00167496657737900025118837898929768925881944596767425537109375); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.3, 0.876837383157582639370275501278229057788848876953125); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.9874567, 0.98612148076325445433809591122553683817386627197265625); + + // Student distribution with 6 degrees of freedom + distribution.setParameterAtIndex(6.0, 0); + assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.002333318101494775250); } QUIZ_CASE(geometric_distribution) { @@ -92,6 +117,12 @@ QUIZ_CASE(geometric_distribution) { distribution.setParameterAtIndex(0.2, 0); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 7.0, 0.8322278399999998299563230830244719982147216796875); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 3.0, 0.5904); + + // Geometric distribution with probability of success 0.4 + distribution.setParameterAtIndex(0.4, 0); + assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.24); + assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.384); } QUIZ_CASE(fisher_distribution) { @@ -115,4 +146,10 @@ QUIZ_CASE(fisher_distribution) { assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.4, 0.94560850441205857); assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.425, 0.95425004959692871775); + // Fisher distribution with d1 = 4 and d2 = 2 + distribution.setParameterAtIndex(4.0, 0); + distribution.setParameterAtIndex(2.0, 1); + assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0); + assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.19555555555555555); } From a8783fe21fb8c3eeef5cb4a56dabfd50596d89c3 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 8 Dec 2017 09:26:27 -0500 Subject: [PATCH 114/117] Remove a duplicate function, cleanup sorting and use consistent argument names in math.h. Add missing math.h tests and make each test a single line for easier comparison with math.h. Add missing cmath undefs and functions and use constexpr instead of static. --- liba/include/math.h | 44 ++++--- liba/test/math.c | 295 +++++++++++++------------------------------ libaxx/include/cmath | 178 ++++++++++++++++---------- 3 files changed, 228 insertions(+), 289 deletions(-) diff --git a/liba/include/math.h b/liba/include/math.h index 7fef24005..3cb95bcb5 100644 --- a/liba/include/math.h +++ b/liba/include/math.h @@ -35,13 +35,13 @@ typedef double double_t; #define FP_SUBNORMAL 0x08 #define FP_ZERO 0x10 -#define fpclassify(x) __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x) -#define signbit(x) __builtin_signbit(x) #define finite(x) __builtin_finite(x) +#define fpclassify(x) __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x) #define isfinite(x) __builtin_isfinite(x) #define isnormal(x) __builtin_isnormal(x) #define isnan(x) __builtin_isnan(x) #define isinf(x) __builtin_isinf(x) +#define signbit(x) __builtin_signbit(x) float acosf(float x); float acoshf(float x); @@ -60,19 +60,19 @@ float fabsf(float x); float fmaxf(float x, float y); float floorf(float x); float fmodf(float x, float y); -float frexpf(float x, int *eptr); +float frexpf(float x, int *exp); float hypotf(float x, float y); -float ldexpf(float x, int n); +float ldexpf(float x, int exp); float lgammaf(float x); float lgammaf_r(float x, int *signgamp); float log1pf(float x); float log10f(float x); float logf(float x); -float modff(float value, float *iptr); +float modff(float x, float *iptr); float nearbyintf(float x); float powf(float x, float y); float roundf(float x); -float scalbnf(float x, int n); +float scalbnf(float x, int exp); float sinf(float x); float sinhf(float x); float sqrtf(float x); @@ -99,7 +99,7 @@ double fabs(double x); double fmax(double x, double y); double floor(double x); double fmod(double x, double y); -double frexp(double x, int *eptr); +double frexp(double x, int *exp); double hypot(double x, double y); double lgamma(double x); double lgamma_r(double x, int *signgamp); @@ -108,14 +108,13 @@ double log1p(double x); double log10(double x); double log2(double x); double logb(double x); -double modf(double value, double *iptr); +double modf(double x, double *iptr); double nearbyint(double x); double pow(double x, double y); -double nearbyint(double x); double rint(double x); double round(double x); -double scalb(double x, double fn); -double scalbn(double x, int n); +double scalb(double x, double exp); +double scalbn(double x, int exp); double sin(double x); double sinh(double x); double sqrt(double x); @@ -124,6 +123,8 @@ double tanh(double x); double tgamma(double x); double trunc(double x); +extern int signgam; + /* The C99 standard says that any libc function can be re-declared as a macro. * (See N1124 paragraph 7.1.4). This means that C files willing to actually * implement said functions should either re-define the prototype or #undef the @@ -145,18 +146,19 @@ double trunc(double x); #define fabsf(x) __builtin_fabsf(x) #define floorf(x) __builtin_floorf(x) #define fmodf(x, y) __builtin_fmodf(x, y) -#define frexpf(x, y) __builtin_frexpf(x, y) -#define ldexpf(x, n) __builtin_ldexpf(x, n) +#define frexpf(x, exp) __builtin_frexpf(x, exp) +#define ldexpf(x, exp) __builtin_ldexpf(x, exp) #define lgammaf(x) __builtin_lgammaf(x) #define lgammaf_r(x, signgamp) __builtin_lgammaf_r(x, signgamp) #define log1pf(x) __builtin_log1pf(x) #define log10f(x) __builtin_log10f(x) #define logf(x) __builtin_logf(x) -#define nanf(s) __builtin_nanf(s) +#define modff(x, iptr) __builtin_modff(x, iptr) +#define nanf(tagp) __builtin_nanf(tagp) #define nearbyintf(x) __builtin_nearbyintf(x) #define powf(x, y) __builtin_powf(x, y) #define roundf(x) __builtin_roundf(x) -#define scalbnf(x, n) __builtin_scalbnf(x, n) +#define scalbnf(x, exp) __builtin_scalbnf(x, exp) #define sinf(x) __builtin_sinf(x) #define sinhf(x) __builtin_sinhf(x) #define sqrtf(x) __builtin_sqrtf(x) @@ -182,7 +184,8 @@ double trunc(double x); #define fabs(x) __builtin_fabs(x) #define floor(x) __builtin_floor(x) #define fmod(x, y) __builtin_fmod(x, y) -#define ldexp(x, n) __builtin_scalbn(x, n) +#define frexp(x, exp) __builtin_frexp(x, exp) +#define ldexp(x, exp) __builtin_scalbn(x, exp) #define lgamma(x) __builtin_lgamma(x) #define lgamma_r(x, signgamp) __builtin_lgamma_r(x, signgamp) #define log(x) __builtin_log(x) @@ -190,11 +193,14 @@ double trunc(double x); #define log10(x) __builtin_log10(x) #define log2(x) __builtin_log2(x) #define logb(x) __builtin_logb(x) -#define nan(s) __builtin_nan(s) +#define modf(x, iptr) __builtin_modf(x, iptr) +#define nan(tagp) __builtin_nan(tagp) +#define nearbyint(x) __builtin_nearbyint(x) #define pow(x, y) __builtin_pow(x, y) #define rint(x) __builtin_rint(x) #define round(x) __builtin_round(x) -#define scalbn(x, n) __builtin_scalbn(x, n) +#define scalb(x, exp) __builtin_scalb(x, exp) +#define scalbn(x, exp) __builtin_scalbn(x, exp) #define sin(x) __builtin_sin(x) #define sinh(x) __builtin_sinh(x) #define sqrt(x) __builtin_sqrt(x) @@ -203,8 +209,6 @@ double trunc(double x); #define tgamma(x) __builtin_tgamma(x) #define trunc(x) __builtin_trunc(x) -extern int signgam; - LIBA_END_DECLS #endif diff --git a/liba/test/math.c b/liba/test/math.c index 64f874df8..c09fc30f2 100644 --- a/liba/test/math.c +++ b/liba/test/math.c @@ -1,210 +1,97 @@ // This file tests that each math fuction links. #include -int test_fpclassifyf(float x) { - return fpclassify(x); -} -int test_isfinitef(float x) { - return isfinite(x); -} -int test_isnormalf(float x) { - return isnormal(x); -} -int test_isnanf(float x) { - return isnan(x); -} -int test_isinff(float x) { - return isinf(x); -} +int test_fpclassifyf(float x) { return fpclassify(x); } +int test_signbitf(float x) { return signbit(x); } +int test_finitef(float x) { return finite(x); } +int test_isfinitef(float x) { return isfinite(x); } +int test_isnormalf(float x) { return isnormal(x); } +int test_isnanf(float x) { return isnan(x); } +int test_isinff(float x) { return isinf(x); } -float test_acosf(float x) { - return acosf(x); -} -float test_acoshf(float x) { - return acoshf(x); -} -float test_asinf(float x) { - return asinf(x); -} -float test_asinhf(float x) { - return asinhf(x); -} -float test_atanf(float x) { - return atanf(x); -} -float test_atan2f(float y, float x) { - return atan2f(y, x); -} -float test_atanhf(float x) { - return atanhf(x); -} -float test_ceilf(float x) { - return ceilf(x); -} -float test_copysignf(float x, float y) { - return copysignf(x, y); -} -float test_cosf(float x) { - return cosf(x); -} -float test_coshf(float x) { - return coshf(x); -} -float test_expf(float x) { - return expf(x); -} -float test_expm1f(float x) { - return expm1f(x); -} -float test_fabsf(float x) { - return fabsf(x); -} -float test_floorf(float x) { - return floorf(x); -} -float test_fmodf(float x, float y) { - return fmodf(x, y); -} -float test_lgammaf(float x) { - return lgammaf(x); -} -float test_lgammaf_r(float x, int *signgamp) { - return lgammaf_r(x, signgamp); -} -float test_log1pf(float x) { - return log1pf(x); -} -float test_log10f(float x) { - return log10f(x); -} -float test_logf(float x) { - return logf(x); -} -float test_nanf(const char *s) { - return nanf(s); -} -float test_nearbyintf(float x) { - return nearbyintf(x); -} -float test_powf(float x, float y) { - return powf(x, y); -} -float test_roundf(float x) { - return roundf(x); -} -float test_scalbnf(float x, int n) { - return scalbnf(x, n); -} -float test_sinf(float x) { - return sinf(x); -} -float test_sinhf(float x) { - return sinhf(x); -} -float test_sqrtf(float x) { - return sqrtf(x); -} -float test_tanf(float x) { - return tanf(x); -} -float test_tanhf(float x) { - return tanhf(x); -} +float test_acosf(float x) { return acosf(x); } +float test_acoshf(float x) { return acoshf(x); } +float test_asinf(float x) { return asinf(x); } +float test_asinhf(float x) { return asinhf(x); } +float test_atanf(float x) { return atanf(x); } +float test_atan2f(float y, float x) { return atan2f(y, x); } +float test_atanhf(float x) { return atanhf(x); } +float test_ceilf(float x) { return ceilf(x); } +float test_copysignf(float x, float y) { return copysignf(x, y); } +float test_cosf(float x) { return cosf(x); } +float test_coshf(float x) { return coshf(x); } +float test_expf(float x) { return expf(x); } +float test_expm1f(float x) { return expm1f(x); } +float test_fabsf(float x) { return fabsf(x); } +float test_floorf(float x) { return floorf(x); } +float test_fmodf(float x, float y) { return fmodf(x, y); } +float test_frexpf(float x, int *exp) { return frexpf(x, exp); } +float test_ldexpf(float x, int exp) { return ldexpf(x, exp); } +float test_lgammaf(float x) { return lgammaf(x); } +float test_lgammaf_r(float x, int *signgamp) { return lgammaf_r(x, signgamp); } +float test_log1pf(float x) { return log1pf(x); } +float test_log10f(float x) { return log10f(x); } +float test_logf(float x) { return logf(x); } +float test_modff(float x, float *iptr) { return modff(x, iptr); } +float test_nanf(const char *s) { return nanf(s); } +float test_nearbyintf(float x) { return nearbyintf(x); } +float test_powf(float x, float y) { return powf(x, y); } +float test_roundf(float x) { return roundf(x); } +float test_scalbnf(float x, int exp) { return scalbnf(x, exp); } +float test_sinf(float x) { return sinf(x); } +float test_sinhf(float x) { return sinhf(x); } +float test_sqrtf(float x) { return sqrtf(x); } +float test_tanf(float x) { return tanf(x); } +float test_tanhf(float x) { return tanhf(x); } +float test_truncf(float x) { return truncf(x); } -int test_fpclassify(double x) { - return fpclassify(x); -} -int test_isfinite(double x) { - return isfinite(x); -} -int test_isnormal(double x) { - return isnormal(x); -} -int test_isnan(double x) { - return isnan(x); -} -int test_isinf(double x) { - return isinf(x); -} +int test_fpclassify(double x) { return fpclassify(x); } +int test_signbit(double x) { return signbit(x); } +int test_finite(double x) { return finite(x); } +int test_isfinite(double x) { return isfinite(x); } +int test_isnormal(double x) { return isnormal(x); } +int test_isnan(double x) { return isnan(x); } +int test_isinf(double x) { return isinf(x); } -double test_acos(double x) { - return acos(x); -} -double test_acosh(double x) { - return acosh(x); -} -double test_asin(double x) { - return asin(x); -} -double test_asinh(double x) { - return asinh(x); -} -double test_atan(double x) { - return atan(x); -} -double test_atanh(double x) { - return atanh(x); -} -double test_ceil(double x) { - return ceil(x); -} -double test_copysign(double x, double y) { - return copysign(x, y); -} -double test_cos(double x) { - return cos(x); -} -double test_cosh(double x) { - return cosh(x); -} -double test_exp(double x) { - return exp(x); -} -double test_expm1(double x) { - return expm1(x); -} -double test_fabs(double x) { - return fabs(x); -} -double test_floor(double x) { - return floor(x); -} -double test_lgamma(double x) { - return lgamma(x); -} -double test_lgamma_r(double x, int *signgamp) { - return lgamma_r(x, signgamp); -} -double test_log1p(double x) { - return log1p(x); -} -double test_log10(double x) { - return log10(x); -} -double test_log(double x) { - return log(x); -} -double test_pow(double x, double y) { - return pow(x, y); -} -double test_round(double x) { - return round(x); -} -double test_scalbn(double x, int n) { - return scalbn(x, n); -} -double test_sin(double x) { - return sin(x); -} -double test_sinh(double x) { - return sinh(x); -} -double test_sqrt(double x) { - return sqrt(x); -} -double test_tan(double x) { - return tan(x); -} -double test_tanh(double x) { - return tanh(x); -} +double test_acos(double x) { return acos(x); } +double test_acosh(double x) { return acosh(x); } +double test_asin(double x) { return asin(x); } +double test_asinh(double x) { return asinh(x); } +double test_atan(double x) { return atan(x); } +double test_atan2(double y, double x) { return atan2(y, x); } +double test_atanh(double x) { return atanh(x); } +double test_ceil(double x) { return ceil(x); } +double test_copysign(double x, double y) { return copysign(x, y); } +double test_cos(double x) { return cos(x); } +double test_cosh(double x) { return cosh(x); } +double test_erf(double x) { return erf(x); } +double test_erfc(double x) { return erfc(x); } +double test_exp(double x) { return exp(x); } +double test_expm1(double x) { return expm1(x); } +double test_fabs(double x) { return fabs(x); } +double test_floor(double x) { return floor(x); } +double test_fmod(double x, double y) { return fmod(x, y); } +double test_frexp(double x, int *exp) { return frexp(x, exp); } +double test_ldexp(double x, int exp) { return ldexp(x, exp); } +double test_lgamma(double x) { return lgamma(x); } +double test_lgamma_r(double x, int *signgamp) { return lgamma_r(x, signgamp); } +double test_log(double x) { return log(x); } +double test_log1p(double x) { return log1p(x); } +double test_log10(double x) { return log10(x); } +double test_log2(double x) { return log2(x); } +double test_logb(double x) { return logb(x); } +double test_modf(double x, double *iptr) { return modf(x, iptr); } +double test_nan(const char *s) { return nan(s); } +double test_nearbyint(double x) { return nearbyint(x); } +double test_pow(double x, double y) { return pow(x, y); } +double test_rint(double x) { return rint(x); } +double test_round(double x) { return round(x); } +double test_scalb(double x, double exp) { return scalb(x, exp); } +double test_scalbn(double x, int exp) { return scalbn(x, exp); } +double test_sin(double x) { return sin(x); } +double test_sinh(double x) { return sinh(x); } +double test_sqrt(double x) { return sqrt(x); } +double test_tan(double x) { return tan(x); } +double test_tanh(double x) { return tanh(x); } +double test_tgamma(double x) { return tgamma(x); } +double test_trunc(double x) { return trunc(x); } diff --git a/libaxx/include/cmath b/libaxx/include/cmath index e3c7835e2..6a3e3894e 100644 --- a/libaxx/include/cmath +++ b/libaxx/include/cmath @@ -3,11 +3,13 @@ #include +#undef finite #undef fpclassify #undef isfinite #undef isnormal #undef isnan #undef isinf +#undef signbit #undef acosf #undef acoshf @@ -26,12 +28,15 @@ #undef fmaxf #undef floorf #undef fmodf +#undef frexpf #undef hypotf +#undef ldexpf #undef lgammaf #undef lgammaf_r #undef log1pf #undef log10f #undef logf +#undef modff #undef nanf #undef nearbyintf #undef powf @@ -42,12 +47,14 @@ #undef sqrtf #undef tanf #undef tanhf +#undef truncf #undef acos #undef acosh #undef asin #undef asinh #undef atan +#undef atan2 #undef atanh #undef ceil #undef copysign @@ -61,88 +68,129 @@ #undef fmax #undef floor #undef fmod +#undef frexp #undef hypot +#undef ldexp #undef lgamma #undef lgamma_r +#undef log #undef log1p #undef log10 -#undef log +#undef log2 +#undef logb +#undef modf +#undef nan +#undef nearbyint #undef pow +#undef rint #undef round +#undef scalb #undef scalbn #undef sin #undef sinh #undef sqrt #undef tan #undef tanh +#undef tgamma +#undef trunc namespace std { +inline constexpr int fpclassify(float x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x); } +inline constexpr bool isfinite(float x) { return __builtin_isfinite(x); } +inline constexpr bool isinf(float x) { return __builtin_isinf(x); } +inline constexpr bool isnan(float x) { return __builtin_isnan(x); } +inline constexpr bool isnormal(float x) { return __builtin_isnormal(x); } +inline constexpr bool signbit(float x) { return __builtin_signbit(x); } -static inline double acos(double x) { return __builtin_acos(x); } -static inline float acos(float x) { return __builtin_acosf(x); } -static inline double acosh(double x) { return __builtin_acosh(x); } -static inline float acosh(float x) { return __builtin_acoshf(x); } -static inline double asin(double x) { return __builtin_asin(x); } -static inline float asin(float x) { return __builtin_asinf(x); } -static inline double asinh(double x) { return __builtin_asinh(x); } -static inline float asinh(float x) { return __builtin_asinhf(x); } -static inline double atan(double x) { return __builtin_atan(x); } -static inline float atan(float x) { return __builtin_atanf(x); } -static inline double atanh(double x) { return __builtin_atanh(x); } -static inline float atanh(float x) { return __builtin_atanhf(x); } -static inline double ceil(double x) { return __builtin_ceil(x); } -static inline float ceil(float x) { return __builtin_ceilf(x); } -static inline double copysign(double x, double y) { return __builtin_copysign(x, y); } -static inline float copysign(float x, float y) { return __builtin_copysignf(x, y); } -static inline double cos(double x) { return __builtin_cos(x); } -static inline float cos(float x) { return __builtin_cosf(x); } -static inline double cosh(double x) { return __builtin_cosh(x); } -static inline float cosh(float x) { return __builtin_coshf(x); } -static inline double erf(double x) { return __builtin_erf(x); } -static inline double erfc(double x) { return __builtin_erfc(x); } -static inline double exp(double x) { return __builtin_exp(x); } -static inline float exp(float x) { return __builtin_expf(x); } -static inline double fabs(double x) { return __builtin_fabs(x); } -static inline float fabs(float x) { return __builtin_fabsf(x); } -static inline double fmax(double x, double y) { return __builtin_fmax(x, y); } -static inline float fmax(float x, float y) { return __builtin_fmaxf(x, y); } -static inline double floor(double x) { return __builtin_floor(x); } -static inline float floor(float x) { return __builtin_floorf(x); } -static inline double fmod(double x, double y) { return __builtin_fmod(x, y); } -static inline float fmod(float x, float y) { return __builtin_fmodf(x, y); } -static inline int fpclassify(double x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x); } -static inline int fpclassify(float x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x); } -static inline double hypot(double x, double y) { return __builtin_hypot(x, y); } -static inline float hypotf(float x, float y) { return __builtin_hypotf(x, y); } -static inline bool isfinite(double x) { return __builtin_isfinite(x); } -static inline bool isfinite(float x) { return __builtin_isfinite(x); } -static inline bool isinf(double x) { return __builtin_isinf(x); } -static inline bool isinf(float x) { return __builtin_isinf(x); } -static inline bool isnan(double x) { return __builtin_isnan(x); } -static inline bool isnan(float x) { return __builtin_isnan(x); } -static inline bool isnormal(double x) { return __builtin_isnormal(x); } -static inline bool isnormal(float x) { return __builtin_isnormal(x); } -static inline double lgamma(double x) { return __builtin_lgamma(x); } -static inline float lgamma(float x) { return __builtin_lgammaf(x); } -static inline double log10(double x) { return __builtin_log10(x); } -static inline float log10(float x) { return __builtin_log10f(x); } -static inline double log(double x) { return __builtin_log(x); } -static inline float log(float x) { return __builtin_logf(x); } -static inline double pow(double x, double y) { return __builtin_pow(x, y); } -static inline float pow(float x, float y) { return __builtin_powf(x, y); } -static inline double round(double x) { return __builtin_round(x); } -static inline float round(float x) { return __builtin_roundf(x); } -static inline double sin(double x) { return __builtin_sin(x); } -static inline float sin(float x) { return __builtin_sinf(x); } -static inline double sinh(double x) { return __builtin_sinh(x); } -static inline float sinh(float x) { return __builtin_sinhf(x); } -static inline double sqrt(double x) { return __builtin_sqrt(x); } -static inline float sqrt(float x) { return __builtin_sqrtf(x); } -static inline double tan(double x) { return __builtin_tan(x); } -static inline float tan(float x) { return __builtin_tanf(x); } -static inline double tanh(double x) { return __builtin_tanh(x); } -static inline float tanh(float x) { return __builtin_tanhf(x); } +inline constexpr float acos(float x) { return __builtin_acosf(x); } +inline constexpr float acosh(float x) { return __builtin_acoshf(x); } +inline constexpr float asin(float x) { return __builtin_asinf(x); } +inline constexpr float asinh(float x) { return __builtin_asinhf(x); } +inline constexpr float atan(float x) { return __builtin_atanf(x); } +inline constexpr float atan2(float y, float x) { return __builtin_atan2f(y, x); } +inline constexpr float atanh(float x) { return __builtin_atanhf(x); } +inline constexpr float ceil(float x) { return __builtin_ceilf(x); } +inline constexpr float copysign(float x, float y) { return __builtin_copysignf(x, y); } +inline constexpr float cos(float x) { return __builtin_cosf(x); } +inline constexpr float cosh(float x) { return __builtin_coshf(x); } +inline constexpr float exp(float x) { return __builtin_expf(x); } +inline constexpr float expm1(float x) { return __builtin_expm1f(x); } +inline constexpr float fabs(float x) { return __builtin_fabsf(x); } +inline constexpr float floor(float x) { return __builtin_floorf(x); } +inline constexpr float fmax(float x, float y) { return __builtin_fmaxf(x, y); } +inline constexpr float fmod(float x, float y) { return __builtin_fmodf(x, y); } +inline constexpr float frexp(float x, int *exp) { return __builtin_frexpf(x, exp); } +inline constexpr float ldexp(float x, int exp) { return __builtin_ldexpf(x, exp); } +inline constexpr float lgamma(float x) { return __builtin_lgammaf(x); } +inline constexpr float lgamma_r(float x, int *signgamp) { return __builtin_lgammaf_r(x, signgamp); } +inline constexpr float log1p(float x) { return __builtin_log1pf(x); } +inline constexpr float log10(float x) { return __builtin_log10f(x); } +inline constexpr float log(float x) { return __builtin_logf(x); } +inline constexpr float modf(float x, float *iptr) { return __builtin_modff(x, iptr); } +inline constexpr float nanf(const char *tagp) { return __builtin_nanf(tagp); } +inline constexpr float nearbyint(float x) { return __builtin_nearbyintf(x); } +inline constexpr float pow(float x, float y) { return __builtin_powf(x, y); } +inline constexpr float round(float x) { return __builtin_roundf(x); } +inline constexpr float scalbn(float x, int exp) { return __builtin_scalbnf(x, exp); } +inline constexpr float sin(float x) { return __builtin_sinf(x); } +inline constexpr float sinh(float x) { return __builtin_sinhf(x); } +inline constexpr float sqrt(float x) { return __builtin_sqrtf(x); } +inline constexpr float tan(float x) { return __builtin_tanf(x); } +inline constexpr float tanh(float x) { return __builtin_tanhf(x); } +inline constexpr float trunc(float x) { return __builtin_truncf(x); } + +inline constexpr int fpclassify(double x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x); } +inline constexpr bool isfinite(double x) { return __builtin_isfinite(x); } +inline constexpr bool isinf(double x) { return __builtin_isinf(x); } +inline constexpr bool isnan(double x) { return __builtin_isnan(x); } +inline constexpr bool isnormal(double x) { return __builtin_isnormal(x); } +inline constexpr bool signbit(double x) { return __builtin_signbit(x); } + +inline constexpr double acos(double x) { return __builtin_acos(x); } +inline constexpr double acosh(double x) { return __builtin_acosh(x); } +inline constexpr double asin(double x) { return __builtin_asin(x); } +inline constexpr double asinh(double x) { return __builtin_asinh(x); } +inline constexpr double atan(double x) { return __builtin_atan(x); } +inline constexpr double atan2(double y, double x) { return __builtin_atan2(y, x); } +inline constexpr double atanh(double x) { return __builtin_atanh(x); } +inline constexpr double ceil(double x) { return __builtin_ceil(x); } +inline constexpr double copysign(double x, double y) { return __builtin_copysign(x, y); } +inline constexpr double cos(double x) { return __builtin_cos(x); } +inline constexpr double cosh(double x) { return __builtin_cosh(x); } +inline constexpr double erf(double x) { return __builtin_erf(x); } +inline constexpr double erfc(double x) { return __builtin_erfc(x); } +inline constexpr double exp(double x) { return __builtin_exp(x); } +inline constexpr double expm1(double x) { return __builtin_expm1(x); } +inline constexpr double fabs(double x) { return __builtin_fabs(x); } +inline constexpr double floor(double x) { return __builtin_floor(x); } +inline constexpr double fmax(double x, double y) { return __builtin_fmax(x, y); } +inline constexpr double fmod(double x, double y) { return __builtin_fmod(x, y); } +inline constexpr double frexp(double x, int *exp) { return __builtin_frexp(x, exp); } +inline constexpr double hypot(double x, double y) { return __builtin_hypot(x, y); } +inline constexpr double ldexp(double x, int exp) { return __builtin_scalbn(x, exp); } +inline constexpr double lgamma(double x) { return __builtin_lgamma(x); } +inline constexpr double lgamma_r(double x, int *signgamp) { return __builtin_lgamma_r(x, signgamp); } +inline constexpr double log(double x) { return __builtin_log(x); } +inline constexpr double log1p(double x) { return __builtin_log1p(x); } +inline constexpr double log10(double x) { return __builtin_log10(x); } +inline constexpr double log2(double x) { return __builtin_log2(x); } +inline constexpr double logb(double x) { return __builtin_logb(x); } +inline constexpr double modf(double x, double *iptr) { return __builtin_modf(x, iptr); } +inline constexpr double nan(const char *tagp) { return __builtin_nan(tagp); } +inline constexpr double nearbyint(double x) { return __builtin_nearbyint(x); } +inline constexpr double pow(double x, double y) { return __builtin_pow(x, y); } +inline constexpr double rint(double x) { return __builtin_rint(x); } +inline constexpr double round(double x) { return __builtin_round(x); } +inline constexpr double scalb(double x, double exp) { return __builtin_scalb(x, exp); } +inline constexpr double scalbn(double x, int exp) { return __builtin_scalbn(x, exp); } +inline constexpr double sin(double x) { return __builtin_sin(x); } +inline constexpr double sinh(double x) { return __builtin_sinh(x); } +inline constexpr double sqrt(double x) { return __builtin_sqrt(x); } +inline constexpr double tan(double x) { return __builtin_tan(x); } +inline constexpr double tanh(double x) { return __builtin_tanh(x); } +inline constexpr double tgamma(double x) { return __builtin_tgamma(x); } +inline constexpr double trunc(double x) { return __builtin_trunc(x); } } From d2f40130b224668614d28a3b204c89b9e37c4e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 16 Mar 2020 17:51:47 +0100 Subject: [PATCH 115/117] [build] Change folder name: stable_release --> all_official --- build/targets.all.mak | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build/targets.all.mak b/build/targets.all.mak index 989c4fb7b..be798beb3 100644 --- a/build/targets.all.mak +++ b/build/targets.all.mak @@ -29,32 +29,32 @@ all_official: $(call file_check,$(ANDROID_GRADLE_PROPERTIES)) $(call file_check,$(IOS_MOBILE_PROVISION)) $(call command_check,$(EMCC)) - $(Q) rm -rf output/stable_release - $(Q) mkdir -p output/stable_release + $(Q) rm -rf output/all_official + $(Q) mkdir -p output/all_official $(Q) echo "BUILD_FIRMWARE DEVICE N0110" $(Q) $(MAKE) clean $(Q) $(MAKE) epsilon.official.onboarding.dfu - $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu + $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0110.dfu $(Q) echo "BUILD_FIRMWARE DEVICE N0100" $(Q) $(MAKE) MODEL=n0100 clean $(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu - $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu + $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0100.dfu $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP" $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip - $(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip + $(Q) cp output/release/simulator/web/simulator.official.zip output/all_official/simulator.web.zip $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js - $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.js $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js - $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.python.js $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" $(Q) $(MAKE) PLATFORM=simulator TARGET=android clean $(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk - $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk + $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/all_official/epsilon.apk $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" $(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa - $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa + $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/all_official/epsilon.ipa From 8c370b409c2e66146635ae9b81b2f7a680ec647e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 16 Mar 2020 17:52:20 +0100 Subject: [PATCH 116/117] [build] Add the .mem files to all_official/ --- build/targets.all.mak | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/targets.all.mak b/build/targets.all.mak index be798beb3..39f2dddea 100644 --- a/build/targets.all.mak +++ b/build/targets.all.mak @@ -46,10 +46,12 @@ all_official: $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js $(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.js + $(Q) cp output/release/simulator/web/epsilon.official.js.mem output/all_official/epsilon.js.mem $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js $(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.python.js + $(Q) cp output/release/simulator/web/epsilon.official.js.mem output/all_official/epsilon.python.js.mem $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" $(Q) $(MAKE) PLATFORM=simulator TARGET=android clean $(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk From 5f8f1d96eeb4ccfa27a40947292703dc4d5c54a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 16 Mar 2020 17:52:41 +0100 Subject: [PATCH 117/117] [build] Actually use the mobileprovision file stored in build/artifacts/ --- build/targets.all.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/targets.all.mak b/build/targets.all.mak index 39f2dddea..e6d989add 100644 --- a/build/targets.all.mak +++ b/build/targets.all.mak @@ -58,5 +58,5 @@ all_official: $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/all_official/epsilon.apk $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" $(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean - $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE=$(IOS_MOBILE_PROVISION) output/release/simulator/ios/app/epsilon.official.ipa $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/all_official/epsilon.ipa