ACTIVITE 1 – Résolution d’une équation par dichotomie

Chargement de Python... Veuillez patienter.

I - Principe de la méthode dichotomique

On souhaite déterminer une valeur numérique de \(\sqrt{2}\) avec une précision de 5 chiffres après la virgule, en utilisant l'algorithme de dichotomie

Ecrire une équation polynomiale sous la forme \(f(x)=0\) dont \(\sqrt{2}\) est solution.

C'est cette équation que nous allons chercher à résoudre par dichotomie.

Pour que cette méthode fonctionne, il faut déterminer un intervalle dans lequel cette fonction s'annule une fois et une seule, qui sera notre intervalle de départ. Pour cela, le plus simple est de tracer la courbe représentative de la fonction sur un intervalle "au feeling" (vous avez une idée de la valeur approximative de \(\sqrt{2}\), j'espère...).

Nous avons maintenant une idée de l'intervalle sur lequel chercher la solution.

Quelle propriété doit vérifier la fonction \(f\) sur cet intervalle, pour que la dichotomie fonctionne ? Est-ce bien le cas ici ?

Ecrire l'algorithme de dichotomie permettant d'obtenir la valeur de \(\sqrt{2}\) à \(10^{-5}\) près.

    Passons à un exemple physique concret. Dans ce circuit :
  • \( E=5 \text{ V} \)
  • \( R = 1,0~\text{k}\Omega \)
  • la relation courant-tension de la diode est \( i = I_s\times \left( \mathrm{e}^{u_D/V_0} -1 \right) \)
    avec \(I_s=1,0\cdot 10^{-12}\text{ A}\) et \(V_0=26\cdot 10^{-12}\text{ mV}\)
On souhaite déterminer l'intensité \(i\) du courant circulant dans le circuit, mais il n'est pas possible d'exprimer \(i\) algébriquement en fonction des paramètres du problème.

Appliquer la loi des mailles, et en déduire une équation \(f(u_D)=0\) dont \(u_D\) est solution, ne dépendant que des paramètres \(E\), \(R\), \(I_s\) et \(V_0\).

Pour résoudre cette équation par dichotomie, il faudrait déjà avoir une idée approximative de l'intervalle \(\left[u_{D1},u_{D2}\right]\) dans lequel cette fonction s'annule. Pour cela, tracer le graphe de cette fonction et en déduire un intervalle \(\left[u_{D1},u_{D2}\right]\) de départ pour appliquer la dichotomie ensuite.

En déduire un intervalle de départ convenable pour la dichotomie.
Ecrire l'algorithme de dichotomie et en déduire la tension aux bornes de la diode et l'intensité du courant circulant dans le circuit.

II - Utilisation de la fonction bisect()

Il existe une fonction bisect() toute prête, disponible dans la bibliothèque scipy.optimize, qui applique automatiquement la méthode dichotomique pour trouver le zéro d'une fonction.
Au lieu de programmer la boucle nous-même, on peut utiliser cette fonction qui fait tout le travail !

Cherchons la documentation de cette fonction sur le site officiel de SciPy :
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.bisect.html

    Points importants à avoir en tête :
  1. Toujours définir la fonction dont on cherche le zéro avant d'appeler bisect()
  2. Choisir un bon intervalle de départ : le graphique aide ! → Il faut que f s’annule 1 fois et 1 seule sur cet intervalle.
  3. bisect() fait ensuite tout le travail : pas besoin de boucle !

Utiliser cette fonction bisect() pour déterminer une valeur numérique de \(\sqrt{2}\), puis pour déterminer le point de fonctionnement du circuit précédent.

terminal = false packages = ["numpy", "matplotlib", "scipy"] [[fetch]] files = [] import sys import io import traceback from js import document, console, window from pyodide.ffi import create_proxy import base64 # Configuration matplotlib pour PyScript import matplotlib matplotlib.use('Agg') # Backend non-interactif pour PyScript import matplotlib.pyplot as plt # Contexte global partagé entre toutes les cellules global_context = {'plt': plt, 'matplotlib': matplotlib} def capture_output(func, *args, **kwargs): """Capture la sortie d'une fonction""" old_stdout = sys.stdout old_stderr = sys.stderr stdout_capture = io.StringIO() stderr_capture = io.StringIO() sys.stdout = stdout_capture sys.stderr = stderr_capture try: result = func(*args, **kwargs) stdout_output = stdout_capture.getvalue() stderr_output = stderr_capture.getvalue() return result, stdout_output, stderr_output finally: sys.stdout = old_stdout sys.stderr = old_stderr def handle_matplotlib_figures(output_element): """Gère l'affichage des figures matplotlib""" current_figures = plt.get_fignums() if current_figures: # Créer ou récupérer le conteneur des figures figures_container = output_element.querySelector('.figures-container') if not figures_container: figures_container = document.createElement('div') figures_container.className = 'figures-container' figures_container.style.cssText = ''' display: flex; flex-wrap: wrap; gap: 15px; margin: 10px 0; justify-content: center; ''' output_element.appendChild(figures_container) for fig_num in current_figures: fig = plt.figure(fig_num) # Convertir la figure en image base64 buf = io.BytesIO() fig.savefig(buf, format='png', bbox_inches='tight', dpi=150) buf.seek(0) img_data = base64.b64encode(buf.read()).decode() buf.close() # Créer un conteneur pour la figure avec bouton de suppression figure_wrapper = document.createElement('div') figure_wrapper.className = 'figure-wrapper' figure_wrapper.style.cssText = ''' position: relative; display: inline-block; border: 1px solid #ddd; border-radius: 8px; padding: 10px; background: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); margin: 5px; ''' # Créer l'élément img pour afficher la figure img_element = document.createElement('img') img_element.src = f'data:image/png;base64,{img_data}' img_element.className = 'matplotlib-figure' img_element.style.cssText = ''' max-width: 300px; max-height: 250px; height: auto; display: block; border-radius: 4px; ''' # Créer le bouton de suppression delete_btn = document.createElement('button') delete_btn.innerHTML = '×' delete_btn.className = 'figure-delete-btn' delete_btn.style.cssText = ''' position: absolute; top: 5px; right: 5px; width: 25px; height: 25px; border: none; border-radius: 50%; background: rgba(220, 53, 69, 0.8); color: white; font-size: 16px; font-weight: bold; cursor: pointer; display: flex; align-items: center; justify-content: center; line-height: 1; z-index: 10; ''' delete_btn.title = 'Supprimer cette figure' # Ajouter l'événement de suppression def create_delete_handler(wrapper): def delete_figure(event): wrapper.remove() return delete_figure delete_btn.onclick = create_delete_handler(figure_wrapper) # Assembler la figure figure_wrapper.appendChild(img_element) figure_wrapper.appendChild(delete_btn) figures_container.appendChild(figure_wrapper) # Fermer toutes les figures pour éviter les accumulations plt.close('all') return True return False def execute_python_code(code, cell_id): """Exécute le code Python et affiche le résultat""" output_element = document.querySelector(f'#output-{cell_id}') loading_element = document.querySelector(f'#loading-{cell_id}') loading_element.style.display = 'block' figures_container = output_element.querySelector('.figures-container') if figures_container: text_outputs = output_element.querySelectorAll('.text-output') for text_output in text_outputs: text_output.remove() output_element.className = 'output' nodes_to_remove = [] for node in output_element.childNodes: if node.nodeType == 3: nodes_to_remove.append(node) for node in nodes_to_remove: node.remove() else: output_element.innerHTML = '' output_element.className = 'output' try: # PROTECTION : Injecter un compteur d'itérations protected_code = """ import sys class _IterationLimit: def __init__(self, max_iterations=1000000): self.max_iterations = max_iterations self.count = 0 def check(self): self.count += 1 if self.count > self.max_iterations: raise RuntimeError(f"⚠️ Exécution interrompue : plus de {self.max_iterations} itérations détectées.\\nVérifiez qu'il n'y a pas de boucle infinie dans votre code.") _iter_limit = _IterationLimit() _original_trace = sys.gettrace() def _trace_calls(frame, event, arg): if event == 'line': _iter_limit.check() return _trace_calls sys.settrace(_trace_calls) try: """ + "\n".join(" " + line for line in code.split("\n")) + """ finally: sys.settrace(_original_trace) """ def run_code(): exec(protected_code, global_context) lines = code.strip().split('\n') if lines: last_line = lines[-1].strip() if (last_line and not last_line.startswith((' ', '\t')) and not last_line.endswith(':') and not last_line.startswith(('print(', 'import ', 'from ', 'def ', 'class ', 'if ', 'for ', 'while ', 'try:', 'except', 'with ', 'assert ', 'del ', 'pass', 'break', 'continue', 'return', 'yield', 'raise', 'global ', 'nonlocal ', 'plt.', 'fig')) and '=' not in last_line.split('#')[0]): try: return eval(last_line, global_context) except: pass return None result, stdout_output, stderr_output = capture_output(run_code) has_figures = handle_matplotlib_figures(output_element) output = "" if stdout_output: output += stdout_output if stderr_output: output += stderr_output if result is not None: output += str(result) if output: if has_figures: text_div = document.createElement('div') text_div.className = 'text-output' text_div.textContent = output output_element.appendChild(text_div) else: output_element.textContent = output elif not has_figures: output_element.textContent = "✓ Code exécuté avec succès" output_element.className = 'output success' except Exception as e: error_output = f"❌ Erreur:\n{str(e)}\n\n{traceback.format_exc()}" output_element.textContent = error_output output_element.className = 'output error' finally: loading_element.style.display = 'none' # Exposer les fonctions à JavaScript window.execute_python_code = create_proxy(execute_python_code) # Signaler que PyScript est prêt console.log("PyScript ready!") try: # Activer l'interface immédiatement status_element = document.querySelector('#pyscript-status') if status_element: status_element.innerHTML = 'Python est prêt ! Vous pouvez maintenant exécuter votre code.' status_element.className = 'pyscript-status pyscript-ready' # Activer tous les boutons d'exécution run_buttons = document.querySelectorAll('.btn-run') for button in run_buttons: button.disabled = False # Notifier JavaScript window.pyScriptIsReady = True except Exception as e: console.log(f"Error during PyScript initialization: {e}")