/*
* MathGraph32 Javascript : Software for animating online dynamic mathematics figures
* https://www.mathgraph32.org/
* @Author Yves Biton (yves.biton@sesamath.net)
* @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
*/
import Complexe from '../types/Complexe'
import { erreurCalculException, getStr, MAX_VALUE, MIN_VALUE } from '../kernel/kernel'
import CCbGlob from '../kernel/CCbGlob'
import CSommeDansFormule from './CSommeDansFormule'
export default CProduitDansFormule
/**
* Classe représentant un produit indicé dans un arbre binaire de calcul.
* @constructor
* @extends CCb
* @param {CListeObjets} listeProprietaire La liste propriétaire.
* @param {CCb} calculASommer Le calcul à multiplier
* @param {CCb} bornea L'indice de départ.
* @param {CCb} borneb L'indice de fin.
* @param {CCb} pas Le pas à ajouter à l'indice pour chaque somme (1 la plupart du temps)
* @param {string} nomVariable Le nom choisi pour la variable de sommation.
* @returns {CProduitDansFormule}
*/
function CProduitDansFormule (listeProprietaire, calculASommer, bornea, borneb, pas, nomVariable) {
if (arguments.length === 1) CSommeDansFormule.call(this, listeProprietaire)
else CSommeDansFormule.call(this, listeProprietaire, calculASommer, bornea, borneb, pas, nomVariable)
}
CProduitDansFormule.prototype = new CSommeDansFormule()
CProduitDansFormule.prototype.constructor = CProduitDansFormule
CProduitDansFormule.prototype.superClass = 'CSommeDansFormule'
CProduitDansFormule.prototype.className = 'CProduitDansFormule'
CProduitDansFormule.prototype.nature = function () {
return CCbGlob.natProduitDansFormule
}
CProduitDansFormule.prototype.getClone = function (listeSource, listeCible) {
return new CProduitDansFormule(listeCible, this.calculASommer.getClone(listeSource, listeCible),
this.indiceDebut.getClone(listeSource, listeCible), this.indiceFin.getClone(listeSource, listeCible),
this.pas.getClone(listeSource, listeCible), this.nomVariable)
}
CProduitDansFormule.prototype.getCopie = function () {
return new CProduitDansFormule(this.listeProprietaire, this.calculASommer.getCopie(), this.indiceDebut.getCopie(),
this.indiceFin.getCopie(), this.pas.getCopie(), this.nomVariable)
}
CProduitDansFormule.prototype.getCore = function () {
return new CProduitDansFormule(this.listeProprietaire, this.calculASommer.getCore(), this.indiceDebut.getCore(),
this.indiceFin.getCore(), this.pas.getCore(), this.nomVariable)
}
/**
* Fonction renvoyant le résultat réel de la somme indicée
* Lors du calcul de l'expression à sommer, la valeur de l'indice de sommation est affectée au dernier
* élément du tableau arrayparam
* @param {number[]} arrayparam Tableau de paramètres
* @param {number} inddeb Indice de début de sommation
* @param {number} indfin Indice de fin de sommation
* @param {number} pas Valeur du pas de sommation
* @param {boolean} infoRandom true pour un recalcul des appels à random()
* @returns {number} La valeur du produit
*/
CProduitDansFormule.prototype.resultatBase = function (arrayparam, inddeb, indfin, pas, infoRandom) {
const n = arrayparam.length - 1
this.listeProprietaire.nombreIterations += (indfin - inddeb) / pas
if (this.listeProprietaire.nombreIterations > CCbGlob.nombreMaxiIterations) throw new Error(erreurCalculException)
let prod = 1
for (let i = inddeb; i <= indfin; i += pas) {
arrayparam[n] = i
prod *= this.calculASommer.resultatFonction(infoRandom, arrayparam)
}
return prod
}
/**
* Renvoie le résultat réel du produit.
* @param {boolean} infoRandom true si les calculs aléatoires doivent être relancés
* @returns {number}
*/
CProduitDansFormule.prototype.resultat = function (infoRandom) {
const val = new Array(1)
const dinddeb = this.indiceDebut.resultat(infoRandom)
if ((dinddeb > MAX_VALUE) || (dinddeb < MIN_VALUE) || (dinddeb !== Math.floor(dinddeb))) throw new Error(erreurCalculException)
const dindfin = this.indiceFin.resultat(infoRandom)
if ((dindfin > MAX_VALUE) || (dindfin < MIN_VALUE) || (dindfin !== Math.floor(dindfin)) ||
(dindfin < dinddeb)) throw new Error(erreurCalculException)
const dpas = this.pas.resultat(infoRandom)
if ((dpas > MAX_VALUE) || (dpas < MIN_VALUE) ||
(dpas !== Math.floor(dpas)) || (dpas <= 0)) throw new Error(erreurCalculException)
return this.resultatBase(val, dinddeb, dindfin, dpas, infoRandom)
}
CProduitDansFormule.prototype.resultatFonction = function (infoRandom, valeurParametre) {
let val, i
if (valeurParametre instanceof Array) {
const n = valeurParametre.length
val = new Array(n + 1)
for (i = 0; i < n; i++) val[i] = valeurParametre[i]
} else {
val = new Array(2)
val[0] = valeurParametre
}
const dinddeb = this.indiceDebut.resultatFonction(infoRandom, valeurParametre)
if ((dinddeb > MAX_VALUE) || (dinddeb < MIN_VALUE) || (dinddeb !== Math.floor(dinddeb))) throw new Error(erreurCalculException)
const dindfin = this.indiceFin.resultatFonction(infoRandom, valeurParametre)
if ((dindfin > MAX_VALUE) || (dindfin < MIN_VALUE) || (dindfin !== Math.floor(dindfin)) ||
(dindfin < dinddeb)) throw new Error(erreurCalculException)
const dpas = this.pas.resultatFonction(infoRandom, valeurParametre)
if ((dpas > MAX_VALUE) || (dpas < MIN_VALUE) ||
(dpas !== Math.floor(dpas)) || (dpas <= 0)) throw new Error(erreurCalculException)
return this.resultatBase(val, dinddeb, dindfin, dpas, infoRandom)
}
/**
* @typedef ParamComplexe
* @property {number} x
* @property {number} y
*/
/**
* Fonction renvoyant dans le complexe zRes le résultat du produit complexe indicé
* Lors du calcul de l'expression à sommer, la valeur de l'indice de sommation est affectée au dernier
* élément du tableau arrayparam (sous forme d'un complexe)
* @param {ParamComplexe[]} arrayparam le tableau de paramètres complexes
* @param {number} inddeb L'indice de début
* @param {number} indfin L'indice de fin
* @param {number} pas La valeur du pas
* @param {boolean} infoRandom true pour un recalcul des appels de random()
* @param {Complexe} zRes Le complexe dans lequel est revoyé le résultat
*/
CProduitDansFormule.prototype.resultatComplexeBase = function (arrayparam, inddeb, indfin, pas, infoRandom, zRes) {
const n = arrayparam.length - 1
this.listeProprietaire.nombreIterations += (indfin - inddeb) / pas
if (this.listeProprietaire.nombreIterations > CCbGlob.nombreMaxiIterations) throw new Error(erreurCalculException)
zRes.x = 1
zRes.y = 0
const z = new Complexe()
for (let i = inddeb; i <= indfin; i += pas) {
arrayparam[n].x = i
arrayparam[n].y = 0
this.calculASommer.resultatFonctionComplexe(infoRandom, arrayparam, z)
zRes.produitComp(z, zRes)
}
}
/**
* Renvoie le résultat complexe du produit dans le complee zres.
* @param {boolean} infoRandom true si les calculs aléatoires doivent être relancés
* @param {Complexe} zRes
* @returns {void}
*/
CProduitDansFormule.prototype.resultatComplexe = function (infoRandom, zRes) {
const val = new Array(1)
val[0] = new Complexe()
const inddeb = new Complexe()
this.indiceDebut.resultatComplexe(infoRandom, inddeb)
if (inddeb.y !== 0) throw new Error(erreurCalculException)
const dinddeb = inddeb.x
if ((dinddeb > MAX_VALUE) || (dinddeb < MIN_VALUE) || (dinddeb !== Math.floor(dinddeb))) throw new Error(erreurCalculException)
const indfin = new Complexe()
this.indiceFin.resultatComplexe(infoRandom, indfin)
if (indfin.y !== 0) throw Error(erreurCalculException)
const dindfin = indfin.x
if ((dindfin > MAX_VALUE) || (dindfin < MIN_VALUE) || (dindfin !== Math.floor(dindfin)) ||
(dindfin < dinddeb)) throw new Error(erreurCalculException)
const valpas = new Complexe()
this.pas.resultatComplexe(infoRandom, valpas)
if (valpas.y !== 0) throw new Error(erreurCalculException)
const dpas = valpas.x
if ((dpas > MAX_VALUE) || (dpas < MIN_VALUE) ||
(dpas !== Math.floor(dpas)) || (dpas <= 0)) throw new Error(erreurCalculException)
this.resultatComplexeBase(val, dinddeb, dindfin, dpas, infoRandom, zRes)
}
CProduitDansFormule.prototype.resultatFonctionComplexe = function (infoRandom, valeurParametre, zRes) {
let i, val
if (valeurParametre instanceof Array) {
const n = valeurParametre.length
val = new Array(n + 1)
for (i = 0; i < n; i++) val[i] = new Complexe(valeurParametre[i])
val[n] = new Complexe()
} else {
val = new Array(2)
val[0] = valeurParametre
val[1] = new Complexe()
}
const inddeb = new Complexe()
this.indiceDebut.resultatFonctionComplexe(infoRandom, valeurParametre, inddeb)
if (inddeb.y !== 0) throw new Error(erreurCalculException)
const dinddeb = inddeb.x
if ((dinddeb > MAX_VALUE) || (dinddeb < MIN_VALUE) || (dinddeb !== Math.floor(dinddeb))) throw new Error(erreurCalculException)
const indfin = new Complexe()
this.indiceFin.resultatFonctionComplexe(infoRandom, valeurParametre, indfin)
if (indfin.y !== 0) throw new Error(erreurCalculException)
const dindfin = indfin.x
if ((dindfin > MAX_VALUE) || (dindfin < MIN_VALUE) || (dindfin !== Math.floor(dindfin)) ||
(dindfin < dinddeb)) throw new Error(erreurCalculException)
const valpas = new Complexe()
this.pas.resultatFonctionComplexe(infoRandom, valeurParametre, valpas)
if (valpas.y !== 0) throw new Error(erreurCalculException)
const dpas = valpas.x
if ((dpas > MAX_VALUE) || (dpas < MIN_VALUE) ||
(dpas !== Math.floor(dpas)) || (dpas <= 0)) throw new Error(erreurCalculException)
this.resultatComplexeBase(val, dinddeb, dindfin, dpas, infoRandom, zRes)
}
CProduitDansFormule.prototype.chaineCalcul = function (varFor = null) {
let varFor2, i
let n = 0
if (varFor === null) varFor2 = new Array(1)
else {
n = varFor.length
varFor2 = new Array(n + 1)
}
for (i = 0; i < n; i++) varFor2[i] = varFor[i]
varFor2[n] = this.nomVariable
return getStr('produit') + '(' + this.calculASommer.chaineCalculSansPar(varFor2) + ',' +
this.nomVariable + ',' + this.indiceDebut.chaineCalculSansPar(varFor) + ',' +
this.indiceFin.chaineCalculSansPar(varFor) + ',' + this.pas.chaineCalculSansPar(varFor) + ')'
}
CProduitDansFormule.prototype.chaineLatex = function (varFor, fracSimple = false) {
let varFor2, i, up
let n = 0
if (varFor === null) varFor2 = new Array(1)
else {
n = varFor.length
varFor2 = new Array(n + 1)
}
for (i = 0; i < n; i++) varFor2[i] = varFor[i]
varFor2[n] = this.nomVariable
// Deuxième paramètre de chaineLatexSansPar à true dans les bornes pour utilier \frac dedans et pas \dfrac
up = ''
if (this.pas.nature() === CCbGlob.natConstante) {
if (this.pas.valeur === 1) up = this.indiceFin.chaineLatexSansPar(varFor, true)
}
if (up === '') {
up = this.indiceFin.chaineLatexSansPar(varFor, true) + '\\text{ ' + getStr('step') + ' }' +
this.pas.chaineLatex(varFor, true)
}
return '\\prod\\limits_{' + this.nomVariable + '=' + this.indiceDebut.chaineLatexSansPar(varFor, true) + '}' + '^{' + up + '}' +
'{' + this.calculASommer.chaineLatex(varFor2, fracSimple) + '}'
}
CProduitDansFormule.prototype.calculAvecValeursRemplacees = function (bfrac) {
return new CProduitDansFormule(this.listeProprietaire, this.calculASommer.calculAvecValeursRemplacees(bfrac),
this.indiceDebut.calculAvecValeursRemplacees(bfrac), this.indiceFin.calculAvecValeursRemplacees(bfrac),
this.pas.calculAvecValeursRemplacees(bfrac), this.nomVariable)
}
CProduitDansFormule.prototype.deriveePossible = function (indiceVariable) {
return !this.calculASommer.dependDeVariable(indiceVariable) &&
!this.indiceDebut.dependDeVariable(indiceVariable) && !this.indiceFin.dependDeVariable(indiceVariable) &&
!this.pas.dependDeVariable(indiceVariable)
}