Source code for Mes_fctions_d_analyse

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Mar 17 19:11:52 2022

@author: jlebovits
"""

from __future__ import division
import sys
import random
from copy import deepcopy

import src.scripts.Mes_fctions.Mes_fctions_deterministes
from src.scripts.Mes_fctions.Mes_fctions_deterministes import * 

import src.scripts.Mes_fctions.Mes_fctions_generalistes
from src.scripts.Mes_fctions.Mes_fctions_generalistes import * 

import src.scripts.Mes_fctions.Mes_fctions_probabilistes
from src.scripts.Mes_fctions.Mes_fctions_probabilistes import * 

import src.scripts.Mes_fctions.Mes_fctions_d_ecriture_Latex
from src.scripts.Mes_fctions.Mes_fctions_d_ecriture_Latex import *

import src.scripts.Mes_fctions.Mes_fctions_d_alg_lineaire_bis
from src.scripts.Mes_fctions.Mes_fctions_d_alg_lineaire_bis import * 

import src.scripts.Mes_fctions.Mes_fctions_generalistes_bis
from src.scripts.Mes_fctions.Mes_fctions_generalistes_bis import * 

from sympy import *
from src.scripts.pxs_runtime import get_pxs_lang, myst

[docs] def pxs_config(): pxs_lang = get_pxs_lang() if pxs_lang == 'fr': return {"ln_notation": True, "mul_symbol": "", "order": "lex", "decimal_separator": "comma"} else: return {"ln_notation": True, "mul_symbol": "", "order": "lex", "decimal_separator": "dot"}
[docs] def pxsl_par_minus(expr): """ Wraps a LaTeX expression in parentheses if it starts with a minus sign. Parameters ---------- expr : sympy expression or numeric The expression to be displayed. Returns ------- myst : LaTeX-formatted object (via the myst function) The LaTeX string, wrapped in parentheses if negative. """ config_standard = pxs_config() # Vérifie si l'expression, convertie en chaîne, commence par un signe '-' # Cela permet d'identifier les expressions négatives (par exemple -x, -3, -sin(x)...) if str(expr).startswith('-'): # Si l'expression est négative, on ajoute des parenthèses autour de son affichage LaTeX # Exemple : -x → \left(-x\right) # myst() est ici utilisée pour insérer la version LaTeX dynamique de l'expression return myst( r"""\left(\py{latex(expr, **config_standard)}\right) """, globals(), locals() ) else: # Si l'expression n’est pas négative, on la renvoie simplement en LaTeX sans parenthèses return myst( r"""\py{latex(expr, **config_standard)} """, globals(), locals() )
[docs] def pxsl_par(expr): """ Wraps a LaTeX expression in parentheses if it starts with a minus sign or if ti is an Add. Parameters ---------- expr : sympy expression or numeric The expression to be displayed. Returns ------- myst : LaTeX-formatted object (via the myst function) The LaTeX string, wrapped in parentheses if negative or Add. """ config_standard = pxs_config() # Vérifie si l'expression, convertie en chaîne, commence par un signe '-' # Cela permet d'identifier les expressions négatives (par exemple -x, -3, -sin(x)...) if str(expr).startswith('-') or isinstance(expr, Add): # Si l'expression est négative, on ajoute des parenthèses autour de son affichage LaTeX # Exemple : -x → \left(-x\right) # myst() est ici utilisée pour insérer la version LaTeX dynamique de l'expression return myst( r"""\left(\py{latex(expr, **config_standard)}\right) """, globals(), locals() ) else: # Si l'expression n’est pas négative, on la renvoie simplement en LaTeX sans parenthèses return myst( r"""\py{latex(expr, **config_standard)} """, globals(), locals() )
[docs] def pxsl_par_add(expr): """ Wraps a LaTeX expression in parentheses if it is an Add object. Parameters ---------- expr : sympy expression or numeric The expression to be displayed. Returns ------- myst : LaTeX-formatted object (via the myst function) The LaTeX string, wrapped in parentheses if Add. """ config_standard = pxs_config() # Vérifie si l'expression, convertie en chaîne, commence par un signe '-' # Cela permet d'identifier les expressions négatives (par exemple -x, -3, -sin(x)...) if isinstance(expr, Add): # Si l'expression est négative, on ajoute des parenthèses autour de son affichage LaTeX # Exemple : -x → \left(-x\right) # myst() est ici utilisée pour insérer la version LaTeX dynamique de l'expression return myst( r"""\left(\py{latex(expr, **config_standard)}\right) """, globals(), locals() ) else: # Si l'expression n’est pas négative, on la renvoie simplement en LaTeX sans parenthèses return myst( r"""\py{latex(expr, **config_standard)} """, globals(), locals() )
def _pxs_resolve_pairs(var = Symbol('x'), f1 = None, f2 = None, type_int = None): """ Resolves the function pairs provided by the user for integration by parts. Allowed cases: (u, dv) or (du, v). Returns consistent (u, du, v, dv) tuples. Parameters ---------- var : sympy Symbol The variable of integration. f1, f2 : sympy expressions The two functions or derivatives provided by the user. type_int : str Type of pairing expected, either "udv" for (u, dv) or "vdu" for (du, v). Returns ------- tuple A tuple (u, du, v, dv) with coherent expressions for integration by parts. """ # Si le type correspond à (u, dv) # On dérive f1 pour obtenir du et on intègre f2 pour obtenir v if type_int == "udv": du = diff(f1, var) v = integrate(f2, var) return f1, du, v, f2 # Si le type correspond à (du, v) # On intègre f2 pour obtenir u et on dérive f1 pour obtenir dv if type_int == "vdu": u = integrate(f2, var) dv = diff(f1, var) return u, f2, f1, dv def _pxsl_choose_udv(u, du, v, dv, var = Symbol('x')): """ Generates bilingual LaTeX text (English/French) explaining the choice of functions u and v' in an integration by parts setup. Parameters ---------- u : sympy expression Function chosen as u(x). du : sympy expression Derivative of u(x). v : sympy expression Function chosen as v(x). dv : sympy expression Derivative of v(x), i.e., v'(x). Returns ------- str A LaTeX-formatted bilingual text describing u, v', and their derivatives. """ config_standard = pxs_config() text = "" # Introduction : phrase bilingue annonçant le choix de u et v' text = myst(r""" \en{with}\fr{On choisit $u$ et $v'$ tels que :} """, globals(), locals()) # Bloc d'équations affichant les expressions de u(x) et v'(x) text += myst(r""" \en{\begin{equation*} &u = \py{latex(u, **config_standard)}& &\textrm{and}& &v' = \py{latex(dv, **config_standard)}& \end{equation*}} \fr{\begin{equation*} &u(\py{var}) = \py{latex(u, **config_standard)}& &\textrm{et}& &v'(\py{var}) = \py{latex(dv, **config_standard)}.& \end{equation*}} """, globals(), locals()) # Transition bilingue vers les dérivées et primitives correspondantes text += myst(r""" \en{gives}\fr{On en déduit donc} """) # Bloc d'équations affichant u'(x) et v(x) text += myst(r""" \en{\begin{equation*} &u' = \py{latex(du, **config_standard)}& &\textrm{and}& &v = \py{latex(v, **config_standard)}.& \end{equation*}} \fr{\begin{equation*} &u'(\py{var}) = \py{latex(du, **config_standard)}& &\textrm{et}& &v(\py{var}) = \py{latex(v, **config_standard)}.& \end{equation*}} """, globals(), locals()) # Retourne le texte LaTeX complet (mélange de phrases et équations) return text def _pxsl_choose_vdu(u, du, v, dv, var = Symbol('x')): """ Generates bilingual LaTeX text (English/French) explaining the choice of functions u' and v in an integration by parts setup. Parameters ---------- u : sympy expression Function corresponding to u(x). du : sympy expression Derivative of u(x), i.e., u'(x). v : sympy expression Function chosen as v(x). dv : sympy expression Derivative of v(x), i.e., v'(x). Returns ------- str A LaTeX-formatted bilingual text describing u', v, and their corresponding functions and derivatives. """ config_standard = pxs_config() text = "" # Introduction : phrase bilingue annonçant le choix de u' et v text = myst(r""" \en{with}\fr{On choisit $u'$ et $v$ tels que :} """, globals(), locals()) # Bloc d'équations affichant u'(x) et v(x) text += myst(r""" \en{\begin{equation*} &u' = \py{latex(du, **config_standard)}& &\textrm{and}& &v = \py{latex(v, **config_standard)}& \end{equation*}} \fr{\begin{equation*} &u'(\py{var}) = \py{latex(du, **config_standard)}& &\textrm{et}& &v(\py{var}) = \py{latex(v, **config_standard)}.& \end{equation*}} """, globals(), locals()) # Transition bilingue vers les primitives et dérivées correspondantes text += myst(r""" \en{gives}\fr{On en déduit donc} """) # Bloc d’équations affichant u(x) et v'(x) text += myst(r""" \en{\begin{equation*} &u = \py{latex(u, **config_standard)}& &\textrm{and}& &v' = \py{latex(dv, **config_standard)}.& \end{equation*} } \fr{\begin{equation*} &u(\py{var}) = \py{latex(u, **config_standard)}& &\textrm{et}& &v'(\py{var}) = \py{latex(dv, **config_standard)}.& \end{equation*} } """, globals(), locals()) # Retourne le texte LaTeX complet (phrases bilingues et équations) return text def _pxsl_resolution_prim(u, du, v, dv, type_int, var = Symbol('x')): """ Generates the bilingual LaTeX formula showing the integration by parts resolution in the case of an *indefinite integral* (primitive). Depending on the type of pair chosen ("udv" or "vdu"), the function builds the appropriate LaTeX equation for: ∫ u·v' dx = u·v − ∫ u'·v dx or ∫ u'·v dx = u·v − ∫ u·v' dx Parameters ---------- u : sympy expression Function u(x). du : sympy expression Derivative of u(x). v : sympy expression Function v(x). dv : sympy expression Derivative of v(x), i.e., v'(x). type_int : str Type of integration by parts ("udv" or "vdu"). Returns ------- str A LaTeX-formatted bilingual text representing the integration by parts formula. """ # Cas où l'utilisateur a fourni (u, dv) # Construction de la formule : ∫u·v' dx = u·v − ∫u'·v dx if type_int == "udv": text = myst(r""" \begin{equation*} \label{eq} \int \py{pxsl_par_add(u)}\cdot \py{pxsl_par_add(dv)} \ d\py{var} &= \py{pxsl_par_add(u)}\cdot \py{pxsl_par(v)} - \int \py{pxsl_par_add(du)} \cdot \py{pxsl_par(v)} \ d\py{var}\\ """, globals(), locals()) # Cas où l'utilisateur a fourni (du, v) # Construction de la formule : ∫u'·v dx = u·v − ∫u·v' dx if type_int == "vdu": text = myst(r""" \begin{equation*} \label{eq} \int \py{pxsl_par_add(du)}\cdot \py{pxsl_par_add(v)} \ d\py{var} &= \py{pxsl_par_add(u)}\cdot \py{pxsl_par(v)} - \int \py{pxsl_par_add(u)} \cdot \py{pxsl_par(dv)} \ d\py{var}\\ """, globals(), locals()) # Retourne le texte LaTeX de la résolution par parties return text def _pxsl_resolution_int(u, du, v, dv, type_int, a, b, var = Symbol('x')): """ Generates the bilingual LaTeX formula showing the integration by parts resolution in the case of a *definite integral* with bounds a and b. Depending on the type of pair chosen ("udv" or "vdu"), the function builds the appropriate LaTeX equation for: ∫[a,b] u·v' dx = [u·v]_a^b − ∫[a,b] u'·v dx or ∫[a,b] u'·v dx = [u·v]_a^b − ∫[a,b] u·v' dx Parameters ---------- u : sympy expression Function u(x). du : sympy expression Derivative of u(x). v : sympy expression Function v(x). dv : sympy expression Derivative of v(x), i.e., v'(x). type_int : str Type of integration by parts ("udv" or "vdu"). a, b : numeric or symbolic Lower and upper bounds of integration. Returns ------- str A LaTeX-formatted bilingual text representing the definite integral integration by parts formula. """ # Définition des crochets ou barres selon la langue (français/anglais) # bl = left bracket pour la version française # br = right bracket (ou borne d’évaluation) avec indices a et b config_standard = pxs_config() bl = myst(r""" \en{}\fr{\left[} """, globals(), locals()) br = myst(r""" \en{\bigg|_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}}\fr{\right]_{\py{latex(a, **config_satndard)}}^{\py{latex(b, **config_standard)}}} """, globals(), locals()) # Cas (u, dv) : ∫[a,b] u·v' dx = [u·v]_a^b − ∫[a,b] u'·v dx if type_int == "udv": text = myst(r""" \begin{equation*} \label{eq} \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{pxsl_par_add(u)}\cdot \py{pxsl_par(dv)} \ d\py{var} &= \py{bl}\py{pxsl_par_add(u)}\cdot \py{pxsl_par(v)}\py{br} - \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{pxsl_par_add(du)} \cdot \py{pxsl_par(v)} \ d\py{var}\\ """, globals(), locals()) # Cas (du, v) : ∫[a,b] u'·v dx = [u·v]_a^b − ∫[a,b] u·v' dx if type_int == "vdu": text = myst(r""" \begin{equation*} \label{eq} \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{pxsl_par_add(du)}\cdot \py{pxsl_par(v)} \ d\py{var} &= \py{bl}\py{pxsl_par_add(u)}\cdot \py{pxsl_par(v)}\py{br} - \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{pxsl_par_add(u)} \cdot \py{pxsl_par(dv)} \ d\py{var}\\ """, globals(), locals()) # Retourne le texte LaTeX complet de la résolution avec bornes return text def _pxsl_minus(uv, expr, nb_IBP, a = None, b = None, var = Symbol('x')): """ Builds LaTeX fragments for the integration by parts process when handling sign changes and coefficients, with or without integration bounds. Parameters ---------- uv : sympy expression The product term u·v from integration by parts. expr : sympy expression The remaining integral expression after applying integration by parts. nb_IBP : int The number of successive integrations by parts already applied (used to adjust display). a, b : numeric or symbolic, optional Lower and upper bounds of integration. If None, the integral is indefinite. Returns ------- tuple (text, text2) : Two LaTeX strings representing intermediate and simplified steps of the integration by parts process, with correct sign and coefficient handling. """ config_standard = pxs_config() # Si les bornes a et b ne sont pas données → intégrale indéfinie if a is None and b is None: bl = myst(r""" """) br = myst(r""" """) intf = myst(r""" \int """) else: # Si les bornes sont données → intégrale définie bl = myst(r"""\en{}\fr{\left[} """, globals(), locals()) br = myst(r"""\en{\bigg|_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}}\fr{\right]_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}} """, globals(), locals()) intf = myst(r""" \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} """, globals(), locals()) # Extraction du coefficient numérique de expr (partie indépendante de x) # puis gestion du signe et de la valeur absolue if expr.as_independent(var)[0] < 0 and expr.as_independent(var)[0] != -1: coeff = myst(r"""\py{latex(-expr.as_independent(var)[0], **config_standard)} """, globals(), locals()) elif expr.as_independent(var)[0] > 0 and expr.as_independent(var)[0] != 1: coeff = myst(r"""\py{latex(expr.as_independent(var)[0], **config_standard)} """, globals(), locals()) else: coeff = myst(r""" """, globals(), locals()) # Si l’expression commence par un signe négatif if str(expr).startswith('-'): # Cas "plus" après simplification du signe text = myst(r""" &=\py{bl}\py{latex(uv, **config_standard)}\py{br} + \py{coeff} \py{intf} \py{latex(simplify(expr.as_independent(var)[1]), **config_standard)} \ d\py{var} """, globals(), locals()) # Si c’est une deuxième IBP avec bornes données if nb_IBP == 2 and a is not None and b is not None: text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)} - \py{pxsl_par(uv.subs(var,a))} + \py{coeff} \py{intf} \py{latex(expr.as_independent(var)[1], **config_standard)} \ d\py{var} """, globals(), locals()) # Vérifie si la différence symbolique a une forme simplifiée if Add(uv.subs(var,b), - uv.subs(var,a), evaluate = False) != uv.subs(var,b) - uv.subs(var,a): text += myst(r""" \\&=\py{latex(uv.subs(var,b) - uv.subs(var,a), **config_standard)} + \py{coeff} \py{intf} \py{latex(expr.as_independent(var)[1], **config_standard)} \ dx """, globals(), locals()) # Deuxième bloc textuel, version simplifiée text2 = myst(r""" &=\py{bl}\py{latex(uv, **config_standard)}\py{br} + \py{coeff} """, globals(), locals()) else: # Cas standard (pas de signe négatif initial) text = myst(r""" &=\py{bl}\py{latex(uv, **config_standard)}\py{br} - \py{coeff} \py{intf} \py{latex(simplify(expr.as_independent(var)[1]), **config_standard)} \ d\py{var} """, globals(), locals()) # Gestion spéciale pour la deuxième IBP avec bornes if nb_IBP == 2 and a is not None and b is not None: text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)} - \py{pxsl_par(uv.subs(var,a))} - \py{coeff} \py{intf} \py{latex(expr.as_independent(var)[1], **config_standard)} \ d\py{var} """, globals(), locals()) # Vérifie si la forme développée diffère de la soustraction directe if Add(uv.subs(var,b), - uv.subs(var,a), evaluate = False) != uv.subs(var,b) - uv.subs(var,a): text += myst(r""" \\&=\py{latex(uv.subs(var,b)-uv.subs(var,a), **config_standard)} - \py{coeff} \py{intf} \py{latex(expr.as_independent(var)[1], **config_standard)} \ d\py{var} """, globals(), locals()) # Deuxième bloc textuel, version simplifiée text2 = myst(r""" &=\py{bl}\py{latex(uv, **config_standard)}\py{br} - \py{coeff} """, globals(), locals()) # Retourne les deux chaînes LaTeX construites return text, text2 def _pxsl_explain(u, du, v, dv, type_int, nb_IBP, a = None, b = None, var = Symbol('x')): """ Builds a bilingual LaTeX explanation for the integration by parts process, using either the primitive form or the definite integral form. The function combines: - the core integration by parts equation (via _pxsl_resolution_prim or _pxsl_resolution_int) - the corresponding minus/plus term adjustments (via _pxsl_minus) depending on the integration type ("udv" or "vdu") and the presence of bounds. Parameters ---------- u : sympy expression Function u(x). du : sympy expression Derivative of u(x). v : sympy expression Function v(x). dv : sympy expression Derivative of v(x), i.e., v'(x). type_int : str Integration by parts type: "udv" for (u, dv) or "vdu" for (du, v). nb_IBP : int Number of integration by parts steps performed (for formatting purposes). a, b : numeric or symbolic, optional Integration bounds. If None, the integral is indefinite. Returns ------- tuple (text, text2) : Two LaTeX strings representing the detailed explanation and simplified version of the integration by parts process. """ # Si les bornes ne sont pas fournies → cas d’intégrale indéfinie if a is None and b is None: # Étape 1 : construire la résolution pour une primitive text = _pxsl_resolution_prim(u, du, v, dv, type_int, var) # Étape 2 : ajouter les termes avec le bon signe selon le type d’intégration if type_int == "udv": text += _pxsl_minus(u*v, v*du, nb_IBP, var = var)[0] text2 = _pxsl_minus(u*v, v*du, nb_IBP, var = var)[1] else: text += _pxsl_minus(u*v, u*dv, nb_IBP, var = var)[0] text2 = _pxsl_minus(u*v, u*dv, nb_IBP, var = var)[1] # Retourne le texte complet et sa version simplifiée return text, text2 # Sinon → cas d’intégrale définie else: # Étape 1 : construire la résolution avec bornes text = _pxsl_resolution_int(u, du, v, dv, type_int, a, b, var) # Étape 2 : ajouter les termes corrigés en fonction du type d’intégration if type_int == "udv": text += _pxsl_minus(u*v, v*du, nb_IBP, a, b, var)[0] text2 = _pxsl_minus(u*v, v*du, nb_IBP, a, b, var)[1] else: text += _pxsl_minus(u*v, u*dv, nb_IBP, a, b, var)[0] text2 = _pxsl_minus(u*v, u*dv, nb_IBP, a, b, var)[1] # Retourne le texte complet et la version simplifiée avec bornes return text, text2 def _pxsl_conclude(uv, expr, origin_int, var = Symbol('x')): """ Generates the final bilingual LaTeX step that concludes the integration by parts process, displaying the complete evaluated primitive with constant C. Parameters ---------- uv : sympy expression The product term u·v obtained during integration by parts. expr : sympy expression The remaining part of the expression (integral to be evaluated or simplified). origin_int : sympy expression The original integral expression (used for final verification and display). Returns ------- str A LaTeX-formatted bilingual text showing the final result of the integration, including the constant of integration. """ config_standard = pxs_config() # Extraction du coefficient numérique de l’expression (partie indépendante de x) # Gestion du signe et des cas particuliers (valeurs 1 ou -1 ignorées) if expr.as_independent(var)[0] < 0 and expr.as_independent(var)[0] != -1: coeff = myst(r"""\py{latex(-expr.as_independent(var)[0], **config_standard)} """, globals(), locals()) dot = myst(r"""\cdot """) elif expr.as_independent(var)[0] > 0 and expr.as_independent(var)[0] != 1: coeff = myst(r"""\py{latex(expr.as_independent(var)[0], **config_standard)} """, globals(), locals()) dot = myst(r"""\cdot """) else: coeff = myst(r""" """, globals(), locals()) # Si l’expression commence par un signe négatif if str(expr).startswith('-'): # Cas où le signe devient "plus" après simplification text = myst(r""" \\&= \py{latex(uv, **config_standard)} + \py{coeff}\py{dot} \py{pxsl_par(integrate(expr.as_independent(var)[1], x))} + C """, globals(), locals()) else: # Cas standard : on garde le signe négatif devant le terme intégré text = myst(r""" \\&= \py{latex(uv, **config_standard)} - \py{coeff}\py{dot}\py{pxsl_par(integrate(expr.as_independent(var)[1], var))} + C """, globals(), locals()) # Ajout de la ligne finale donnant la primitive complète de l’intégrale d’origine text += myst(r"""\\ & = \py{latex(integrate(origin_int, var), **config_standard)} + C, \textrm{ \en{with}\fr{où} }C\textrm{ \en{a real constant}\fr{est une constante réelle}}. \end{equation*} """, globals(), locals()) # Retourne le texte LaTeX complet de conclusion return text def _pxsl_conclude_int(uv, expr, origin_int, a, b, var = Symbol('x')): """ Generates the final bilingual LaTeX step concluding the integration by parts process for a *definite integral* between bounds a and b. This function evaluates and formats the expression: [u·v]_a^b ± coefficient × [∫f(x)dx]_a^b and shows the fully evaluated result of the original definite integral. Parameters ---------- uv : sympy expression The product term u·v obtained during integration by parts. expr : sympy expression The remaining part of the expression (integral to be evaluated or simplified). origin_int : sympy expression The original integral expression (used for final comparison and display). a, b : numeric or symbolic Lower and upper bounds of the definite integral. Returns ------- str A LaTeX-formatted bilingual text showing the final step of the definite integration by parts, with all evaluations and signs displayed correctly. """ config_standard = pxs_config() # Définit les crochets et notations bilingues pour les bornes d’intégration bl = myst(r"""\en{}\fr{\left[} """, globals(), locals()) br = myst(r"""\en{\bigg|_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}}\fr{\right]_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}} """, globals(), locals()) # Extraction du coefficient numérique et gestion du signe # On ajoute aussi les symboles nécessaires selon la présence d’un coefficient if expr.as_independent(var)[0] < 0 and expr.as_independent(var)[0] != -1: coeff = myst(r"""\py{latex(-expr.as_independent(var)[0], **config_standard)} """, globals(), locals()) dot = myst(r"""\cdot """) l_par = myst(r"""\left( """) r_par = myst(r"""\right) """) elif expr.as_independent(var)[0] > 0 and expr.as_independent(var)[0] != 1: coeff = myst(r"""\py{latex(expr.as_independent(var)[0], **config_standard)} """, globals(), locals()) dot = myst(r"""\cdot """) l_par = myst(r"""\left( """) r_par = myst(r"""\right) """) else: coeff = myst(r""" """, globals(), locals()) dot = myst(r""" """) l_par = myst(r""" """) r_par = myst(r""" """) # Si l’expression commence par un signe négatif if expr.could_extract_minus_sign(): # Cas où le signe devient "plus" après simplification text = myst(r""" \\&= \py{latex(uv.subs(var,b), **config_standard)} - \py{pxsl_par(uv.subs(var,a))} + \py{coeff} \py{dot}\py{bl}\py{pxsl_par_minus(integrate(expr.as_independent(var)[1], var))}\py{br}""", globals(), locals()) if isinstance(uv.subs(var,a), Add): text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)}""", globals(), locals()) for term in uv.subs(var,a).as_ordered_terms(): if term.could_extract_minus_sign(): text += myst(r""" + \py{latex(-term, **config_standard)}""", globals(), locals()) else: text += myst(r""" - \py{latex(abs(term), **config_standard)}""", globals(), locals()) text += myst(r""" + \py{coeff} \py{dot}\py{l_par}\py{latex(integrate(expr.as_independent(var)[1], var).subs(var,b), **config_standard)} - \py{pxsl_par(integrate(expr.as_independent(var)[1], var).subs(var,a))}\py{r_par} """, globals(), locals()) elif uv.subs(var,a).could_extract_minus_sign(): text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)} + \py{latex(-uv.subs(var,a), **config_standard)} + \py{coeff} \py{dot}\py{l_par}\py{latex(integrate(expr.as_independent(var)[1], var).subs(var,b), **config_standard)} - \py{pxsl_par(integrate(expr.as_independent(var)[1], var).subs(var,a))}\py{r_par} """, globals(), locals()) else: text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)} - \py{latex(uv.subs(var,a), **config_standard)} + \py{coeff} \py{dot}\py{l_par}\py{latex(integrate(expr.as_independent(var)[1], var).subs(var,b), **config_standard)} - \py{pxsl_par(integrate(expr.as_independent(var)[1], var).subs(var,a))}\py{r_par} """, globals(), locals()) else: # Cas standard : le signe reste négatif devant la deuxième intégrale text = myst(r""" \\&= \py{latex(uv.subs(var,b), **config_standard)} - \py{pxsl_par(uv.subs(var,a))} - \py{coeff}\py{dot}\py{bl}\py{pxsl_par_minus(integrate(expr.as_independent(var)[1], var))}\py{br}""", globals(), locals()) if isinstance(uv.subs(var,a), Add): text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)}""", globals(), locals()) for term in uv.subs(var,a).as_ordered_terms(): if term.could_extract_minus_sign(): text += myst(r""" + \py{latex(-term, **config_standard)}""", globals(), locals()) else: text += myst(r""" - \py{latex(term, **config_standard)}""", globals(), locals()) text += myst(r""" - \py{coeff} \py{dot}\left(\py{latex(integrate(expr.as_independent(var)[1], var).subs(var,b), **config_standard)} - \py{pxsl_par(integrate(expr.as_independent(var)[1], var).subs(var,a))}\right) """, globals(), locals()) elif uv.subs(var,a).could_extract_minus_sign(): text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)} + \py{latex(-uv.subs(var,a), **config_standard)} - \py{coeff} \py{dot}\left(\py{latex(integrate(expr.as_independent(var)[1], var).subs(var,b), **config_standard)} - \py{pxsl_par(integrate(expr.as_independent(var)[1], var).subs(var,a))}\right) """, globals(), locals()) else: text += myst(r""" \\&=\py{latex(uv.subs(var,b), **config_standard)} - \py{latex(uv.subs(var,a), **config_standard)} - \py{coeff} \py{dot}\left(\py{latex(integrate(expr.as_independent(var)[1], var).subs(var,b), **config_standard)} - \py{pxsl_par(integrate(expr.as_independent(var)[1], var).subs(var,a))}\right) """, globals(), locals()) # Ligne finale : égalité avec l’intégrale définie complète d’origine text += myst(r"""\\ & = \py{latex(integrate(origin_int, (var, a, b)), **config_standard)}. \end{equation*} """, globals(), locals()) # Retourne le texte LaTeX complet de conclusion (forme avec bornes) return text def _pxs_explain_IBP(var = Symbol('x'), f1 = None, f2 = None, type_int = None, nb_IBP = 1, a = None, b = None): """ Builds a complete bilingual LaTeX correction text for the Integration by Parts (IBP) process, handling both single and double applications, and supporting definite or indefinite integrals. Depending on the number of integrations by parts (`nb_IBP`) and the type (`type_int`), this function calls all the appropriate sub-functions: - _pxs_resolve_pairs → identifies (u, du, v, dv) - _pxsl_choose_udv/vdu → generates the introduction LaTeX text - _pxsl_explain → generates the main formula - _pxsl_conclude/_int → final step (primitive or definite) - recursively calls itself if nb_IBP = 2 Parameters ---------- x : sympy Symbol The integration variable. f1, f2 : sympy expressions The two parts of the integrand provided by the user. type_int : str Integration by parts type: "udv" for (u, dv) or "vdu" for (du, v). nb_IBP : int, optional Number of integration by parts steps (1 or 2). Default is 1. a, b : numeric or symbolic, optional Lower and upper bounds of integration (if given, produces a definite integral). Returns ------- str A LaTeX-formatted bilingual text that fully explains the integration by parts procedure, with all symbolic steps, coefficients, and final results. """ config_standard = pxs_config() text = "" # --- Définition des éléments de mise en forme selon la présence de bornes --- if a is None and b is None: bl = myst(r""" """) br = myst(r""" """) intf = myst(r""" \int """) else: bl = myst(r"""\en{}\fr{\left[} """, globals(), locals()) br = myst(r"""\en{\bigg|_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}}\fr{\right]_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}}} """, globals(), locals()) intf = myst(r""" \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} """, globals(), locals()) # === Première intégration par parties === u, du, v, dv = _pxs_resolve_pairs(var, f1, f2, type_int) # Introduction selon le type choisi (u,dv) ou (du,v) if type_int == "udv": text += _pxsl_choose_udv(u, du, v, dv, var) else: text += _pxsl_choose_vdu(u, du, v, dv, var) # Phrase bilingue avant l’application de la formule text += myst(r""" \en{So integration by parts gives us:}\fr{En appliquant la formule, on obtient : }""") # Construction de la formule selon la présence ou non de bornes if a is None and b is None: text += _pxsl_explain(u, du, v, dv, type_int, nb_IBP, var = var)[0] text2 = _pxsl_explain(u, du, v, dv, type_int, nb_IBP, var = var)[1] else: text += _pxsl_explain(u, du, v, dv, type_int, nb_IBP, a, b, var = var)[0] text2 = _pxsl_explain(u, du, v, dv, type_int, nb_IBP, a, b, var = var)[1] # === Conclusion si une seule intégration par parties === if nb_IBP == 1 and a is None and b is None: if type_int == "udv": text += _pxsl_conclude(u*v, v*du, u*dv, var = var) if type_int == "vdu": text += _pxsl_conclude(u*v, u*dv, v*du, var = var) elif nb_IBP == 1: if type_int == "udv": text += _pxsl_conclude_int(u*v, v*du, u*dv, a, b, var = var) if type_int == "vdu": text += _pxsl_conclude_int(u*v, u*dv, v*du, a, b, var = var) # === Cas où une deuxième intégration par parties est demandée (primitive) === if nb_IBP == 2 and a is None and b is None: text += myst(r""" \end{equation*} """) if type_int == "udv": text += _pxs_explain_IBP(var, du.as_independent(var)[1], v.as_independent(var)[1], "udv") text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int \py{latex(u*dv, **config_standard)} d\py{var} \py{text2}\py{latex(integrate(du.as_independent(var)[1]*v.as_independent(var)[1],var), **config_standard)}=\py{latex(integrate(u*dv,var), **config_standard)} \end{equation*} """, globals(), locals()) if type_int == "vdu": text += _pxs_explain_IBP(var, dv.as_independent(var)[1], u.as_independent(var)[1], "vdu") # === Cas où une deuxième intégration par parties est demandée (avec bornes) === elif nb_IBP == 2: text += myst(r""" \end{equation*} """) if type_int == "udv": text += _pxs_explain_IBP(var, du.as_independent(var)[1], v.as_independent(var)[1], "udv", a = a, b = b) # Gestion du signe et du coefficient pour la 2e IBP if (v*du).as_independent(var)[0] < 0: coeff = latex((v*du).as_independent(var)[0], **config_standard) if (v*du).as_independent(var)[0] != -1 else myst(r""" """) dot = myst("""\cdot """) if (v*du).as_independent(var)[0] != -1 else myst(r""" """) if a == None and b == None: text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int \py{latex(u*dv, **config_standard)} d\py{var} =latex(u*v, **config_standard) + \py{coeff}\py{dot}\py{pxsl_par(integrate((v*du).as_independent(var)[1],var), **config_standard)}=\py{latex(integrate(u*dv,var), **config_standard)} \end{equation*} """, globals(), locals()) else: text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{latex(u*dv, **config_standard)} d\py{var} =\py{latex((u*v).subs(var,b)-(u*v).subs(var,a), **config_standard)} + \py{coeff}\py{dot}\py{pxsl_par(integrate((v*du).as_independent(var)[1],(var,a,b)), **config_standard)}=\py{latex(integrate(u*dv,(var,a,b)), **config_standard)} \end{equation*} """, globals(), locals()) else: coeff = latex((v*du).as_independent(var)[0], **config_standard) if (v*du).as_independent(var)[0] != 1 else myst(r""" """) dot = myst("""\cdot """) if (v*du).as_independent(var)[0] != 1 else myst(r""" """) if a == None and b == None: text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int \py{latex(u*dv, **config_standard)} d\py{var} =latex(u*v, **config_standard) - \py{coeff}\py{dot}\left(\py{pxsl_par(integrate((v*du).as_independent(var)[1],var), **config_standard)}=\py{latex(integrate(u*dv,var), **config_standard)}\right) \end{equation*} """, globals(), locals()) else: text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{latex(u*dv, **config_standard)} d\py{var} =\py{latex, **config_standard)} - \py{coeff}\py{dot}\left(\py{pxsl_par(integrate((v*du).as_independent(var)[1],(var,a,b)), **config_standard)}\right)=\py{latex(integrate(u*dv,(var,a,b)), **config_standard)} \end{equation*} """, globals(), locals()) if type_int == "vdu": text += _pxs_explain_IBP(var, dv.as_independent(var)[1], u.as_independent(var)[1], "vdu", a = a, b = b) if (u*dv).as_independent(var)[0] < 0: coeff = latex((u*dv).as_independent(var)[0], **config_standard) if (u*dv).as_independent(var)[0] != -1 else myst(r""" """) dot = myst("""\cdot """) if (v*du).as_independent(var)[0] != -1 else myst(r""" """) text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int \py{latex(v*du, **config_standard)} d\py{var} =\py{latex((u*v).subs(var,b)-(u*v).subs(var,a), **config_standard)} + \py{coeff}\py{dot}\py{pxsl_par(integrate((u*dv).as_independent(var)[1],(var,a,b)), **config_standard)}=\py{latex(integrate(v*du,(var,a,b)), **config_standard)} \end{equation*} """, globals(), locals()) else: coeff = latex((u*dv).as_independent(var)[0], **config_standard) if (u*dv).as_independent(var)[0] != 1 else myst(r""" """) dot = myst("""\cdot """) if (v*du).as_independent(var)[0] != 1 else myst(r""" """) text += myst(r""" \en{Thus}\fr{On a donc :} \begin{equation*} \int \py{latex(v*du, **config_standard)} d\py{var} = \py{latex((u*v).subs(var,b)-(u*v).subs(var,a), **config_standard)} - \py{coeff}\py{dot}\py{pxsl_par(integrate((u*dv).as_independent(var)[1],(var,a,b)), **config_standard)}=\py{latex(integrate(v*du,(var,a,b)), **config_standard)} \end{equation*} """, globals(), locals()) # Retourne le texte LaTeX complet expliquant les étapes de l’IBP return text
[docs] def pxs_explain_IBP(var = Symbol('x'), f1 = None, f2 = None, type_int = "udv", a = None, b = None, nb_IBP = 1, link = "https://app.pyxiscience.com/teacher/modules/7e0b271d-92f9-11f0-a777-0e37881c19a9/chapter/258e5825-9de5-11f0-a5a8-0e37881c19a9#quotient-fini#IBP2"): """ Creates a complete bilingual LaTeX explanation for computing an integral using the Integration by Parts (IBP) method. This is the main public-facing function that introduces the IBP concept, calls the internal recursive explanation generator `_pxs_explain_IBP`, and concludes by showing the final boxed result of the integral (definite or indefinite). Parameters ---------- var : sympy Symbol The integration variable. f1, f2 : sympy expressions The two parts of the integrand (used as u and dv or du and v). type_int : str, optional Type of integration by parts ("udv" or "vdu"). Default is "udv". a, b : numeric or symbolic, optional Lower and upper bounds of the integral. If None, it’s treated as an indefinite integral. nb_IBP : int, optional Number of integrations by parts to perform (1 or 2). Default is 1. Returns ------- str A bilingual LaTeX-formatted text containing the full reasoning, step-by-step explanation, and final boxed conclusion of the IBP process. """ config_standard = pxs_config() # Introduction bilingue avec lien interactif vers le chapitre concerné text = myst(r""" ```{fr} On calcule cette intégrale en réalisant une [{color:blue}`intégration par parties`]({{link}}) : ``` ```{en} Using [{color:blue}`integration by parts`]({{link}}) ``` """, globals(), locals()) # Détermination des paires u, du, v, dv à partir des deux fonctions données u, du, v, dv = _pxs_resolve_pairs(var, f1, f2, type_int) # Appel de la fonction principale interne qui rédige les étapes détaillées text += _pxs_explain_IBP(var, f1, f2, type_int, nb_IBP, a, b) # === Cas (u, dv) sans bornes === if type_int == "udv" and a is None and b is None: text += myst(r""" \en{Thus,}\fr{On a donc montré :} \begin{equation*} \fbox{$\displaystyle{\int \py{latex(u*dv, **config_standard)} \;d\py{var} = \py{latex(integrate(u*dv, var), **config_standard)}} + C$, \en{with}\fr{où} $C$ \en{a real constant}\fr{est une constante réelle}.} \end{equation*}""", globals(), locals()) # === Cas (u, dv) avec bornes === elif type_int == "udv": text += myst(r""" \en{Thus,}\fr{On a donc montré :} \begin{equation*} \fbox{$\displaystyle{\int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{latex(u*dv, **config_standard)} \;d\py{var} = \py{latex(integrate(u*dv, (var, a, b)), **config_standard)}}$} \end{equation*}""", globals(), locals()) # === Cas (du, v) sans bornes === if type_int == "vdu" and a is None and b is None: text += myst(r""" \en{Thus,}\fr{On a donc montré :} \begin{equation*} \fbox{$\displaystyle{\int \py{latex(v*du, **config_standard)} \;d\py{var} = \py{latex(integrate(v*du, var), **config_standard)}} + C$, \en{with}\fr{où} $C$ \en{a real constant}\fr{est une constante réelle}.} \end{equation*}""", globals(), locals()) # === Cas (du, v) avec bornes === elif type_int == "vdu": text += myst(r""" \en{Thus,}\fr{On a donc montré :} \begin{equation*} \fbox{$\displaystyle{\int_{\py{latex(a, **config_standard)}}^{\py{latex(b, **config_standard)}} \py{latex(v*du, **config_standard)}\;d\py{var} = \py{latex(integrate(v*du, (var, a, b)), **config_standard)}}$} \end{equation*}""", globals(), locals()) # Retourne le texte complet, incluant l’introduction, le déroulé et la conclusion return text