import sympy as sp
x = sp.Symbol("x")
p = x**2 - 1
(p, p.free_symbols, p.subs(x, 3))(x**2 - 1, {x}, 8)
Setelah menyelesaikan unit ini, pembaca dapat:
Fraction dan SymPy untuk mempertahankan hasil eksak;ZZ, QQ, RR, SR, parent dan coercion, gelang polinom, faktorisasi, penyelesaian eksak, serta konversi pendekatan yang dinyatakan.Prasyarat lokal: Unit 1 dan Unit 2, operasi polinomial, persamaan kuadrat, dan pengertian domain fungsi. Jalur pertama memakai pustaka standar Python dan SymPy; lab SageMath 9.5 lokal merupakan bagian wajib unit. Tidak diperlukan kalkulus atau aljabar linear.
Ekspresi
memuat simbol bebas . Ia belum mempunyai satu nilai numerik. Substitusi menghasilkan nilai eksak , tetapi tidak mengubah ekspresi asal menjadi bilangan.
import sympy as sp
x = sp.Symbol("x")
p = x**2 - 1
(p, p.free_symbols, p.subs(x, 3))(x**2 - 1, {x}, 8)
Perbedaan ini penting bagi notebook yang dijalankan tidak berurutan. Nama x dalam kode dapat menunjuk objek Python, sedangkan simbol SymPy bernama x merupakan bagian dari pohon ekspresi. Tampilkan dan simpan pohon yang sebenarnya dipakai, bukan hanya hasil terakhir di layar.
Untuk bilangan rasional kecil, pustaka standar sudah cukup:
from fractions import Fraction
Fraction(1, 10) + Fraction(2, 10)Fraction(3, 10)
Fraction(3, 10) dan sp.Rational(3, 10) sama-sama mempertahankan nilai rasional eksak. Pilih batas antarpustaka secara eksplisit; jangan mengubahnya menjadi float hanya untuk memperoleh keluaran yang tampak lebih pendek.
Tanpa keterangan tanda, rumus tidak benar untuk setiap bilangan real. Jika real, hasil yang benar ialah . Jika , barulah hasilnya .
x_real = sp.Symbol("x", real=True)
x_positive = sp.Symbol("x", positive=True)
(
sp.simplify(sp.sqrt(x_real**2)),
sp.simplify(sp.sqrt(x_positive**2)),
)(Abs(x), x)
Nama cetak kedua simbol sama, tetapi asumsi internalnya berbeda. Oleh sebab itu, sebuah rekaman komputasi simbolik harus menyimpan definisi simbol atau pernyataan domain yang menyertainya.
Domain juga harus dipertahankan ketika faktor dibatalkan. Untuk
SymPy memperoleh setelah pembatalan. Kedua rumus memberi nilai sama pada domain bersama, yaitu . Namun, keduanya bukan fungsi yang sama jika domain asal ikut menjadi bagian definisi: rumus asal tidak terdefinisi pada , sedangkan bernilai di sana.
Operator == pada dua ekspresi SymPy terutama membandingkan struktur kanonisnya. Ia bukan pertanyaan universal “apakah kedua rumus ini mempunyai nilai sama bagi semua masukan yang sah?”. Contohnya, ekspresi dan mempunyai struktur berbeda tetapi merupakan polinom yang sama.
left = (x + 1) ** 2
right = x**2 + 2*x + 1
structurally_equal = left == right
polynomial_identity = sp.expand(left - right) == 0
(structurally_equal, polynomial_identity)(False, True)
Prosedur pemeriksaan harus sesuai dengan kelas ekspresi. Ekspansi selisih cocok untuk identitas polinomial. simplify(left-right) == 0 berguna sebagai pemeriksaan lain, tetapi bukan pengganti pencatatan domain, cabang akar, asumsi, atau titik singular.
Komputasi simbolik mempertahankan akar dan faktor tanpa pendekatan desimal.
x = sp.Symbol("x")
polynomial = x**4 - 1
factored = sp.factor(polynomial)
(factored, sp.expand(factored) == polynomial)((x - 1)*(x + 1)*(x**2 + 1), True)
Faktorisasi yang diharapkan ialah
Pemeriksaan dengan expand menguji bahwa hasil tersebut kembali menjadi polinom masukan. Untuk persamaan , domain solusi harus dinyatakan:
x = sp.Symbol("x", real=True)
solutions = sp.solveset(sp.Eq(x**2, 2), x, domain=sp.S.Reals)
solutionsHasil real eksaknya adalah . Substitusi setiap kandidat ke harus memberikan residual eksak nol. Jika domain diubah, bentuk atau jumlah solusi dapat berubah; karena itu, jangan menyimpan daftar akar tanpa persamaan dan domainnya.
Keluaran sistem aljabar komputer mempunyai beberapa peran yang berbeda:
solve mengusulkan nilai yang kemudian dapat diperiksa;Faktorisasi dapat diperiksa langsung dengan distributivitas. Namun, keberhasilan satu perintah tidak membuktikan bahwa setiap keluaran algoritme untuk setiap masukan pasti benar. Klaim lebih luas juga bergantung pada spesifikasi algoritme dan kebenaran implementasinya. Dalam tulisan matematis, nyatakan tepatnya hubungan mana yang diperiksa komputer dan langkah umum mana yang dibuktikan secara matematis.
Tampilan dua dimensi yang nyaman dibaca dapat berubah karena lebar terminal, pengaturan printer, atau versi pustaka. Unit ini memakai sympy.srepr untuk merekam pohon ekspresi dan JSON dengan kunci terurut, inden tetap, UTF-8, serta akhir baris LF. Versi SymPy ikut disimpan karena bentuk kanonis pustaka dapat berubah antarrilis.
Jalankan skrip dari akar proyek:
python source/code/unit05_symbolic.py --output output/unit05-results.json
Medan core_sha256 mengikat rekaman inti sebelum medan hash ditambahkan. Menjalankan perintah yang sama pada lingkungan yang sama harus menghasilkan byte identik. Hash bukan bukti kebenaran matematika; ia membuktikan bahwa dua urutan byte sama.
SageMath menyatukan banyak struktur matematika dalam satu sistem yang memakai sintaks Python. Dalam unit ini, Sage bukan layanan web dan bukan potongan opsional. Lab dijalankan lokal dengan SageMath 9.5 yang dibekukan di WSL Ubuntu 22.04. SageCell atau layanan jarak jauh tidak memenuhi persyaratan karena runtime, ketersediaan jaringan, dan byte hasilnya tidak berada di bawah kendali eksperimen lokal.
Jika profil itu belum tersedia, ikuti panduan penyiapan lokal dan jalankan verifikasi lock sebelum lab. Perbedaan versi harus dicatat; jangan menyebut profil yang berbeda sebagai lingkungan rilis yang identik.
Dari akar proyek pada PowerShell, jalankan:
wsl.exe -d Ubuntu-22.04 -- /usr/bin/sage -python source/code/unit05_sage_lab.py --output output/unit05-sage-results.json
wsl.exe -d Ubuntu-22.04 -- /usr/bin/sage -python tests/test_unit05_sage.py
Perintah pertama menulis JSON deterministik ke jalur relatif yang diberikan. Perintah kedua menjalankan seluruh tes lab di runtime yang sama. Blok Sage di pembaca ini sengaja berupa pagar python biasa, bukan blok Quarto {python}. Karena itu, build Windows tidak mencoba mengimpor Sage melalui kernel Python biasa.
Sage menanyakan parent() suatu objek, bukan hanya tipe implementasi Python. Empat parent inti lab ini adalah:
| Nama | Parent matematika | Peran |
|---|---|---|
ZZ |
gelang bilangan bulat | aritmetika bulat eksak |
QQ |
lapangan bilangan rasional | pembagian rasional eksak |
RR |
lapangan real 53 bit | pendekatan titik-mengambang |
SR |
gelang simbolik | ekspresi dan persamaan simbolik |
from sage.all import QQ, RR, SR, ZZ
bilangan_bulat = ZZ(6)
rasional = QQ(1) / 3
pendekatan = RR(rasional)
simbolik = SR(rasional)
print(bilangan_bulat.parent())
print(rasional.parent())
print(pendekatan.parent())
print(simbolik.parent())Nilai cetak saja tidak cukup. 1/3 dalam QQ merupakan nilai eksak, sedangkan nilai dalam RR adalah pendekatan pada presisi parent-nya.
Coercion adalah konversi kanonis yang dipilih Sage ketika operasi mencampurkan parent. Misalnya, ZZ(6) + QQ(1)/3 hidup di QQ karena ada peta kanonis dari ZZ ke QQ. Lab memeriksa peta ZZ ke QQ, QQ ke RR, dan QQ ke SR secara eksplisit.
from sage.all import QQ, RR, SR, ZZ
assert QQ.has_coerce_map_from(ZZ)
assert RR.has_coerce_map_from(QQ)
assert SR.has_coerce_map_from(QQ)
campuran = ZZ(6) + QQ(1) / 3
assert campuran.parent() is QQCoercion yang tersedia tidak berarti semua perubahan representasi tanpa kerugian. Pemetaan QQ ke RR mengubah rasional eksak menjadi pendekatan. Karena itu, kode ilmiah harus menuliskan titik konversinya.
Parent polinom menyimpan gelang koefisien. PolynomialRing(QQ, "x") menyatakan polinom satu variabel dengan koefisien rasional. Ini lebih spesifik daripada sekadar ekspresi simbolik yang kebetulan tampak seperti polinom.
from sage.all import PolynomialRing, QQ
R = PolynomialRing(QQ, "x")
x = R.gen()
p = x**4 - 1
faktor = p.factor()
assert p.parent() is R
assert R.base_ring() is QQ
assert faktor.prod() == p
print(faktor)Faktorisasi tepatnya . Pemeriksaan prod() mengalikan faktor di dalam parent yang sama dan membandingkannya dengan polinom asal.
Untuk persamaan simbolik, domain dan parent masih harus dicatat. Lab memakai SR, meminta solusi berbentuk kamus, lalu mensubstitusikan setiap kandidat ke residual.
from sage.all import SR, solve
y = SR.var("y")
solusi = solve(y**2 == 2, y, solution_dict=True)
nilai = [baris[y] for baris in solusi]
assert all((akar**2 - 2).simplify_full() == 0 for akar in nilai)Residual nol memeriksa dua kandidat yang dikembalikan. Ia tidak sendirinya membuktikan bahwa tidak ada solusi lain pada domain berbeda.
Jangan mengubah objek eksak menjadi desimal hanya agar tampilannya pendek. Pertahankan objek asal dan tuliskan parent tujuan:
from sage.all import QQ, RR
eksak = QQ(1) / 3
hampiran = RR(eksak)
assert eksak.parent() is QQ
assert hampiran.parent() is RR
print(eksak, hampiran, RR.precision())RR(eksak) adalah keputusan representasi yang dapat ditemukan dalam sumber. Rekaman lab menyimpan nilai eksak, teks konversi, nilai pendekatan, parent, dan presisi 53 bit.
unit05-sage-results.json mencatat SageMath 9.5, keharusan eksekusi lokal, parent, peta coercion, gelang polinom, faktor, solusi, residual, konversi ke RR, dan core_sha256. Semua objek diubah menjadi bentuk JSON yang ditentukan sebelum serialisasi. Dua eksekusi dengan runtime yang sama harus menghasilkan byte sama.
Skrip menolak versi selain 9.5. Pembatasan ini bukan klaim bahwa versi lain salah; ia mengikat bukti kerja pada runtime yang benar-benar diuji. Hasil SageMath tetap bukan pengganti bukti umum. Parent dan residual menjelaskan apa yang diperiksa oleh komputasi; argumen matematika menjelaskan mengapa klaim berlaku pada domainnya.
Bentuk ekspresi di SymPy. Sebutkan simbol bebasnya, lalu evaluasi pada secara eksak.
Gunakan Symbol, Rational, atribut free_symbols, dan subs.
Kode t=sp.Symbol("t"); q=t**3-2*t menghasilkan simbol bebas {t}. Substitusi q.subs(t, sp.Rational(1,2)) memberi . Ekspresi q tetap memuat t; -7/8 adalah nilai pada satu masukan, bukan pengganti ekspresi asal.
Seorang pembaca menyederhanakan menjadi untuk semua bilangan real. Berikan contoh penyangkal dan tuliskan hasil umum yang benar.
Coba satu bilangan real negatif.
Ambil . Maka , sedangkan , sehingga penyederhanaan itu gagal. Untuk real, bentuk umum yang benar ialah . Bentuk sah jika ditambahkan asumsi , dan khusus simbol SymPy positif dapat dideklarasikan dengan positive=True.
Bandingkan dengan . Nyatakan pada himpunan mana nilainya sama dan jelaskan mengapa domain kedua fungsi tidak otomatis sama.
Faktorkan pembilang dan periksa penyebut sebelum membatalkan faktor.
Karena , kedua rumus memberi nilai sama untuk setiap . Rumus pecahan tidak terdefinisi pada , sementara bernilai . Jadi keduanya setara pada domain bersama, tetapi bukan fungsi dengan domain yang sama kecuali pembatasan dipertahankan.
Faktorkan , cari semua akar realnya secara eksak, lalu tuliskan dua pemeriksaan yang dapat dilakukan tanpa mempercayai tampilan keluaran.
Keluarkan faktor v, kemudian faktorkan selisih kuadrat.
, sehingga akar realnya ialah . Pemeriksaan pertama: ekspansi v*(v-1)*(v+1) harus kembali ke v**3-v. Pemeriksaan kedua: substitusi setiap akar ke polinom harus memberi residual eksak nol. Kedua pemeriksaan ini mengikat klaim lokal yang jelas.
Mengapa menyimpan hanya tangkapan layar keluaran pretty print tidak cukup untuk eksperimen simbolik yang dapat direproduksi? Sebutkan sedikitnya empat unsur rekaman yang lebih baik.
Pikirkan pohon ekspresi, asumsi, domain, versi, dan byte keluaran.
Tangkapan layar dapat kehilangan struktur, mudah berubah karena tata letak, dan tidak dapat dievaluasi ulang. Rekaman yang lebih baik memuat (1) pohon ekspresi kanonis, (2) asumsi simbol, (3) domain masalah, (4) versi SymPy atau SageMath, (5) masukan dan metode, serta (6) JSON atau format teks dengan aturan urutan dan akhir baris yang tetap. Hash kemudian dapat membandingkan byte, sedangkan residual atau ekspansi memeriksa klaim matematis tertentu.
Di SageMath 9.5 lokal, bentuk ZZ(5), QQ(2)/3, dan jumlah keduanya. Catat parent setiap objek dan jelaskan coercion yang terjadi. Lalu buat gelang QQ[z], faktorkan , dan periksa bahwa hasil kali faktor kembali ke polinom asal.
Gunakan parent(), QQ.has_coerce_map_from(ZZ), PolynomialRing(QQ, "z"), serta metode factor() dan prod().
Jalankan blok ini hanya melalui /usr/bin/sage -python, bukan kernel Quarto Windows.
from sage.all import PolynomialRing, QQ, ZZ
a = ZZ(5)
b = QQ(2) / 3
c = a + b
Rz = PolynomialRing(QQ, "z")
z = Rz.gen()
pz = z**4 - 1
fz = pz.factor()
assert a.parent() is ZZ
assert b.parent() is QQ
assert c.parent() is QQ
assert QQ.has_coerce_map_from(ZZ)
assert Rz.base_ring() is QQ
assert fz.prod() == pzfrom sage.all import PolynomialRing, QQ, ZZ
bilangan_bulat = ZZ(5)
bilangan_rasional = QQ(2) / 3
hasil_campuran = bilangan_bulat + bilangan_rasional
assert str(bilangan_bulat.parent()) == "Integer Ring"
assert str(bilangan_rasional.parent()) == "Rational Field"
assert hasil_campuran == QQ(17) / 3
assert hasil_campuran.parent() is QQ
gelang = PolynomialRing(QQ, "z")
z = gelang.gen()
polinom = z**4 - 1
faktorisasi = polinom.factor()
assert faktorisasi.prod() == polinom
assert {str(faktor) for faktor, _ in faktorisasi} == {
"z - 1",
"z + 1",
"z^2 + 1",
}Sage memakai peta kanonis ZZ ke QQ, sehingga hasil penjumlahan hidup di QQ dan tetap eksak. Polinom hidup di QQ[z]; mengalikan faktor di parent yang sama memberi sertifikat lokal bagi faktorisasi tersebut.
Selesaikan di SR, periksa residual setiap solusi secara eksak, lalu ubah akar positif secara eksplisit ke RR. Simpan nilai eksak, parent asal, nilai pendekatan, parent tujuan, dan presisinya. Jelaskan apa yang dibuktikan residual dan apa yang tidak.
Gunakan solve(..., solution_dict=True), simplify_full(), dan RR(akar). Jangan mengganti objek SR sebelum residual eksak diperiksa.
from sage.all import RR, SR, solve
w = SR.var("w")
baris_solusi = solve(w**2 == 5, w, solution_dict=True)
akar = [baris[w] for baris in baris_solusi]
assert {str(nilai) for nilai in akar} == {"-sqrt(5)", "sqrt(5)"}
assert all((nilai**2 - 5).simplify_full() == 0 for nilai in akar)
akar_positif = next(nilai for nilai in akar if nilai > 0)
hampiran = RR(akar_positif)
assert akar_positif.parent() is SR
assert hampiran.parent() is RR
assert RR.precision() == 53from sage.all import RR, SR, solve
w = SR.var("w")
solusi = solve(w**2 == 5, w, solution_dict=True)
nilai_eksak = sorted((baris[w] for baris in solusi), key=str)
residual_nol = [
bool((nilai**2 - 5).simplify_full() == 0)
for nilai in nilai_eksak
]
akar_positif = next(nilai for nilai in nilai_eksak if nilai > 0)
nilai_hampiran = RR(akar_positif)
rekaman = {
"exact": str(akar_positif),
"exact_parent": str(akar_positif.parent()),
"approximate": str(nilai_hampiran),
"approximate_parent": str(nilai_hampiran.parent()),
"precision_bits": RR.precision(),
}
assert residual_nol == [True, True]
assert rekaman["exact"] == "sqrt(5)"
assert rekaman["exact_parent"] == "Symbolic Ring"
assert rekaman["approximate_parent"].startswith("Real Field")
assert rekaman["precision_bits"] == 53Residual eksak memeriksa bahwa dua kandidat memenuhi persamaan. Konversi RR(akar_positif) menghasilkan pendekatan 53 bit tanpa menghapus rekaman objek eksak. Pemeriksaan ini tidak membuktikan kelengkapan algoritme solve untuk semua persamaan atau semua domain.
ZZ, QQ, RR, SR, parent dan coercion, gelang polinom, faktorisasi, penyelesaian, residual, serta konversi pendekatan eksplisit; layanan jarak jauh tidak menggantikannya.