diff --git a/spec/mock_jasmine.ts b/spec/mock_jasmine.ts index 8f03ee968fd9695c3b0ce6b1619a724d6b577bfb..2ba5f986c0158e410e0ab085db02e0cb5eb59786 100644 --- a/spec/mock_jasmine.ts +++ b/spec/mock_jasmine.ts @@ -98,6 +98,16 @@ class Expect { console.error(message); } } + + public toBeUndefined(message?: string) { + if (this.actual !== undefined) { + if (message === undefined) { + console.error(message); + } else { + console.error(this.actual + " should be undefined"); + } + } + } } /** diff --git a/spec/regime_uniforme/regime_uniforme_puissance.spec.ts b/spec/regime_uniforme/regime_uniforme_puissance.spec.ts index 37ec2a7ef51c66176e8686675f96ac5875c9dac0..f6088e27c8fcbf41c97d7348fb1cdaa4b23be48b 100644 --- a/spec/regime_uniforme/regime_uniforme_puissance.spec.ts +++ b/spec/regime_uniforme/regime_uniforme_puissance.spec.ts @@ -1,12 +1,17 @@ -// tslint:disable-next-line:no-reference -/// <reference path="../../node_modules/@types/jasmine/index.d.ts" /> +/** + * IMPORTANT ! + * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine") + * Pour exécuter ce code dans le débugger. + * Faire de même avec le fichier test_func.ts + */ +// import { describe, expect, it, xdescribe } from "../mock_jasmine"; -import { Result } from "../../src/util/result"; import { RegimeUniforme } from "../../src/regime_uniforme"; import { cSnPuiss, ParamsSectionPuiss } from "../../src/section/section_puissance"; import { MessageCode } from "../../src/util/message"; -import { equalEpsilon, checkResult } from "../test_func"; -import { precDist, precDigits } from "../test_config"; +import { Result } from "../../src/util/result"; +import { precDigits, precDist } from "../test_config"; +import { checkResult } from "../test_func"; describe("Class RegimeUniforme / section puissance :", () => { describe("pas de débordement :", () => { diff --git a/src/base.ts b/src/base.ts index 4365b942d68073c04d6fc6d7a26abd39a54cf317..f74f97a4a38d112ac8224622d167b277c5de2fd1 100644 --- a/src/base.ts +++ b/src/base.ts @@ -16,6 +16,7 @@ export class Serie { * @note Etendre cette classe pour toutes les classes à debugguer * Dans le constructeur, utiliser super(true) pour debugger la classe, super(false) sinon. */ +// tslint:disable-next-line:max-classes-per-file export abstract class Debug { /** * @param _DBG Flag de débuggage @@ -27,13 +28,13 @@ export abstract class Debug { * @param s Message à afficher dans la console */ public debug(s: any) { - if (this._DBG) console.log(s); + // tslint:disable-next-line:no-console + if (this._DBG) { console.log(s); } } get DBG() { return this._DBG; } } - /** * Méthode simulant l'opérateur booléen xor * @see http://www.howtocreate.co.uk/xor.html @@ -49,16 +50,12 @@ export function BoolIdentity(a: boolean, b: boolean): boolean { return (a && b) || (!a && !b); } - /** * arrondi d'un nombre avec une précision donnée * @param val nombre à arrondir * @param prec nombre de chiffres */ export function round(val: number, prec: number) { - let m = Math.pow(10, prec || 0); + const m = Math.pow(10, prec || 0); return Math.round(val * m) / m; } - -// export class UndefinedError extends Error { -// } diff --git a/src/dichotomie.ts b/src/dichotomie.ts index 55e4b48a2740ff685d6bd1ff703c68ce5adb3ef1..3b79383e8da773e92fc5548fbdd54d32f2573b08 100644 --- a/src/dichotomie.ts +++ b/src/dichotomie.ts @@ -1,12 +1,11 @@ // import { XOR, BoolIdentity, Debug, Result, ResultCode, UndefinedError } from "./base"; -import { XOR, BoolIdentity, Debug } from "./base"; -import { Result } from "./util/result"; -import { Message, MessageCode } from "./util/message"; +import { BoolIdentity, Debug, XOR } from "./base"; import { Nub } from "./nub"; -import { ParamDefinition, ParamDomain, ParamDomainValue } from "./param" -import { Pair } from "./util/pair"; +import { ParamDefinition, ParamDomain, ParamDomainValue } from "./param"; import { Interval } from "./util/interval"; - +import { Message, MessageCode } from "./util/message"; +import { Pair } from "./util/pair"; +import { Result } from "./util/result"; class SearchInterval extends Interval { private _step: number; @@ -17,21 +16,21 @@ class SearchInterval extends Interval { constructor(d: Dichotomie, min: number, max: number, s: number) { super(min, max); - if (s == 0) { - let e = new Message(MessageCode.ERROR_DICHO_NULL_STEP); + if (s === 0) { + const e = new Message(MessageCode.ERROR_DICHO_NULL_STEP); throw e; } this._step = s; this._dicho = d; } - reverse() { + public reverse() { this._step = -this._step; } - growStep(k: number) { - if (k == 0) { - let e = new Message(MessageCode.ERROR_DICHO_INVALID_STEP_GROWTH); + public growStep(k: number) { + if (k === 0) { + const e = new Message(MessageCode.ERROR_DICHO_INVALID_STEP_GROWTH); throw e; } this._step *= k; @@ -42,22 +41,12 @@ class SearchInterval extends Interval { } get targets() { - if (this._targets == undefined) + if (this._targets === undefined) { this._targets = new Pair(undefined, undefined); + } return this._targets; } - private updateTargets() { - let t1 = this.targets.val1; - if (t1 == undefined) - t1 = this._dicho.CalculX(this._val1).vCalc - - let t2 = this.targets.val2; - if (t2 == undefined) - t2 = this._dicho.CalculX(this._val2).vCalc; - this.targets.setValues(t1, t2); - } - /** * get target value for lower bound */ @@ -74,35 +63,49 @@ class SearchInterval extends Interval { return this.targets.val2; } - next() { + public next() { if (this._step > 0) { this._val1 = this._val2; this._val2 += this._step; this.targets.setValues(this.targets.val2, undefined); - } - else { + } else { this._val2 = this._val1; this._val1 += this._step; this.targets.setValues(undefined, this.targets.val1); } } - hasTargetValue(targ: number) { + public hasTargetValue(targ: number) { this.updateTargets(); return this.targets.intervalHasValue(targ); } - toString(): string { + public toString(): string { return super.toString() + " step=" + this._step; } -} + private updateTargets() { + let t1 = this.targets.val1; + if (t1 === undefined) { + t1 = this._dicho.CalculX(this._val1).vCalc; + } + + let t2 = this.targets.val2; + if (t2 === undefined) { + t2 = this._dicho.CalculX(this._val2).vCalc; + } + this.targets.setValues(t1, t2); + } + +} /** * calcul par dichotomie - * principe : y=f(x1,x2,...), on connait une valeur de y, on cherche par ex le x2 correspondant, les autres xi étant fixés. + * principe : y=f(x1,x2,...), on connait une valeur de y, + * on cherche par ex le x2 correspondant, les autres xi étant fixés. * la méthode Equation() calcule analytiquement y=f(xi) */ +// tslint:disable-next-line:max-classes-per-file export class Dichotomie extends Debug { /** * définition de la variable de la fonction @@ -120,18 +123,19 @@ export class Dichotomie extends Debug { private analyticalSymbol: string; /** - * Construction de la classe. - * @param nub Noeud de calcul contenant la méthode de calcul Equation - * @param sVarCalc Nom de la variable à calculer - * @param targetSymbol nom du paramètre calculé analytiquement par Equation() - */ - constructor(private nub: Nub, private sVarCalc: string, dbg: boolean = false, targetSymbol: string = undefined) { + * Construction de la classe. + * @param nub Noeud de calcul contenant la méthode de calcul Equation + * @param sVarCalc Nom de la variable à calculer + * @param targetSymbol nom du paramètre calculé analytiquement par Equation() + */ + constructor(private nub: Nub, private sVarCalc: string, dbg: boolean = false, targetSymbol?: string) { super(dbg); this._paramX = this.nub.getParameter(this.sVarCalc); - if (targetSymbol == undefined) + if (targetSymbol === undefined) { this.analyticalSymbol = this.nub.getFirstAnalyticalParameter().symbol; - else + } else { this.analyticalSymbol = targetSymbol; + } } /** @@ -156,6 +160,40 @@ export class Dichotomie extends Debug { this._startIntervalMaxSteps = n; } + public CalculX(x: number): Result { + this.vX = x; + return this.Calcul(); + } + + /** + * trouve la valeur x pour y=f(x) avec un y donné + * @param rTarget valeur de y + * @param rTol tolérance pour l'arrêt de la recherche + * @param rInit valeur initiale approximative de x + */ + public Dichotomie(rTarget: number, rTol: number, rInit: number): Result { + // console.log("-----"); + // for (let x = 0; x <= 1; x += 0.1) + // console.log(this.CalculX(x).vCalc); + // console.log("-----"); + + // recherche de l'intervalle de départ + + this.debug( + "Dichotomie : valeur cible de " + this.analyticalSymbol + "=" + rTarget + + ", valeur initiale de " + this.sVarCalc + "=" + rInit + ); + + const r = this.getStartInterval(rTarget, rInit); + if (r.ok) { + const interv: SearchInterval = r.intSearch; + // Dichotomie + return this.dichoSearch(rTarget, rTol, interv.min, interv.max, interv.targetLower, interv.targetUpper); + } else { + return new Result(r.res); + } + } + /** * Calcul de l'équation analytique. * @note Wrapper vers this.nub.Equation pour simplifier le code. @@ -163,28 +201,25 @@ export class Dichotomie extends Debug { * Il faudra s'assurer que cette première variable correspond à la méthode de calcul la plus rapide */ private Calcul(): Result { - let r: Result = this.nub.Equation(this.analyticalSymbol); - this.debug("dicho : Calcul(vX=" + this.sVarCalc + "=" + this.vX + ") -> " + this.analyticalSymbol + "=" + r.vCalc); + const r: Result = this.nub.Equation(this.analyticalSymbol); + this.debug( + "dicho : Calcul(vX=" + this.sVarCalc + "=" + this.vX + ") -> " + + this.analyticalSymbol + "=" + r.vCalc); return r; } - CalculX(x: number): Result { - this.vX = x - return this.Calcul(); - } - /** * Détermine si une fonction est croissante ou décroissante. * @param x point auquel on calcul la dérivée * @param dom domaine de définition de la variable */ private isIncreasingFunction(x: number, dom: Interval): boolean { - let epsilon = 1e-8; - let bounds = new Interval(x - epsilon, x + epsilon); + const epsilon = 1e-8; + const bounds = new Interval(x - epsilon, x + epsilon); bounds.setBounds(bounds.intersect(dom)); // au cas où l'on sorte du domaine de la variable de la fonction - let y1 = this.CalculX(bounds.min).vCalc; - let y2 = this.CalculX(bounds.max).vCalc; + const y1 = this.CalculX(bounds.min).vCalc; + const y2 = this.CalculX(bounds.max).vCalc; return y2 > y1; } @@ -200,9 +235,10 @@ export class Dichotomie extends Debug { let n = 0; let ok: boolean = false; do { - var inters: Interval = intSearch.intersect(intMax); - if (inters.length == 0) + const inters: Interval = intSearch.intersect(intMax); + if (inters.length === 0) { break; + } intSearch.setBounds(inters); if (intSearch.hasTargetValue(rTarget)) { ok = true; @@ -223,79 +259,73 @@ export class Dichotomie extends Debug { private getStartInterval(rTarget: number, rInit: number): any { this.debug("intervalle de départ"); - let prmDom: ParamDomain = this._paramX.getDomain(); - let step = 0.001; + const prmDom: ParamDomain = this._paramX.getDomain(); + const step = 0.001; - let min, max; - switch (prmDom.domain) { - case ParamDomainValue.INTERVAL: - min = prmDom.minValue; - max = prmDom.maxValue; - break; - - case ParamDomainValue.NOT_NULL: - if (rInit == 0) - rInit = 1e-8; - // pas de break - - default: - let a = ParamDomain.getDefaultBounds(prmDom.domain); - min = a.min; - max = a.max; + const min: number = prmDom.minValue; + const max: number = prmDom.maxValue; + if (prmDom.domain === ParamDomainValue.NOT_NULL) { + if (rInit === 0) { + rInit = 1e-8; + } } - let intMax: Interval = new Interval(min, max); + const intMax: Interval = new Interval(min, max); try { intMax.checkValue(rInit); - } - catch (m) { - return { ok: false, "res": m }; + } catch (m) { + return { ok: false, res: m }; } // initialisation de l'intervalle de recherche let intSearch: SearchInterval = new SearchInterval(this, rInit - step / 2, rInit + step / 2, step); - intSearch.setBounds(intSearch.intersect(intMax)); // au cas où l'on sorte du domaine de la variable de la fonction + // au cas où l'on sorte du domaine de la variable de la fonction + intSearch.setBounds(intSearch.intersect(intMax)); // sens de variation de la fonction - let inc = this.isIncreasingFunction(rInit, intMax); + const inc = this.isIncreasingFunction(rInit, intMax); - let initTarget = this.CalculX(rInit).vCalc; + const initTarget = this.CalculX(rInit).vCalc; // if (initTarget > rTarget && inc || initTarget < rTarget && !inc) - if (BoolIdentity(initTarget > rTarget, inc)) - intSearch.reverse(); // par ex, la fonction est croissante et la valeur initiale de la variable a une image par la fonction > valeur cible + if (BoolIdentity(initTarget > rTarget, inc)) { + intSearch.reverse(); + // par ex, la fonction est croissante et la valeur initiale + // de la variable a une image par la fonction > valeur cible + } // on cherche dans une première direction let a = this.searchTarget(rTarget, intSearch, intMax); - if (a.ok) + if (a.ok) { return a; + } // il se peut que la fonction ne soit pas monotone et qu'il faille chercher dans l'autre direction - let oldStepSign = intSearch.step > 0 ? 1 : -1; + const oldStepSign = intSearch.step > 0 ? 1 : -1; intSearch = new SearchInterval(this, rInit + step / 2, rInit + step, step * -oldStepSign); - intSearch.setBounds(intSearch.intersect(intMax)); // au cas où l'on sorte du domaine de la variable de la fonction + // au cas où l'on sorte du domaine de la variable de la fonction + intSearch.setBounds(intSearch.intersect(intMax)); a = this.searchTarget(rTarget, intSearch, intMax); - if (a.ok) + if (a.ok) { return a; + } // gestion de l'erreur // la valeur cible de la fonction est elle trouvable ? - - let m; let res: Message; let errDomain = false; switch (prmDom.domain) { case ParamDomainValue.INTERVAL: - let si: SearchInterval = new SearchInterval(this, intMax.min, intMax.max, 1); + const si: SearchInterval = new SearchInterval(this, intMax.min, intMax.max, 1); errDomain = !si.hasTargetValue(rTarget); break; case ParamDomainValue.POS: case ParamDomainValue.POS_NULL: - let y = this.CalculX(1e-8).vCalc; + const y = this.CalculX(1e-8).vCalc; errDomain = inc && (rTarget < y); break; @@ -303,28 +333,28 @@ export class Dichotomie extends Debug { break; default: - throw "unsupported parameter domain value"; + throw new Error("unsupported parameter domain value"); } if (errDomain) { res = new Message(MessageCode.ERROR_DICHO_INIT_DOMAIN); - res.extraVar["targetSymbol"] = this.analyticalSymbol; // symbole de la variable calculée par la fonction - res.extraVar["targetValue"] = rTarget; // valeur cible pour la fonction - res.extraVar["variableInterval"] = intMax.toString(); // intervalle de valeurs pour la variable d'entrée de la fonction - res.extraVar["variableSymbol"] = this._paramX.symbol; // symbole de la variable d'entrée de la fonction - } - else { + res.extraVar.targetSymbol = this.analyticalSymbol; // symbole de la variable calculée par la fonction + res.extraVar.targetValue = rTarget; // valeur cible pour la fonction + // intervalle de valeurs pour la variable d'entrée de la fonction + res.extraVar.variableInterval = intMax.toString(); + res.extraVar.variableSymbol = this._paramX.symbol; // symbole de la variable d'entrée de la fonction + } else { // if (intSearch.step < 0) - if (BoolIdentity(initTarget > rTarget, inc)) + if (BoolIdentity(initTarget > rTarget, inc)) { res = new Message(MessageCode.ERROR_DICHO_INITVALUE_HIGH); - else + } else { res = new Message(MessageCode.ERROR_DICHO_INITVALUE_LOW); - - res.extraVar["variableSymbol"] = this._paramX.symbol; // symbole de la variable de la fonction - res.extraVar["variableInitValue"] = rInit; // valeur initiale de la variable - res.extraVar["targetSymbol"] = this.analyticalSymbol; // symbole de la variable calculée par la fonction - res.extraVar["targetValue"] = rTarget; // valeur cible pour la fonction - res.extraVar["initTarget"] = initTarget; // valeur de la fonction pour la valeur initiale de la variable + } + res.extraVar.variableSymbol = this._paramX.symbol; // symbole de la variable de la fonction + res.extraVar.variableInitValue = rInit; // valeur initiale de la variable + res.extraVar.targetSymbol = this.analyticalSymbol; // symbole de la variable calculée par la fonction + res.extraVar.targetValue = rTarget; // valeur cible pour la fonction + res.extraVar.initTarget = initTarget; // valeur de la fonction pour la valeur initiale de la variable } return { ok: false, res }; @@ -338,56 +368,34 @@ export class Dichotomie extends Debug { * @param Ymin valeur de la fonction pour Xmin * @param Ymax valeur de la fonction pour Xmax */ + // tslint:disable-next-line:variable-name private dichoSearch(Ytarg: number, rTol: number, Xmin: number, Xmax: number, Ymin: number, Ymax: number): Result { this.debug("dichoSearch : yTarget " + Ytarg + " X " + Xmin + "->" + Xmax + " tol " + rTol); - let Xmid = (Xmin + Xmax) / 2; + // tslint:disable-next-line:variable-name + const Xmid = (Xmin + Xmax) / 2; - if (Math.abs(Xmin - Xmax) <= rTol) + if (Math.abs(Xmin - Xmax) <= rTol) { return new Result(Xmid); + } - let Ymid = this.CalculX(Xmid).vCalc; + // tslint:disable-next-line:variable-name + const Ymid = this.CalculX(Xmid).vCalc; if (Ymin < Ymax) { // fonction croissante - if (Ytarg > Ymid) - return this.dichoSearch(Ytarg, rTol, Xmid, Xmax, Ymid, Ymax); // intervalle supérieur + if (Ytarg > Ymid) { + return this.dichoSearch(Ytarg, rTol, Xmid, Xmax, Ymid, Ymax); + } // intervalle supérieur return this.dichoSearch(Ytarg, rTol, Xmin, Xmid, Ymin, Ymid); // intervalle inférieur - } - else { + } else { // fonction décroissante - if (Ytarg > Ymid) - return this.dichoSearch(Ytarg, rTol, Xmin, Xmid, Ymin, Ymid); // intervalle inférieur + if (Ytarg > Ymid) { + return this.dichoSearch(Ytarg, rTol, Xmin, Xmid, Ymin, Ymid); + } // intervalle inférieur return this.dichoSearch(Ytarg, rTol, Xmid, Xmax, Ymid, Ymax); // intervalle supérieur } } - /** - * trouve la valeur x pour y=f(x) avec un y donné - * @param rTarget valeur de y - * @param rTol tolérance pour l'arrêt de la recherche - * @param rInit valeur initiale approximative de x - */ - Dichotomie(rTarget: number, rTol: number, rInit: number): Result { - // console.log("-----"); - // for (let x = 0; x <= 1; x += 0.1) - // console.log(this.CalculX(x).vCalc); - // console.log("-----"); - - // recherche de l'intervalle de départ - - this.debug("Dichotomie : valeur cible de " + this.analyticalSymbol + "=" + rTarget + ", valeur initiale de " + this.sVarCalc + "=" + rInit); - - let r = this.getStartInterval(rTarget, rInit); - if (r.ok) - var interv: SearchInterval = r.intSearch; - else { - return new Result(r.res); - } - - // Dichotomie - - return this.dichoSearch(rTarget, rTol, interv.min, interv.max, interv.targetLower, interv.targetUpper); - } } diff --git a/src/nub.ts b/src/nub.ts index d3822c3ab8c3d24aabe033a8a341c5b483683da4..c88151028dc73ab235e781aebaf6b080e70ca7e1 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -1,7 +1,7 @@ -import { Debug, Serie } from "./base" +import { Debug, Serie } from "./base"; +import { Dichotomie } from "./dichotomie"; +import { ComputeNode, ParamDefinition, ParamsEquation } from "./param"; import { Result } from "./util/result"; -import { Dichotomie } from "./dichotomie" -import { ComputeNode, ParamDefinition, ParamsEquation } from "./param" /** * Classe abstraite de Noeud de calcul : classe de base pour tous les calculs @@ -14,49 +14,58 @@ export abstract class Nub extends ComputeNode { */ /** - * étapes de recherche de l'intervalle de départ - */ + * étapes de recherche de l'intervalle de départ + */ set dichoStartIntervalMaxSteps(n: number) { this._dichoStartIntervalMaxSteps = n; } - /** + /** * Formule utilisée pour le calcul analytique (solution directe ou méthode de résolution spécifique) */ - abstract Equation(sVarCalc: string): Result; + public abstract Equation(sVarCalc: string): Result; - /** + /** * Calcul d'une équation quelque soit l'inconnue à calculer * @param sVarCalc nom de la variable à calculer * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie * @param rPrec précision de calcul */ - Calc(sVarCalc: string, rInit: number = 0, rPrec: number = 0.001): Result { - if (this._prms.map[sVarCalc].isAnalytical()) + public Calc(sVarCalc: string, rInit: number = 0, rPrec: number = 0.001): Result { + if (this._prms.map[sVarCalc].isAnalytical()) { return this.Equation(sVarCalc); + } - return this.Solve(sVarCalc, rInit, rPrec); + const resSolve: Result = this.Solve(sVarCalc, rInit, rPrec); + if (!resSolve.ok) { + return resSolve; + } + const sAnalyticalPrm: string = this.getFirstAnalyticalParameter().symbol; + this._prms.map[sVarCalc].v = resSolve.vCalc; + const res: Result = this.Equation(sAnalyticalPrm); + res.vCalc = resSolve.vCalc; + return res; } - CalcSerie(svarCalc: string, serie: Serie): Result[] { + public CalcSerie(svarCalc: string, serie: Serie): Result[] { /** @todo faire une boucle pour appeler this.Calc avec chaque valeur de serie.values - * + * */ // let results = [new (Result)]; - let results = [new Result(0)]; + const results = [new Result(0)]; return results; } - /** + /** * Résoud l'équation par une méthode numérique * @param sVarCalc nom de la variable à calculer * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie * @param rPrec précision de calcul */ - Solve(sVarCalc: string, rInit: number, rPrec: number): Result { - let dicho: Dichotomie = new Dichotomie(this, sVarCalc, this.DBG); + private Solve(sVarCalc: string, rInit: number, rPrec: number): Result { + const dicho: Dichotomie = new Dichotomie(this, sVarCalc, this.DBG); dicho.startIntervalMaxSteps = this._dichoStartIntervalMaxSteps; - var target = this._prms.getFirstAnalyticalParameter(); + const target = this._prms.getFirstAnalyticalParameter(); return dicho.Dichotomie(target.v, rPrec, rInit); } } diff --git a/src/param.ts b/src/param.ts index d8aa8ee04f8ff60a352471ec7c15fd86e6efcd7f..32700fab30f383f1dabd7fd2042fc97cc39de408 100644 --- a/src/param.ts +++ b/src/param.ts @@ -1,8 +1,8 @@ // import { Debug, UndefinedError } from './base'; -import { Debug } from './base'; -import { DefinedNumber } from './util/definedvalue'; +import { Debug } from "./base"; +import { DefinedNumber } from "./util/definedvalue"; +import { Interval } from "./util/interval"; import { Message, MessageCode } from "./util/message"; -import { Interval } from './util/interval'; /** * domaine de définition du paramètre @@ -18,7 +18,6 @@ export enum ParamDomainValue { */ POS_NULL, - /** * > 0 */ @@ -36,13 +35,35 @@ export enum ParamDomainValue { } export class ParamDomain { + + public static getDefaultBounds(d: ParamDomainValue): { min: number, max: number } { + switch (d) { + case ParamDomainValue.INTERVAL: + const e: Message = new Message(MessageCode.ERROR_PARAMDOMAIN_INVALID); + throw e; + + case ParamDomainValue.ANY: + case ParamDomainValue.NOT_NULL: + return { min: -Infinity, max: Infinity }; + + case ParamDomainValue.POS: + return { min: 1e-9, max: Infinity }; + + case ParamDomainValue.POS_NULL: + return { min: 0, max: Infinity }; + + // default: + // throw "valeur de ParamDomainValue" + ParamDomainValue[d] + " non prise en charge"; + } + } + private _domain: ParamDomainValue; private _minValue: number; private _maxValue: number; - constructor(d: ParamDomainValue, min: number = undefined, max: number = undefined) { + constructor(d: ParamDomainValue, min?: number, max?: number) { this.checkValue(d, min, max); this._domain = d; @@ -53,37 +74,13 @@ export class ParamDomain { break; default: - let b = ParamDomain.getDefaultBounds(this._domain); + const b = ParamDomain.getDefaultBounds(this._domain); this._minValue = b.min; this._maxValue = b.max; break; } } - private checkValue(val: number, min: number, max: number) { - switch (val) { - case ParamDomainValue.INTERVAL: - if (min == undefined || max == undefined || min > max) { - // throw "invalid " + min + "/" + max + " min/max boundaries for 'interval' parameter definition domain" - let e: Message = new Message(MessageCode.ERROR_PARAMDOMAIN_INTERVAL_BOUNDS); - e.extraVar["minValue"] = min; - e.extraVar["maxValue"] = max; - throw e; - } - break; - - default: - // en dehors du cas INTERVAL, on ne doit pas fournir de valeur - if (min != undefined || max != undefined) { - let e: Message = new Message(MessageCode.ERROR_PARAMDOMAIN_INTERVAL_BOUNDS); - e.extraVar["minValue"] = min; - e.extraVar["maxValue"] = max; - throw e; - } - break; - } - } - get domain() { return this._domain; } @@ -102,41 +99,44 @@ export class ParamDomain { return new Interval(this._minValue, this._maxValue); default: - let b = ParamDomain.getDefaultBounds(this._domain); - return new Interval(b["min"], b["max"]); + const b = ParamDomain.getDefaultBounds(this._domain); + return new Interval(b.min, b.max); } } - public static getDefaultBounds(d: ParamDomainValue): { min: number, max: number } { - switch (d) { + public clone(): ParamDomain { + switch (this._domain) { case ParamDomainValue.INTERVAL: - let e: Message = new Message(MessageCode.ERROR_PARAMDOMAIN_INVALID); - throw e; - - case ParamDomainValue.ANY: - case ParamDomainValue.NOT_NULL: - return { min: -Infinity, max: Infinity }; - - case ParamDomainValue.POS: - return { min: 1e-9, max: Infinity }; - - case ParamDomainValue.POS_NULL: - return { min: 0, max: Infinity }; + return new ParamDomain(this._domain, this._minValue, this._maxValue); - // default: - // throw "valeur de ParamDomainValue" + ParamDomainValue[d] + " non prise en charge"; + default: + return new ParamDomain(this._domain); } } - public clone(): ParamDomain { - switch (this._domain) { + private checkValue(val: number, min: number, max: number) { + switch (val) { case ParamDomainValue.INTERVAL: - return new ParamDomain(this._domain, this._minValue, this._maxValue); + if (min === undefined || max === undefined || min > max) { + const e: Message = new Message(MessageCode.ERROR_PARAMDOMAIN_INTERVAL_BOUNDS); + e.extraVar.minValue = min; + e.extraVar.maxValue = max; + throw e; + } + break; default: - return new ParamDomain(this._domain); + // en dehors du cas INTERVAL, on ne doit pas fournir de valeur + if (min !== undefined || max !== undefined) { + const e: Message = new Message(MessageCode.ERROR_PARAMDOMAIN_INTERVAL_BOUNDS); + e.extraVar.minValue = min; + e.extraVar.maxValue = max; + throw e; + } + break; } } + } /** @@ -167,6 +167,7 @@ export enum ParamCalculability { /** * paramètre avec symbole et domaine de définition */ +// tslint:disable-next-line:max-classes-per-file export class BaseParam extends DefinedNumber { /** * symbole @@ -178,14 +179,15 @@ export class BaseParam extends DefinedNumber { */ private _domain: ParamDomain; - constructor(symb: string, d: ParamDomain | ParamDomainValue, val: number = undefined) { + constructor(symb: string, d: ParamDomain | ParamDomainValue, val?: number) { super(val); this._symbol = symb; - if (d instanceof ParamDomain) + if (d instanceof ParamDomain) { this._domain = d; - else - this._domain = new ParamDomain(<ParamDomainValue>d); + } else { + this._domain = new ParamDomain(d as ParamDomainValue); + } this.checkValue(val); } @@ -194,7 +196,7 @@ export class BaseParam extends DefinedNumber { return this._symbol; } - getDomain(): ParamDomain { + public getDomain(): ParamDomain { return this._domain; } @@ -202,22 +204,21 @@ export class BaseParam extends DefinedNumber { return this._domain.interval; } - /** * gestion de la valeur */ - getValue(): number { + public getValue(): number { if (!this.isDefined) { - let e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED); - e.extraVar["symbol"] = this.symbol; + const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED); + e.extraVar.symbol = this.symbol; throw e; } return super.getValue(); } - setValue(val: number) { + public setValue(val: number) { this.checkValue(val); super.setValue(val); @@ -225,7 +226,7 @@ export class BaseParam extends DefinedNumber { } public checkValue(v: number) { - let sDomain = ParamDomainValue[this._domain.domain]; + const sDomain = ParamDomainValue[this._domain.domain]; switch (this._domain.domain) { case ParamDomainValue.ANY: @@ -233,47 +234,47 @@ export class BaseParam extends DefinedNumber { case ParamDomainValue.POS: if (v <= 0) { - let e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POS); - e.extraVar["symbol"] = this.symbol; - e.extraVar["value"] = v; - throw e; + const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POS); + f.extraVar.symbol = this.symbol; + f.extraVar.value = v; + throw f; } break; case ParamDomainValue.POS_NULL: if (v < 0) { - let e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POSNULL); - e.extraVar["symbol"] = this.symbol; - e.extraVar["value"] = v; - throw e; + const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_POSNULL); + f.extraVar.symbol = this.symbol; + f.extraVar.value = v; + throw f; } break; case ParamDomainValue.NOT_NULL: - if (v == 0) { - let e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_NULL); - e.extraVar["symbol"] = this.symbol; - throw e; + if (v === 0) { + const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_NULL); + f.extraVar.symbol = this.symbol; + throw f; } break; case ParamDomainValue.INTERVAL: - let min = this._domain.minValue; - let max = this._domain.maxValue; + const min = this._domain.minValue; + const max = this._domain.maxValue; if (v < min || v > max) { - let e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTERVAL); - e.extraVar["symbol"] = this.symbol; - e.extraVar["value"] = v; - e.extraVar["minValue"] = min; - e.extraVar["maxValue"] = max; - throw e; + const f = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTERVAL); + f.extraVar.symbol = this.symbol; + f.extraVar.value = v; + f.extraVar.minValue = min; + f.extraVar.maxValue = max; + throw f; } break; default: - let e = new Message(MessageCode.ERROR_PARAMDOMAIN_INVALID); - e.extraVar["symbol"] = this.symbol; - e.extraVar["domain"] = sDomain; + const e = new Message(MessageCode.ERROR_PARAMDOMAIN_INVALID); + e.extraVar.symbol = this.symbol; + e.extraVar.domain = sDomain; throw e; } } @@ -282,6 +283,7 @@ export class BaseParam extends DefinedNumber { /** * définition d'un paramètre d'un neud de calcul */ +// tslint:disable-next-line:max-classes-per-file export class ParamDefinition extends BaseParam { /** * calculabilité @@ -291,7 +293,7 @@ export class ParamDefinition extends BaseParam { /** * noeud de calcul parent */ - private _computeNodeType: ComputeNodeType + private _computeNodeType: ComputeNodeType; // private static _idGen: number = 0; // A VIRER // private _id: number; // A VIRER @@ -320,9 +322,9 @@ export class ParamDefinition extends BaseParam { } set v(val: number) { - if (this.calculability == ParamCalculability.NONE) { - let e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_FIXED); - e.extraVar["symbol"] = this.symbol; + if (this.calculability === ParamCalculability.NONE) { + const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_FIXED); + e.extraVar.symbol = this.symbol; throw e; } super.setValue(val); @@ -335,15 +337,15 @@ export class ParamDefinition extends BaseParam { /** * variable calculable par l'équation ? */ - isAnalytical(): boolean { - return this.calculability == ParamCalculability.EQUATION; + public isAnalytical(): boolean { + return this.calculability === ParamCalculability.EQUATION; } get calculability(): ParamCalculability { - if (this._calc == undefined) { + if (this._calc === undefined) { // throw "value of parameter '" + this._symbol + "' calculability is not defined"; - let e = new Message(MessageCode.ERROR_PARAMDEF_CALC_UNDEFINED); - e.extraVar["symbol"] = this.symbol; + const e = new Message(MessageCode.ERROR_PARAMDEF_CALC_UNDEFINED); + e.extraVar.symbol = this.symbol; throw e; } @@ -355,27 +357,61 @@ export class ParamDefinition extends BaseParam { } public clone(): ParamDefinition { - let res = new ParamDefinition(this._computeNodeType, this.symbol, this.getDomain().clone()); + const res = new ParamDefinition(this._computeNodeType, this.symbol, this.getDomain().clone()); res._calc = this._calc; res.value = this.uncheckedValue; return res; } } - /** * liste des paramètres d'une équation */ +// tslint:disable-next-line:max-classes-per-file export abstract class ParamsEquation { + protected _paramMap: { [key: string]: ParamDefinition } = {}; + public hasParameter(name: string): boolean { + for (const ps in this._paramMap) { + const p: ParamDefinition = this._paramMap[ps]; + if (p.symbol === name) { + return true; + } + } + + return false; + } + + public getParameter(name: string): ParamDefinition { + for (const ps in this._paramMap) { + const p: ParamDefinition = this._paramMap[ps]; + if (p.symbol === name) { + return p; + } + } + + throw new Error("ParamsEquation.getParameter() : invalid parameter name " + name); + } + + public getFirstAnalyticalParameter(): ParamDefinition { + for (const ps in this._paramMap) { + const p: ParamDefinition = this._paramMap[ps]; + if (p.isAnalytical()) { + return p; + } + } + return undefined; + } + protected addParamDefinition(p: ParamDefinition) { - if (!this.hasParameter(p.symbol)) + if (!this.hasParameter(p.symbol)) { this._paramMap[p.symbol] = p; + } } protected addParamDefinitions(ps: ParamsEquation) { - for (let pi in ps._paramMap) { + for (const pi in ps._paramMap) { this.addParamDefinition(ps._paramMap[pi]); } } @@ -385,46 +421,20 @@ export abstract class ParamsEquation { } protected checkParametersCalculability() { - let res = []; + const res = []; - for (let ps in this._paramMap) { - let p: ParamDefinition = this._paramMap[ps]; - if (p.calculability == undefined) + for (const ps in this._paramMap) { + const p: ParamDefinition = this._paramMap[ps]; + if (p.calculability === undefined) { res.push(p.symbol); + } } - if (res.length > 0) - throw 'Calculability of parameter(s) ' + res.toString() + ' has not been defined'; - } - - public hasParameter(name: string): boolean { - for (let ps in this._paramMap) { - let p: ParamDefinition = this._paramMap[ps]; - if (p.symbol == name) - return true; - } - - return false; - } - - public getParameter(name: string): ParamDefinition { - for (let ps in this._paramMap) { - let p: ParamDefinition = this._paramMap[ps]; - if (p.symbol == name) - return p; + if (res.length > 0) { + throw new Error("Calculability of parameter(s) " + res.toString() + " has not been defined"); } - - throw 'ParamsEquation.getParameter() : invalid parameter name ' + name; } - public getFirstAnalyticalParameter(): ParamDefinition { - for (let ps in this._paramMap) { - let p: ParamDefinition = this._paramMap[ps]; - if (p.isAnalytical()) - return p; - } - return undefined; - } } /** @@ -446,11 +456,10 @@ export enum ComputeNodeType { /** * noeud de calcul */ +// tslint:disable-next-line:max-classes-per-file export abstract class ComputeNode extends Debug { protected _prms: ParamsEquation; - protected abstract setParametersCalculability(): void; - constructor(prms: ParamsEquation, dbg: boolean = false) { super(dbg); this._prms = prms; @@ -464,4 +473,7 @@ export abstract class ComputeNode extends Debug { public getFirstAnalyticalParameter(): ParamDefinition { return this._prms.getFirstAnalyticalParameter(); } + + protected abstract setParametersCalculability(): void; + } diff --git a/src/util/result.ts b/src/util/result.ts index 2b64d20a6078c2d15e8dc1d2cdd1d7d5b933730c..066a4d72b6c7a8c3a0b5f976804e60658ea53458 100644 --- a/src/util/result.ts +++ b/src/util/result.ts @@ -1,6 +1,6 @@ import { cLog } from "./log"; +import { Message, MessageCode, MessageSeverity } from "./message"; import { ResultElement } from "./resultelement"; -import { MessageSeverity, Message, MessageCode } from "./message"; /** * Résultat global d'un calcul @@ -18,29 +18,31 @@ export class Result { constructor(v?: number | Message | ResultElement, d?: any) { this._globalLog = new cLog(); this._results = []; - if (typeof (v) === "number" || v instanceof Message) + if (typeof (v) === "number" || v instanceof Message) { this._results.push(new ResultElement(v)); - else if (v instanceof ResultElement) + } else if (v instanceof ResultElement) { this._results.push(v); + } - if (d != undefined) { - for (const i in d) { - const re = new ResultElement(); - re.addExtraResult(i, d[i]); - } + if (d !== undefined) { + this.result.extraResults = d; } } /** - * retourne le journal du 1er ResultElement + * retourne le journal de la calculette */ public get globalLog() { return this._globalLog; } - private get result(): ResultElement { - if (this._results.length == 0) + /** + * Retourne le résultat du premier ResultElement + */ + get result(): ResultElement { + if (this._results.length === 0) { throw new Error("appel à la méthode de Result.result() invalide, il n'y a pas au moins un 'ResultElement'"); + } return this._results[0]; } @@ -59,6 +61,13 @@ export class Result { return this.result.vCalc; } + /** + * @return le résultat de calcul du 1er ResultElement + */ + set vCalc(r: number) { + this.result.vCalc = r; + } + /** * retourne le journal du 1er ResultElement */ @@ -75,12 +84,27 @@ export class Result { } /** - * retourne les résultats complémentaires du 1er ResultElement - */ + * retourne les résultats complémentaires du 1er ResultElement + */ get extraResults() { return this.result.extraResults; } + /** + * Extract one ResultElement as a Result + * @param i index of the ResultElement + */ + public extractResult(i: number): Result { + if (i < 0 || i >= this._results.length) { + throw new Error("Result.extractResult index outside [0;" + (this._results.length - 1) + "]"); + } + return new Result(this._results[i]); + } + + /** + * Ajoute un ResultElement au tableau + * @param r ResultElement à ajouter + */ public addResult(r: ResultElement) { this._results.push(r); } @@ -124,7 +148,8 @@ export class Result { default: throw new Error( - "Result.getExtraResult() : il existe plusieurs ResultElement avec un extratresult dont le nom est '" + name + "'", + "Result.getExtraResult() : il existe plusieurs ResultElement avec" + + " un extratresult dont le nom est '" + name + "'", ); } } @@ -182,12 +207,13 @@ export class Result { * @returns true si au moins un message de log comporte un code d'erreur */ public get hasErrorMessages(): boolean { - for (const m of this.log.messages) { + // Test du journal global + for (const m of this._globalLog.messages) { if (m.getSeverity() === MessageSeverity.ERROR) { return true; } } - + // Test des journaux des résultats for (const r of this._results) { if (r.hasErrorMessages) { return true; diff --git a/src/util/resultelement.ts b/src/util/resultelement.ts index 8d58b6f4cbeddd67457517e8ab9868c5818d8c3f..dc301486fdeeabcfc22d9e77a3a37418139c546f 100644 --- a/src/util/resultelement.ts +++ b/src/util/resultelement.ts @@ -34,6 +34,10 @@ export class ResultElement { get vCalc() { return this._vCalc; } + set vCalc(r: number) { + this._vCalc = r; + } + public get log() { return this._log; } @@ -95,10 +99,14 @@ export class ResultElement { * résultats complémentaires */ - public get extraResults() { + get extraResults() { return this._extraResults; } + set extraResults(d: { [key: string]: any }) { + this._extraResults = d; + } + public addExtraResult(name: string, value: any) { this._extraResults[name] = value; }