from __future__ import division
import sys
import src.scripts.Mes_fctions.Mes_fctions_deterministes
from src.scripts.Mes_fctions.Mes_fctions_deterministes import *
from sympy import Rational
import random
from math import *
from src.scripts.pxs_runtime import myst
[docs]
def randnbres(n, p):
"""
Retourne une liste de n rationnels, tirés aléatoirement entre 0 et p, mais dont la somme vaut 1
Paramètres:
- n (int): Nombre de valeurs rationnelles à générer
- p (int): Borne supérieure pour les valeurs aléatoires (exclusif)
Retourne:
- list: Liste de n rationnels dont la somme est égale à 1
"""
# Générer n nombres entiers aléatoires entre 0 et p-1
l = [random.randint(0, p-1) for _ in range(n)]
# Calculer la somme totale
A = sum(l)
# Si la somme est 0, on génère au moins un nombre non nul
if A == 0:
index = random.randint(0, n-1)
l[index] = random.randint(1, p-1)
A = l[index]
# Convertir chaque nombre en rationnel pour que la somme soit 1
m = [Rational(val, A) for val in l]
return m
[docs]
def randnbresstrictpositifs(n, k, p):
"""
Retourne une liste de n entiers, tirés aléatoirement entre k et p
Paramètres:
- n (int): Nombre d'entiers à générer
- k (int): Borne inférieure (incluse)
- p (int): Borne supérieure (exclue)
Retourne:
- list: Liste de n entiers aléatoires dans l'intervalle [k, p-1]
"""
# Générer directement n nombres aléatoires entre k et p-1
return [random.randint(k, p-1) for _ in range(n)]
[docs]
def Multiple_of_p_in_L(p, L):
"""
Créer, à partir de la liste L, une liste ne contenant que les élements
de L qui sont divisibles par p
Paramètres:
- p (int): Le diviseur
- L (list): Liste d'entiers à filtrer
Retourne:
- list: Liste des éléments de L divisibles par p
"""
return [x for x in L if x % p == 0]
[docs]
def rand_p_proba_a_partir_list(p, L):
"""
Retourne une liste composée de p éléments de
la liste initiale L, pris au hasard (uniformément)
Paramètres:
- p (int): Nombre d'éléments à sélectionner
- L (list): Liste source
Retourne:
- list: Une liste de p éléments tirés au hasard de L
"""
# Vérifier que p n'est pas supérieur à la longueur de L
if p > len(L):
p = len(L)
# Utiliser random.sample pour sélectionner p éléments aléatoires sans remise
return random.sample(L, p)
[docs]
def Test_proba_pris_in_list(L, ind, p, nber_max, Lpartielle):
"""
Teste si le nombre L[ind] peut être choisi comme valeur d'une probabilité.
Cette fonction vérifie si L[ind] peut être accepté comme poids d'une probabilité en tenant compte de:
- La somme totale des poids, qui ne doit pas dépasser nber_max (pour pouvoir renormaliser)
- Il faut avoir p probabilités au total
- On a déjà sélectionné len(Lpartielle) poids
Paramètres:
- L (list): Liste des valeurs possibles pour les poids
- ind (int): Indice du poids à tester dans L
- p (int): Nombre total de probabilités à générer
- nber_max (int/float): Valeur maximale pour la somme des poids
- Lpartielle (list): Liste des poids déjà sélectionnés
Retourne:
- int: 1 si L[ind] peut être accepté, 0 sinon
"""
# Somme des poids déjà sélectionnés
sum_partielle = sum(Lpartielle)
# Nombre de poids restant à choisir après celui-ci
remaining = p - len(Lpartielle) - 1
# Vérifier si la contrainte peut être satisfaite avec ce poids
# 1. La somme actuelle + le nouveau poids + les poids minimaux restants ≤ nber_max
if sum_partielle + L[ind] + remaining * L[0] > nber_max:
return 0
return 1
[docs]
def Poids_d_une_proba_in_list(Linit, p, nber_max):
"""
Renvoie une liste de p poids, pris dans la liste Linit
dont la somme vaut nber_max, pour autant que ce soit possible
Paramètres:
- Linit (list): Liste des valeurs possibles pour les poids
- p (int): Nombre de poids à sélectionner
- nber_max (int/float): Valeur cible pour la somme des poids
Retourne:
- list: Liste de p poids dont la somme est nber_max, ou None si impossible
"""
# Vérifier si la somme est possible
min_possible = p * min(Linit) # Somme minimale possible
max_possible = p * max(Linit) # Somme maximale possible
if nber_max < min_possible or nber_max > max_possible:
return None # Impossible d'atteindre la somme cible
# Trier la liste pour faciliter la recherche
Linit_sorted = sorted(Linit)
def backtrack(index, current_sum, current_list):
# Si nous avons sélectionné p éléments et la somme est correcte
if len(current_list) == p and current_sum == nber_max:
return current_list.copy() # Important de retourner une copie
# Si nous avons dépassé la somme cible ou trop d'éléments
if current_sum > nber_max or len(current_list) >= p:
return None
# Si nous ne pouvons pas atteindre la somme cible avec les éléments restants
min_remaining = (p - len(current_list)) * Linit_sorted[0]
max_remaining = (p - len(current_list)) * Linit_sorted[-1]
if current_sum + min_remaining > nber_max or current_sum + max_remaining < nber_max:
return None
# Essayer chaque élément
for i in range(len(Linit)): # Parcourir toute la liste car nous avons besoin de l'index dans Linit, pas Linit_sorted
# Éviter de réutiliser les éléments déjà utilisés
if Linit[i] not in current_list or current_list.count(Linit[i]) < Linit.count(Linit[i]):
# Ajouter l'élément à notre sélection actuelle
current_list.append(Linit[i])
# Récursivement essayer avec cet élément
result = backtrack(i, current_sum + Linit[i], current_list)
# Si nous avons trouvé une solution, la retourner
if result:
return result
# Sinon, retirer l'élément et essayer le suivant
current_list.pop()
return None
# Commencer le backtracking
return backtrack(0, 0, [])
from math import sqrt, exp, pi
[docs]
def nor(x):
"""
Calcule la densité de la loi normale standard N(0,1) au point x.
Paramètre:
- x (float): Point où évaluer la densité
Retourne:
- float: Valeur de la densité de probabilité en x
"""
return (1 / sqrt(2 * pi)) * exp(-0.5 * x**2)
from sympy import Symbol, Piecewise, Abs
[docs]
def fctionofafiniteRV(f, X):
"""
Crée une nouvelle variable aléatoire finie Y = f(X) à partir d'une variable aléatoire
finie X existante et d'une fonction f.
Parameters:
-----------
f : callable
La fonction à appliquer à la variable aléatoire X
X : RandomSymbol
Une variable aléatoire finie (de type FiniteRV)
Returns:
--------
RandomSymbol
La nouvelle variable aléatoire Y = f(X)
Si la somme des probabilités n'est pas égale à 1, retourne un message d'erreur
Example:
--------
>>> from sympy.stats import FiniteRV, density
>>> from sympy import Rational
>>> X = FiniteRV('X', {0: Rational(1, 3), 1: Rational(2, 3)})
>>> Y = fctionofafiniteRV(lambda x: x**2, X)
>>> density(Y).dict
{0: Rational(1, 3), 1: Rational(2, 3)}
"""
# Récupération des noms pour créer un nom descriptif
stX = str(X)
stf = str(f)
# Récupération du dictionnaire de densité de X
pmf_X = density(X).dict
# Création du nouveau dictionnaire pour f(X)
dico = {}
# Application de la fonction f à chaque valeur possible de X
for key, value in pmf_X.items():
new_key = f(key)
# Agrégation des probabilités pour les valeurs identiques
dico[new_key] = dico.get(new_key, 0) + value
# Vérification que la somme des probabilités vaut 1
# Note: cette vérification est probablement superflue car on ne fait que
# redistribuer les probabilités existantes, donc la somme reste 1
total_prob = sum(dico.values())
# Si la somme est 1 (ou très proche), on crée la nouvelle VA
if abs(total_prob - 1) < 1e-10: # Tolérance pour les erreurs d'arrondi
name = f"{stf}_of_{stX}"
return FiniteRV(name, dico)
else:
return f"Error: The sum of probabilities ({total_prob}) does not equal 1"
[docs]
def ExpandFiniteRV(f, X, name_of_f_of_X_for_LaTeX, ponctu=''):
"""
Génère une représentation LaTeX de la distribution de probabilité de f(X).
Parameters:
-----------
f : callable
La fonction à appliquer à la variable aléatoire X
X : RandomSymbol
Une variable aléatoire finie
name_of_f_of_X_for_LaTeX : str
Nom à utiliser pour f(X) dans la sortie LaTeX
ponctu : str, optional
Type de ponctuation à utiliser ('point', 'virg', ou '')
Returns:
--------
str
La représentation LaTeX de la distribution de probabilité de f(X)
"""
# Définir la ponctuation
terminaison = '.' if ponctu == 'point' else (',' if ponctu == 'virg' else '')
# Symbole de probabilité et nom de la variable
U = 'mathbf{P}' # Utiliser \mathbf{P} au lieu de \bP
T = name_of_f_of_X_for_LaTeX
# Calculer f(X) en tant que variable aléatoire
alpha = fctionofafiniteRV(f, X)
# Extraire les valeurs et probabilités
density_dict = density(alpha).dict
values = list(density_dict.keys())
probabilities = list(density_dict.values())
# Construire la sortie LaTeX
latex_output = myst(r"""\begin{align*}""", globals(), locals())
# Traiter toutes les paires (valeur, probabilité)
n = len(density_dict)
for i in range(n):
s = str(values[i])
r = str(probabilities[i])
# Définir la ponctuation appropriée
if i == n - 1: # Dernier élément
punct = terminaison
else:
punct = ','
# Ajouter la ligne à la sortie avec des parenthèses cohérentes
latex_output += myst(r"""&\\py{U}(\py{T}=\py{s})=\py{r}\py{punct}&""", globals(), locals())
# Ajouter un saut de ligne tous les 4 éléments (sauf pour le dernier)
if (i + 1) % 4 == 0 and i < n - 1:
latex_output += "\n"
latex_output += myst(r"""\end{align*}""", globals(), locals())
return latex_output
# A commenter!!!!!!
[docs]
def ExpandExpFiniteRV(f, X, name_of_the_original_rv, latex_name_of_f_of_alpha,
name_funct_and_name_rv, ponctu=''):
"""
Génère une représentation LaTeX du calcul de l'espérance E[f(X)],
où X est une variable aléatoire finie.
Parameters:
-----------
f : callable
La fonction à appliquer à la variable aléatoire X
X : RandomSymbol
Une variable aléatoire finie
name_of_the_original_rv : str
Nom de la variable aléatoire X pour l'affichage LaTeX
latex_name_of_f_of_alpha : str
Représentation LaTeX de f(alpha)
name_funct_and_name_rv : str
Représentation LaTeX de f(X) pour l'en-tête E[f(X)]
ponctu : str, optional
Type de ponctuation à utiliser ('point', 'virg', ou '')
Returns:
--------
str
La représentation LaTeX du calcul de E[f(X)]
"""
# Définir la ponctuation
terminaison = '.' if ponctu == 'point' else (',' if ponctu == 'virg' else '')
# Calculer f(X) en tant que variable aléatoire
alpha = fctionofafiniteRV(f, X)
# Extraire les valeurs et probabilités
density_dict = density(alpha).dict
values = list(density_dict.keys())
probabilities = list(density_dict.values())
# Calculer l'espérance E[f(X)]
expected_value = sum(v * p for v, p in zip(values, probabilities))
result = str(expected_value)
# Construire l'en-tête LaTeX
latex_output = "\\begin{align*}\n"
latex_output += "\\mathbf{E}[" + name_funct_and_name_rv + "]&=\\sum_{\\alpha\\in " + \
name_of_the_original_rv + "(\\Omega)}" + \
latex_name_of_f_of_alpha + "\\cdot\\mathbf{P}(" + \
name_of_the_original_rv + "=\\alpha)\\\\\n"
# Construire les lignes de calcul
n = len(density_dict)
items_per_line = 5 # Nombre d'éléments par ligne
current_line = "&="
for i in range(n):
value = values[i]
prob = probabilities[i]
# Formater le terme
if i > 0 and i % items_per_line == 0:
current_line += "\\\\\n&\\hspace{2ex}+ "
elif i > 0:
current_line += " + "
# Dernier terme de la somme
if i == n - 1:
current_line += f"{value}\\cdot {prob}\\\\"
else:
current_line += f"{value}\\cdot {prob}"
# Ajouter le résultat final
latex_output += current_line + "\n"
latex_output += f"&={result}{terminaison}\n"
latex_output += "\\end{align*}\n"
return latex_output
# A vérifier !!!!!!
[docs]
def ComputeExpFiniteRV(f, X):
"""
Calcule l'espérance mathématique E[f(X)] pour une variable aléatoire finie X.
Cette fonction est un cas particulier de ComputeExp_p_FiniteRV avec p=1.
Parameters:
-----------
f : callable
La fonction à appliquer à la variable aléatoire X
X : RandomSymbol
Une variable aléatoire finie
Returns:
--------
sympy.Expr
L'espérance E[f(X)]
Example:
--------
>>> from sympy import Rational
>>> from sympy.stats import FiniteRV
>>> X = FiniteRV('X', {1: Rational(1, 4), 2: Rational(1, 2), 3: Rational(1, 4)})
>>> ComputeExpFiniteRV_optimized(lambda x: x**2, X) # E[X^2]
Rational(5, 2)
"""
# Calculer la variable aléatoire f(X)
transformed_X = fctionofafiniteRV(f, X)
# Calculer E[f(X)] directement
return sum(value * prob for value, prob in density(transformed_X).dict.items())
# A vérifier !!!!!!
[docs]
def VarFiniteRV(f, X):
"""
Calcule la variance Var(f(X)) d'une variable aléatoire finie X transformée par une fonction f.
Utilise la formule: Var(f(X)) = E[f(X)²] - E[f(X)]²
Parameters:
-----------
f : callable
La fonction à appliquer à la variable aléatoire X
X : RandomSymbol
Une variable aléatoire finie
Returns:
--------
sympy.Expr
La variance de f(X)
Example:
--------
>>> from sympy import Rational
>>> from sympy.stats import FiniteRV
>>> X = FiniteRV('X', {1: Rational(1, 2), 2: Rational(1, 2)})
>>> VarFiniteRV_optimized(lambda x: x**2, X)
Rational(9, 4)
"""
# Calculer f(X) en tant que variable aléatoire
transformed_X = fctionofafiniteRV(f, X)
# Récupérer la distribution de probabilité
pmf = density(transformed_X).dict
# Calculer E[f(X)] et E[f(X)²] en une seule passe
expected_value = 0
expected_square = 0
for value, probability in pmf.items():
expected_value += value * probability
expected_square += value**2 * probability
# Calculer la variance: Var(f(X)) = E[f(X)²] - E[f(X)]²
variance = expected_square - expected_value**2
return variance
# A vérifier !!!!!!
[docs]
def ComputeExp_p_FiniteRV(f, X, p):
"""
Calcule l'espérance mathématique E[f(X)^p] pour une variable aléatoire finie X,
une fonction f et un exposant p.
Parameters:
-----------
f : callable
La fonction à appliquer à la variable aléatoire X
X : RandomSymbol
Une variable aléatoire finie
p : int or float
L'exposant à appliquer au résultat de f(X)
Returns:
--------
sympy.Expr
L'espérance E[f(X)^p]
Example:
--------
>>> from sympy import Rational
>>> from sympy.stats import FiniteRV
>>> X = FiniteRV('X', {1: Rational(1, 3), 2: Rational(2, 3)})
>>> ComputeExp_p_FiniteRV_optimized(lambda x: x, X, 2) # E[X^2]
Rational(5, 3)
"""
# Définir la fonction composée g(x) = f(x)^p
def g(x):
return f(x)**p
# Alternative si la fonction compo existe:
# g = compo(f, p)
# Calculer la variable aléatoire g(X)
transformed_X = fctionofafiniteRV(g, X)
# Calculer directement E[g(X)] en une seule passe
expected_value = sum(value * prob for value, prob in density(transformed_X).dict.items())
return expected_value
[docs]
def randnbresstrictpositifsreel(n, k, p, s):
"""
Génère une liste de n nombres réels positifs aléatoires.
Parameters:
-----------
n : int
Nombre de valeurs à générer
k : int
Borne inférieure pour la partie entière des nombres
p : int
Borne supérieure pour la partie entière des nombres (non incluse)
s : int
Nombre de chiffres significatifs après la virgule
(Note: la fonction actuelle utilise toujours 1 décimale indépendamment de s)
Returns:
--------
list
Liste de n nombres réels aléatoires entre k et p avec des décimales
Example:
--------
>>> from sympy.stats import DiscreteUniform, sample_iter
>>> randnbresstrictpositifsreel_optimized(5, 1, 10, 1)
[1.7, 3.4, 7.9, 2.3, 8.6] # Résultat exemple avec des valeurs aléatoires
"""
from sympy.stats import DiscreteUniform, sample_iter
import random
# Génération plus efficace utilisant directement les fonctions appropriées
if s <= 0:
# Si aucun chiffre après la virgule n'est demandé, retourner des entiers
integers = list(sample_iter(DiscreteUniform('W', list(range(k, p))), numsamples=n))
return integers
# Créer une liste pour stocker les résultats
result = []
# Générer une liste de n entiers aléatoires entre k et p-1
integers = list(sample_iter(DiscreteUniform('W', list(range(k, p))), numsamples=n))
# Générer une liste de n nombres décimaux entre 0 et 0.9 (un chiffre significatif)
decimals = [round(random.random(), s) for _ in range(n)]
# Combiner les deux pour créer les nombres réels
for i in range(n):
result.append(round(integers[i] + decimals[i], s))
return result