Dokumentace programu sdc Zápočtového programu z Programování III pro neinformatiky — NRPM046 Ondřej Vostal∗ 8. června 2011, Zimní semestr, 2009/2010
1
Stručné zadání
sdc je symbolická kalkulačka, která umí derivovat a výsledek derivování mírně zjednodušit. Jako zjednodušení bude alespon provedeno sečtení konstant za použití distributivního zákona sčítání a násobení. Také budou zjednodušeny výrazy užitím asociativity násobení a sčítání. Dále budou provedeny podobné operace s mocninami: sečteny exponenty se stejnými základy a vynásobeny základy se stejnými mocninami. Upravování bude statické v tom smyslu, že se nebude přecházet mezi jednotlivými ekvivalentními výrazy u kterých by se určovala "jednoduchost"a z nich se vybral nejjednodušší. Spíše bude zjednodušení probíhat tak, že se ‘sdc’ pokusí výraz postupně zkracovat. Nebude se procházet přes dočasné zesložitení výrazu, ikdyž by to mohlo nakonec vést k většímu zjednodušení. Pouze se budou přetáčet jednotlivé argumenty u komutativních operací. Implicitně jsou zadány derivace všech elementárních funkcí, t.j. sin, cos, tan, exp, log, polynom, odmocnina. ∗
Ondřej Vostal je studentem Matematiky, 4. semestr, Matematicko-fyzikální fakulta
Univerzity Karlovy v Praze. mailto:
[email protected].
1
Tabulku známých jednoduchých derivací lze jednoduše rozšířit o nové. Lze také zavést nové symboly. Ty lze však definovat výlučně za použití konečného přirozeného skládání již defino- vaných symbolů. (např. n ∗ b je b + . . . + b, to celé n krát).
2
Přesnější zadání
Program bude interaktivní. Rozhraní programu je textové. Po spuštění program na vstupu očekává zadání dvou slov oddělených buď mezerou, nebo novou řádkou. Pokud je první slovo qq program skončí. Pokud je první slovo tt vypočtou se testové příklady a program skončí. Pokud je první i druhé slovo validní swi-prolog term, pak program na výstupu vypíše derivaci funkce y = T , kde T je druhý term podle proměnné definované prvním termem x. Proměnné ve funkci musí mít názvy složené z malých písmen anglické abecedy (a-z). Proměnná, podle které derivovat musí být stejně jako proměnné ve funkci malé písmeno anglické abecedy. To Do
Výstup programu bude seřazený
. Pokud bude v termu T
funkce, jejíž derivaci program nemůže spočítat, užije ve výstupu formální značení d(T, x) a pokusí se vyhodnotit zbytek výrazu, jak nejlépe to jen půjde. Program lze rozšiřovat přidáváním informací o derivování a aritmetických úpravách libovolných operátorů, nebo přidáním nových operátorů. O tom více v části o rozšiřování programu.
3
Prostředky implementace a použité algoritmy
Program jsem implementoval v prologu. Testování prováděl výlučně v swiprologu. Derivování jako takové je algoritmicky jednoduchá záležitost. Po načtení vstupního termu, který chci derivovat na něj spustím predikát, který zná základní pravidla pro derivování, plus libovolná přidaná pravidla. Ví například, 2
že derivace součtu je součet derivací, atd. Tím dojde k rekurzi a průchodu přes výraz. Složitější část programu představuje zjednodušení výsledného výrazu. Toho dociluji tak, že na výraz v pevném pořadí použiji různé zjednodušující transformace, které vzužívají algebraických vlastností operátorů a funkcí, ze terých se výraz skládá. Použiji transformace v pořadí, ve kterém je uvádím. Popsány budou dále: a) zjednodušovací pravidla (s); b) aritmetické vyhodnocení podvírazů (evaluate); c) přezávorkování (associate) a znovu užitá zjednodušovací pravidla; d) vytknutí (distrib); e) přezávorkování a vytknutí; f) seřazení podle zákonů komutativity (komut); g) vytknutí pro unárních operátory (unarzdistrib). Zjednodušení se nejprve zavolá rekurzivně do hloubky na každý podvýraz, přičemž podvýrazy jsou rozděleny vždy podle argumentů operátorů (viz op dále). Na výsledek každého zjednodušení rekurzivně zavolám zjednodušující predikát. Zjednodušování skončí ve chvíli, kdy už není, co zjednodušit. To, že se tak stane, je v programu zajištěno tak, že To Do .
3.1
Popis zjednodušujících predikátů
Predikáty zde uvedené lze rozšiřovat, nebo, chcete-li, nastavovat přípravou databáze pomocných faktů sdcrc.pl. U každého popíši, jak to lze udělat. 3.1.1
Zesložiťovací pravidla (cp)
O těchto nebyla výše řeč. Zesložitěním projde vstup, než se počítá jeho derivace. Odzesložitěním (což je predikát zesložitění použitý opačně) projde pak výstup, než je vytištěn. Zesložiťování umožní, aby mohl být vstup složitější a tím hezčí a zároveň program i databáze známých algebraických jevů 1
a derivací jednodušší. Např. sqrt(x) = x 2 ), kde sqrt lze napsat značně jednoduššeji, než mocninu x, ale program díky zesložitění při vstupu nemusí o funkci sqrt nic vědět. Predikát cp(?vnější reprezetace, ?vnitřní reprezentace) zajišťuje zesložiťování. Při přidávání, nebo změnách databáze sdcrc.pl je nutné mít 3
na paměti, že predikát nikdy nesmí být použitelný na svůj výsledek (přesněji nesmí se stát, aby cp(A,B),cp(B,C) uspělo, pro daný řádek). Jinak by se program zacyklil. Příklad je možné vyčíst z původní databáze. 3.1.2
Zjednodušovací pravidla (s)
Zjednodušovací pravidla jsou realizovaná v zásadě shodným predikátem jeko predikát cp, akorád předpokládám, že pdedikát s je pouze jednosměrný s(+Složitý výraz, -Jednoduchý výraz). Při přidávání dalších je opět potřeba mít na paměti, že nikdy nesmí uspět s(A,B),s(B,C) vezmeme-li pro definici s jen jeden řádek z databáze. Poznámka. Zacyklit se můžeme i přes více řádku definice predikátu s. Nepodařilo se mi ale vymyslet žádný příklad, který by toto mohl při běžném použití způsobit. Z faktu, že jen jedna forma výrazu je pro nás nejjednoduší by definice způsobující zacyklení stejně neměla smysl. Jako nesmyslný příklad budiž s(A,g(A)). s(g(A),-A). 3.1.3
Přezávorkování (associate)
Uzávorkování výrazů v programu implementuji tak, že kolem operátorů s argumenty si vždy představuji závorky. Tyto nemusí uživatel explicitně na vstupu zadat. Program si je tam představuje automaticky. Přezávorkování se provede tak, že např. platí associate(a+b+c,(a+b)+c). associate(a+b+c,a+(b+c)). Přičemž jednu z variant program generuje automaticky, podle toho, jakou přednost mají operátory. To je vnitřní věcí swi-prologu a není třeba se tím zaobírat, neboť algoritmus v každém případě vygeneruje všechny ostatní možná přezávorkování, jak plyne z postupu zjednodušení vrazu. 4
3.1.4
Vytknutí (distrib)
Vytýkání chápu v programu jako transformaci výrazu (1) (a ∗ b) + (c ∗ b), kde + a ∗ můžou být libovolné operátory. Předpokládám, že operátory nejsou komutativní (tedy že a ∗ b 6= b ∗ a). Zavádím dvě pravidla pro distributivitu. Distributivitou zprava myslím transformaci, která by z výrazu (1) udělala výraz (1r) (a +′ c) ∗′ b. Jde tedy o transformaci, kdy jsou výrazy napravo od vnitřních operátorů (zde ∗) stejné. Důležité je podotknout, že pořadí operandů je zachováno (c je napravo od svého operátoru a b je napravo od svého. Už je asi jasné, že levá transformace převádí výraz (2) (x∗2 3)+2 (x∗2 2) na výraz (2l) x ∗′2 (3 +′2 2) Skrze vytýkání také implementuji přičítání jednotek jako příklad poslouží (3) (x ∗ 2) + x transformuji na (3’) x ∗′ (2 +′ 1) (o sečtení konstant se pak postará jiná část programu). U jednotky už musím počítat s jejím výskytem na obou stranách, tedy je zvlášť implementováno pravidlo pro transformaci z (3) na (3’) a z (4) (p ∗ 4) + 1 na (4’) p ∗′ (4 +′ 1). Podobně pro distributivitu zleva.
5