from functions import (
RealFunction,
DifferentiableFunction,
PolynomialFunction,
SineFunction,
ExponentialFunction,
)
import math
# Przykłady użycia
# Funkcja wielomianowa: 3x^2 - 2x + 1
p = 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^x
e = 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 + 1
df = DifferentiableFunction(f, name="Funkcja kwadratowa")
print(df(3)) # Wypisze 16
pochodna_df = df.derivative()
print(pochodna_df(3)) # Wypisze przybliżoną wartość pochodnej f(x) w x=3, czyli 8
Zadanie
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 argumentx
(liczbę rzeczywistą) i zwraca wynik wywołania przechowywanej funkcjifunc
z tym argumentem.Zaimplementuj metodę
__str__(self)
, która zwraca opis funkcji (np. jej nazwę).
Klasa pochodna
DifferentiableFunction
:Zdefiniuj klasę
DifferentiableFunction
, która dziedziczy poRealFunction
.Jej konstruktor (
__init__
) powinien zachowywać się tak samo jak konstruktor klasy bazowej, przekazując argumenty dosuper().__init__(func, name)
.Zaimplementuj metodę
derivative(self, h=1e-7)
, która przybliża wartość pochodnej funkcji w punkciex
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 punkciex
.
Klasa pochodna
PolynomialFunction
:Zdefiniuj klasę
PolynomialFunction
, która dziedziczy poDifferentiableFunction
.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 danegox
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 punkciex
i zwraca nowy obiekt klasyPolynomialFunction
reprezentujący tę pochodną.
Klasa pochodna
SineFunction
:Zdefiniuj klasę
SineFunction
, która dziedziczy poDifferentiableFunction
.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 danegox
przy użyciu funkcji z modułumath
.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 punkciex
i zwraca nowy obiekt klasySineFunction
reprezentujący tę pochodną.
Klasa pochodna
ExponentialFunction
:Zdefiniuj klasę
ExponentialFunction
, która dziedziczy poDifferentiableFunction
.Jej konstruktor (
__init__
) powinien przyjmować następujące argumenty:base
(opcjonalny): Podstawa funkcji eksponencjalnej (domyślniemath.e
).name
(opcjonalny): Nazwa funkcji eksponencjalnej.
Zaimplementuj metodę
__call__(self, x)
, która oblicza wartość funkcji eksponencjalnej dla danegox
przy użyciu funkcji z modułumath
.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 punkciex
i zwraca nowy obiekt klasyExponentialFunction
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.
Rozwiązanie
#!/usr/bin/env python3
"""Implementacja funkcji rzeczywistych w Pythonie."""
import math
from collections.abc import Callable
class RealFunction:
"""Klasa bazowa reprezentująca funkcję rzeczywistą."""
def __init__(self, func: Callable[[float], float], name: str | None = None):
self.func = func
self.name = name
def __call__(self, x: float) -> float:
return self.func(x)
def __str__(self) -> str:
return self.name if self.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}" if self.name else None,
)
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 = coefficients
def _evaluate_polynomial(self, x: float, coeffs: list[float]) -> float:
"""Oblicza wartość wielomianu dla danego x używając schematu Hornera."""
result = 0
for coeff in coeffs:
result = result * x + coeff
return result
def __str__(self) -> str:
terms = []
for i, coeff in enumerate(self.coefficients):
power = len(self.coefficients) - 1 - i
if coeff:
term = (
f"{'+' if coeff > 0 and i > 0 else ''}"
f" {'-' if coeff < 0 else ''}"
)
if abs(coeff) != 1 or power == 0:
term += str(abs(coeff))
if power > 0:
term += "x" + (f"^{power}" if power > 1 else "")
terms.append(term)
return "".join(terms) or "0"
def derivative(self) -> "PolynomialFunction":
"""Oblicza pochodną wielomianu i zwraca nowy obiekt PolynomialFunction."""
if not self.coefficients:
return PolynomialFunction([])
derivative_coeffs = []
for i, coeff in enumerate(self.coefficients[:-1]):
derivative_coeffs.append(coeff * (len(self.coefficients) - 1 - i))
return PolynomialFunction(
derivative_coeffs,
name=f"Pochodna {self.name}" if self.name else None,
)
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 = amplitude
self.frequency = frequency
self.phase = phase
def __str__(self) -> str:
amplitude = f"{self.amplitude} * " if self.amplitude != 1 else ""
s = f"{amplitude}sin({self.frequency}*x"
if self.phase != 0:
s += f"+{self.phase}"
s += ")"
return s
def 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}" if self.name else None,
)
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 = base
self.scalar = scalar
def __str__(self) -> str:
return (
f"{self.scalar} * {self.base} ^ x"
if self.scalar != 1.0
else f"{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}" if self.name else None,
)