/** @module legacy/outils/espace/fctsEspace */
import { j3pRandomTab, j3pVirgule } from 'src/legacy/core/functions'
import { pgcdMulti } from 'sesajs/number'
/**
* Recherche d’occurence d’une valeur : nombre et positions
* @param {string|number} [occurenceCherchee] valeur recherchée dans le tableau
* @param {Array} [monTableau]
* @return {Object} {nombre, emplacements} nombre d’apparition de la valeur cherchée dans le tableau et tableau des index où a été trouvée cette valeur
*/
export function occurences (occurenceCherchee, monTableau) {
const stock = {}
const tabDesOcc = []
let count = 0
let pos = monTableau.indexOf(occurenceCherchee)
while (pos !== -1) {
count++
tabDesOcc.push(pos)
pos = monTableau.indexOf(occurenceCherchee, pos + 1)
}
stock.nombre = count
stock.emplacements = tabDesOcc
return stock
}
/**
* Crée un tableau contenant plusieurs fois un même élément
* @param {string|number} [elementIdentique] valeur à dupliquer
* @param {Number} [taille] nombre de fois où on la souhiate
* @return {Array} tableau contenant taille fois la valeur elementIdentique
*/
export function creerTableauDe (elementIdentique, taille) {
// Cette fonction crée un tableau de dimmension taille en le remplissant d’élement identiques
const stock = []
for (let k = 0; k < taille; k++) {
stock.push(elementIdentique)
}
return stock
}
/**
* Déterminant de deux vecteurs du plan
* @param {Array} [tabU] tableau de deux éléments (vecteur du plan)
* @param {Array} [tabV] tableau de deux éléments (vecteur du plan)
* @return {Object} {valeur, ecriture} valeur du déterminant et écriture du calcul (x1*y2-y2*x1)
*/
export function determinant (tabU, tabV) {
const stock = {}
const valeur = tabU[0] * tabV[1] - tabU[1] * tabV[0]
let ecriture = tabU[0] + '\\times '
if (j3pVirgule(tabV[1]).substring(0, 1) === '-') {
ecriture = ecriture + '(' + tabV[1] + ')-'
} else {
ecriture = ecriture + tabV[1] + '-'
}
if (j3pVirgule(tabU[1]).substring(0, 1) === '-') {
ecriture = ecriture + '(' + tabU[1] + ')\\times '
} else {
ecriture = ecriture + tabU[1] + '\\times '
}
if (j3pVirgule(tabV[0]).substring(0, 1) === '-') {
ecriture = ecriture + '(' + tabV[0] + ')'
} else {
ecriture = ecriture + tabV[0]
}
stock.valeur = valeur
stock.ecriture = ecriture
return stock
}
/**
* Déterminant de trois vecteurs de l’espace
* @param {Array} [U] tableau de trois éléments (vecteur de l’espace)
* @param {Array} [V] tableau de trois éléments (vecteur de l’espace)
* @param {Array} [W] tableau de trois éléments (vecteur de l’espace)
* @return {Number} déterminant de la matrice
*/
export function determinant3D (U, V, W) {
return U[0] * V[1] * W[2] + U[2] * V[0] * W[1] + U[1] * V[2] * W[0] - (U[2] * V[1] * W[0] + U[0] * V[2] * W[1] + U[1] * V[0] * W[2])
}
/**
* Colinéarité de deux vecteurs de l’espace
* @param {Array} [tabU] tableau de trois éléments (vecteur de l’espace)
* @param {Array} [tabV] tableau de trois éléments (vecteur de l’espace)
* @return {Boolean} renvoie true si les vecteurs sont colinéarires
*/
export function UcolV (tabU, tabV) {
return (Math.abs(tabU[0] * tabV[1] - tabU[1] * tabV[0]) < 1e-12) && (Math.abs(tabU[1] * tabV[2] - tabU[2] * tabV[1]) < 1e-12) && (Math.abs(tabU[0] * tabV[2] - tabU[2] * tabV[0]) < 1e-12)
}
/**
* Egalité de tableaux de nombres
* @param {Array} [tab1] tableau de number
* @param {Array} [tab2] tableau de number
* @return {Boolean} renvoie true si les tableaux sont de la même taille et leurs valeurs tableaux sont deux à deux égales
*/
export function compareTabNum (tab1, tab2) {
if (tab1.length < tab2.length) return false
for (let k = 0; k < tab2.length; k++) {
if (Math.abs(tab1[k] - tab2[k]) > 1e-12) {
return false
}
}
return true
}
/**
* Cette fonction renvoie true si on retrouve tous les éléments du tableau tabJeLesVeux dans monTableau
* Sauf si l’un des éléments du tableau tabJeLeVeux est de proba nulle
* @param {Array} [tabJeLesVeux] tableau
* @param {Array} [probaJeLesVeux] tableau de number entre 0 et 1 (proba)
* @param {Array} [monTableau] tableau
* @return {Boolean}
*/
export function jeLesVeuxDansMonTab (tabJeLesVeux, probaJeLesVeux, monTableau) {
for (let k = 0; k < tabJeLesVeux.length; k++) {
if (!monTableau.includes(tabJeLesVeux[k]) && probaJeLesVeux[k] !== 0) return false
}
return true
}
/**
* Cette fonction crée un tableau de taille dimension, en y mettant des éléments pris dans tabDesChoix, et en respectant la tabDesProbas imposée.
* de telle sorte que tous les éléments de tabDesChoix apparaissent dans la mesure où dimension>=longueur de tabDesChoix
* @param {Array} [tabDesChoix] tableau
* @param {Array} [tabDesProbas] tableau de number entre 0 et 1 (proba)
* @param {Number} [dimension] taille du tableau souhaité
* @return {Array}
*/
export function creeTableauAleatoire (tabDesChoix, tabDesProbas, dimension) {
let stock = []
if (dimension < tabDesChoix.length) {
for (let k = 0; k < dimension; k++) {
stock.push(j3pRandomTab(tabDesChoix, tabDesProbas))
}
} else {
do {
stock = []
for (let k = 0; k < dimension; k++) {
stock.push(j3pRandomTab(tabDesChoix, tabDesProbas))
}
} while (!jeLesVeuxDansMonTab(tabDesChoix, tabDesProbas, stock))
}
return stock
}
/**
* Cette fonction écrit correctement la somme des ak*bk où ak et bk sont les coordonnées respectives des tableau tabAk, tabBk
* @param {Array} [tabAk] tableau de number
* @param {Array} [tabBk] tableau de number
* @return {Object} {valeur, ecriture} valeur du produit scalaire des deux vecteurs et écriture de ce produit
*/
export function sommeAkBk (tabAk, tabBk) {
// le rôle de cette fonction est d’écrire correctement ie avec des parenthèses en cas de signe "-" devant l’un des ak ou bk la somme des ak*bk
// tabAk et tabBk sont des tableaux numériques
// renvoie l’objet stock : .valeur: le résultat de cette somme et .ecriture l’écriture mathquillcorrecte
let valeur = tabAk[0] * tabBk[0]
let ecriture = tabAk[0] + '\\times '
if (j3pVirgule(tabBk[0]).substring(0, 1) === '-') {
ecriture = ecriture + '(' + tabBk[0] + ')+'
} else {
ecriture = ecriture + tabBk[0] + '+'
}
for (let k = 1; k < tabAk.length; k++) {
valeur = valeur + tabAk[k] * tabBk[k]
if (j3pVirgule(tabAk[k]).substring(0, 1) === '-') {
ecriture = ecriture + '(' + tabAk[k] + ')\\times '
} else {
ecriture = ecriture + tabAk[k] + '\\times '
}
if (j3pVirgule(tabBk[k]).substring(0, 1) === '-') {
ecriture = ecriture + '(' + tabBk[k] + ')+'
} else {
ecriture = ecriture + tabBk[k] + '+'
}
}
ecriture = ecriture.substring(0, ecriture.length - 1)
return { valeur, ecriture }
}
/**
* Cette fonction renvoie un nouveau tableau obtenu par application de ma_fonction à tous les éléments du tableau
* @param {Function} [maFonction] fonction à appliquer à chaque valeur du tableau
* @param {Array} [monTableau] tableau
* @return {Array}
*/
export function fonctionTab (maFonction, monTableau) {
return monTableau.map(maFonction)
}
/**
* Cette fonction renvoie vrai si le tableau n’est composé que de true
* @param {Array} [monTableau] tableau de boolean
* @return {Boolean}
*/
export function tableauVrai (monTableau) {
return monTableau.every((elt) => elt)
}
/**
* Cette fonction renvoie un objet correspondant à l’écriture d’une fraction
* @param {number} [nbre] nombre réel
* @return {Object} {ch, mathq, num, den, valeur} ch="a/b" avec pgcd(a,b)=1 et a/b=nbre, mathq est l’écriture de cette fraction en latex, valeur vaut nbre (qui est du type number nécessairement)
*/
export function fraction (nbre) {
// Cette fonction retourne un objet
// .ch :"a/b" avec a/b mise en fraction irréductible du nbre
// .mathq : fraction éditée dans mathquill
// .num : numérateur
// .denom:dénominateur
// .valeur (c’est le nombre saisi)
const stock = {}
if (typeof (nbre) !== 'number') return console.error(nbre, 'doit être du type nuber')
stock.valeur = nbre
let q = Math.abs(nbre)
const x = q
let b = 1
let d = 1
let s = 0
let n = Math.floor(q)
const signeNbre = (nbre < 0) ? -1 : 1
if (x <= 1e-12) {
stock.ch = '0'
stock.mathq = '0'
stock.num = 0
stock.denom = 1
} else {
while (Math.abs(x * d - n) > 1e-8) {
s = q - b * Math.floor(q / b)
n = Math.floor(x / b)
d = Math.floor(1 / b)
q = b
b = s
}
if (d === 1) {
n = signeNbre * n
stock.ch = n
stock.num = n
stock.denom = 1
stock.mathq = (n < 0) ? '-' + Math.abs(n) : n
// stock.mathq="$"+n+"$";
} else {
stock.mathq = (nbre < 0) ? '-\\frac{' + n + '}{' + d + '}' : '\\frac{' + n + '}{' + d + '}'
stock.num = signeNbre * n
stock.denom = d
stock.ch = signeNbre * n + '/' + d
}
}
return stock
}
function egal (a, b) {
// Renvoie true si la différence entre a et b est inférieure ou égale à 10^-9
return Math.abs(a - b) < 1e-9
}
/**
* Cette fonction vérifie si monNombre est entier ou non
* @param {number} [monNombre] nombre réel
* @return {Boolean}
*/
export function estEntier (monNombre) {
return egal(monNombre, Math.floor(monNombre))
}
/**
* Cette fonction écrit correctement le monome sous la forme coeff*variable
* @param {number} [valeurCoeff] nombre réel qui, s’il est décimal, sera écrit sous forme fractionnaire
* @param {string} [devantCoeff] '+' ou '-'
* @param {string} [nomVariable] nomVariable peut être une variable quelconque ou une chaine mathquill comme celle d’un vecteur
* @return {String}
*/
export function monome (valeurCoeff, devantCoeff, nomVariable) {
let stock = ''
if (!egal(valeurCoeff, 0)) {
if (egal(valeurCoeff, 1)) {
if (nomVariable === '') {
stock = devantCoeff + '1'
} else {
stock = devantCoeff + nomVariable
}
}
if (egal(valeurCoeff, -1)) {
stock = (nomVariable === '') ? '-1' : '-' + nomVariable
}
if (!egal(valeurCoeff, 1) && !egal(valeurCoeff, -1)) {
if (valeurCoeff < 0) {
stock = fraction(valeurCoeff).mathq + nomVariable
} else {
stock = devantCoeff + fraction(valeurCoeff).mathq + nomVariable
}
}
}
return stock
}
/**
* Cette fonction écrit correctement une somme de monome (pour un polynôme ou autre, la variable pouvant être différente d’un monome à l’autre)
* @param {Array} [tabCoeff] nombre réel qui, s’il est décimal, sera écrit sous forme fractionnaire
* @param {Array} [tabVariables]
* @return {String}
*/
export function sommeMonomes (tabCoeff, tabVariables) {
let stock = ''
let entreLesChaines = ''
for (let i = 0; i < tabCoeff.length; i++) {
if (tabCoeff[i] !== 0 && i > 0) entreLesChaines = '+'
stock = stock + monome(tabCoeff[i], entreLesChaines, tabVariables[i])
}
if (stock.charAt(0) === '+') stock = stock.substring(1, stock.length)
if (stock === '') stock = '0'
return stock
}
/**
* Cette fonction renvoie le vecteur AB version mathquil en écrivant vLatex("AB")
* @param {string} [strAB] chaine représentant un vecteur
* @return {string}
*/
export function vLatex (strAB) {
return '\\vecteur{' + strAB + '}'
}
/**
* Cette fonction renvoie un entier aléatoire entre entierMini inclus, entierMaxi inclus sans tomber sur les éléments du tableau tabSauf
* @param {number} [entierMini] entier minimal
* @param {number} [entierMaxi] entier maximal
* @param {Array} [tabSauf] liste des entiers à éviter
* @return {Number}
*/
export function entierAlea (entierMini, entierMaxi, tabSauf) {
let stock
do {
stock = entierMini + Math.floor((entierMaxi - entierMini + 1) * Math.random())
} while (tabSauf.includes(stock))
return stock
}
/**
* Cette fonction renvoie le vecteur égal au produit vectoriel de deux vecteurs de l’espace
* @param {Array} [U] tableau de 3 nombres
* @param {Array} [V] tableau de 3 nombres
* @return {Array}
*/
export function produitVectoriel (U, V) {
return [U[1] * V[2] - U[2] * V[1],
U[2] * V[0] - U[0] * V[2],
U[0] * V[1] - U[1] * V[0]]
}
/**
* Calcul le pgcd du tableau de nombres d’une manière bizarre
* - si y’en a pas ça retourne 0
* - si y’en a qu’un ça retourne sa valeur absolue
* - si y’en a plusieurs, on prend leur valeur absolue, puis on regarde le pgcd par paire en retournant le plus grand des deux si l’un est nul…
* @param nombres
* @private
* @return {number}
*/
export function pgcdZarb (nombres) {
// ça les calculait par deux, en prenant le plus grand lorsque l’un était nul, ça revient à supprimer les 0 du tableau
nombres = nombres.filter(nb => nb !== 0).map(Math.abs)
if (nombres.length === 0) return 0
if (nombres.length === 1) return nombres[0]
return pgcdMulti(nombres)
}