Celem tego ćwiczenia jest praktyczne zastosowanie dziedziczenia w Pythonie do stworzenia hierarchii klas reprezentujących różne typy funkcji matematycznych. Zaimplementujesz klasy dla funkcji rzeczywistych, funkcji różniczkowalnych oraz konkretnych przypadków - funkcji wielomianowych, sinusoidalnych i eksponencjalnych.
Klasa bazowa RealFunction:
Zdefiniuj klasę RealFunction.
Jej konstruktor (__init__) powinien przyjmować dwa argumenty:
func: Obiekt wywoływalny (np. funkcja lambda lub zwykła funkcja Pythona), który reprezentuje daną funkcję matematyczną.
name (opcjonalny): Ciąg znaków opisujący nazwę funkcji.
Zaimplementuj metodę __call__(self, x), która przyjmuje argument x (liczbę rzeczywistą) i zwraca wynik wywołania przechowywanej funkcji func z tym argumentem.
Zaimplementuj metodę __str__(self), która zwraca opis funkcji (np. jej nazwę).
Klasa pochodna DifferentiableFunction:
Zdefiniuj klasę DifferentiableFunction, która dziedziczy po RealFunction.
Jej konstruktor (__init__) powinien zachowywać się tak samo jak konstruktor klasy bazowej, przekazując argumenty do super().__init__(func, name).
Zaimplementuj metodę derivative(self, h=1e-7), która przybliża wartość pochodnej funkcji w punkcie x przy użyciu symetrycznego ilorazu różnicowego:
\[\frac{f(x + h) - f(x - h)}{2h}\]
gdzie \(f\) to funkcja reprezentowana przez instancję klasy, a \(h\) jest małą wartością kroku (domyślnie \(10^{-7}\)). Metoda ta powinna zwracać obiekt RealFunction odpowiadający przybliżonej wartości pochodnej w punkcie x.
Klasa pochodna PolynomialFunction:
Zdefiniuj klasę PolynomialFunction, która dziedziczy po DifferentiableFunction.
Jej konstruktor (__init__) powinien przyjmować dwa argumenty:
coefficients: Lista liczb reprezentujących współczynniki wielomianu. Pierwszy element listy odpowiada współczynnikowi przy najwyższej potędze, a ostatni - wyrazowi wolnemu. Na przykład, dla wielomianu \(3x^2 - 2x + 1\), lista współczynników to [3, -2, 1].
name (opcjonalny): Nazwa wielomianu.
Zaimplementuj metodę __call__(self, x), która oblicza wartość wielomianu dla danego x przy użyciu schematu Hornera. Zaimplementuj w tym celu pomocniczą (np. prywatną) metodę __evaluate_polynomial(self, x, coeffs).
Zaimplementuj metodę __str__(self), która zwraca opis wielomianu na podstawie jego współczynników. Powinna ona tworzyć łańcuch znaków reprezentujący wielomian w standardowej formie (np. 3x^2 - 2x + 1).
Zaimplementuj metodę derivative(self), która oblicza wartość pochodnej wielomianu w punkcie x i zwraca nowy obiekt klasy PolynomialFunction reprezentujący tę pochodną.
Klasa pochodna SineFunction:
Zdefiniuj klasę SineFunction, która dziedziczy po DifferentiableFunction.
Jej konstruktor (__init__) powinien przyjmować następujące argumenty:
amplitude (opcjonalny): Amplituda funkcji sinus (domyślnie 1.0).
frequency (opcjonalny): Częstotliwość funkcji sinus (domyślnie 1.0).
phase (opcjonalny): Faza funkcji sinus (domyślnie 0.0).
name (opcjonalny): Nazwa funkcji sinus.
Zaimplementuj metodę __call__(self, x), która oblicza wartość funkcji sinus dla danego x przy użyciu funkcji z modułu math.
Zaimplementuj metodę __str__(self), która zwraca opis funkcji sinus na podstawie jej parametrów (amplituda, częstotliwość, faza).
Zaimplementuj metodę derivative(self), która oblicza wartość pochodnej funkcji sinus w punkcie x i zwraca nowy obiekt klasy SineFunction reprezentujący tę pochodną.
Klasa pochodna ExponentialFunction:
Zdefiniuj klasę ExponentialFunction, która dziedziczy po DifferentiableFunction.
Jej konstruktor (__init__) powinien przyjmować następujące argumenty:
base (opcjonalny): Podstawa funkcji eksponencjalnej (domyślnie math.e).
name (opcjonalny): Nazwa funkcji eksponencjalnej.
Zaimplementuj metodę __call__(self, x), która oblicza wartość funkcji eksponencjalnej dla danego x przy użyciu funkcji z modułu math.
Zaimplementuj metodę __str__(self), która zwraca opis funkcji eksponencjalnej na podstawie jej podstawy.
Zaimplementuj metodę derivative(self), która oblicza wartość pochodnej funkcji eksponencjalnej w punkcie x i zwraca nowy obiekt klasy ExponentialFunction reprezentujący tę pochodną.
Przykładowe użycie klas:
Poniżej znajdują się przykłady użycia zdefiniowanych klas. Możesz je umieścić w jednej komórce kodu w Jupyter Notebook.
Show the code
from functions import ( RealFunction, DifferentiableFunction, PolynomialFunction, SineFunction, ExponentialFunction,)import math# Przykłady użycia# Funkcja wielomianowa: 3x^2 - 2x + 1p = PolynomialFunction([3, -2, 1], name="Wielomian Kwadratowy")print(p)print(p(2))pochodna_p = p.derivative()print(pochodna_p)print(pochodna_p(2))# Funkcja sinus: 2*sin(0.5*x + 0.3)s = SineFunction(amplitude=2, frequency=0.5, phase=0.3, name="Funkcja Sinus")print(s)print(s(math.pi))pochodna_s = s.derivative()print(pochodna_s)print(pochodna_s(math.pi))# Funkcja eksponencjalna: 2^xe = ExponentialFunction(base=2, name="Funkcja Eksponencjalna")print(e)print(e(3))pochodna_e = e.derivative()print(pochodna_e(3))# Przykład użycia DifferentiableFunction z funkcjądef f(x):return x**2+2* x +1df = DifferentiableFunction(f, name="Funkcja kwadratowa")print(df(3)) # Wypisze 16pochodna_df = df.derivative()print(pochodna_df(3)) # Wypisze przybliżoną wartość pochodnej f(x) w x=3, czyli 8
Rozwiązanie
Show the code
#!/usr/bin/env python3"""Implementacja funkcji rzeczywistych w Pythonie."""import mathfrom collections.abc import Callableclass RealFunction:"""Klasa bazowa reprezentująca funkcję rzeczywistą."""def__init__(self, func: Callable[[float], float], name: str|None=None):self.func = funcself.name = namedef__call__(self, x: float) ->float:returnself.func(x)def__str__(self) ->str:returnself.name ifself.name else"Anonimowa funkcja"class DifferentiableFunction(RealFunction):"""Klasa reprezentująca funkcję różniczkowalną."""def__init__(self, func: Callable[[float], float], name: str|None=None):super().__init__(func, name)def derivative(self, h: float=1e-7) ->"RealFunction":"""Oblicza pochodną funkcji w punkcie x przy użyciu różnic centralnych."""return RealFunction(lambda x: (self.func(x + h) -self.func(x - h)) / (2* h), name=f"Pochodna {self.name}"ifself.name elseNone, )class PolynomialFunction(DifferentiableFunction):"""Klasa reprezentująca funkcję wielomianową."""def__init__(self, coefficients: list[float], name: str|None=None):super().__init__(lambda x: self._evaluate_polynomial(x, coefficients), name)self.coefficients = coefficientsdef _evaluate_polynomial(self, x: float, coeffs: list[float]) ->float:"""Oblicza wartość wielomianu dla danego x używając schematu Hornera.""" result =0for coeff in coeffs: result = result * x + coeffreturn resultdef__str__(self) ->str: terms = []for i, coeff inenumerate(self.coefficients): power =len(self.coefficients) -1- iif coeff: term = (f"{'+'if coeff >0and i >0else''}"f" {'-'if coeff <0else''}" )ifabs(coeff) !=1or power ==0: term +=str(abs(coeff))if power >0: term +="x"+ (f"^{power}"if power >1else"") terms.append(term)return"".join(terms) or"0"def derivative(self) ->"PolynomialFunction":"""Oblicza pochodną wielomianu i zwraca nowy obiekt PolynomialFunction."""ifnotself.coefficients:return PolynomialFunction([]) derivative_coeffs = []for i, coeff inenumerate(self.coefficients[:-1]): derivative_coeffs.append(coeff * (len(self.coefficients) -1- i))return PolynomialFunction( derivative_coeffs, name=f"Pochodna {self.name}"ifself.name elseNone, )class SineFunction(DifferentiableFunction):"""Klasa reprezentująca funkcję sinus."""def__init__(self, amplitude: float=1.0, frequency: float=1.0, phase: float=0.0, name: str|None=None, ):super().__init__(lambda x: amplitude * math.sin(frequency * x + phase), name)self.amplitude = amplitudeself.frequency = frequencyself.phase = phasedef__str__(self) ->str: amplitude =f"{self.amplitude} * "ifself.amplitude !=1else"" s =f"{amplitude}sin({self.frequency}*x"ifself.phase !=0: s +=f"+{self.phase}" s +=")"return sdef derivative(self) ->"SineFunction":"""Oblicza pochodną funkcji sinus i zwraca nowy obiekt SineFunction."""# Pochodna amplitude * sin(frequency * x + phase)# to amplitude * frequency * cos(frequency * x + phase)return SineFunction( amplitude=self.amplitude *self.frequency, frequency=self.frequency, phase=self.phase + math.pi /2, name=f"Pochodna {self.name}"ifself.name elseNone, )class ExponentialFunction(DifferentiableFunction):"""Klasa reprezentująca funkcję eksponencjalną."""def__init__(self, base: float= math.e, scalar: float=1.0, name: str|None=None, ):super().__init__(lambda x: scalar * base**x, name)self.base = baseself.scalar = scalardef__str__(self) ->str:return (f"{self.scalar} * {self.base} ^ x"ifself.scalar !=1.0elsef"{self.base} ^ x" )def derivative(self) ->"ExponentialFunction":"""Oblicza pochodną funkcji eksponencjalnej."""return ExponentialFunction( base=self.base, scalar=self.scalar * math.log(self.base), name=f"Pochodna {self.name}"ifself.name elseNone, )