Logică și structuri discrete - Relații: Exerciții

1. Ordini parțiale Orice limbaj de programare definește o ordine de evaluare pentru expresii. În C, operatorii &&  ||  , (virgula pentru secvențiere) și ? : (condițional) își evaluează întâi primul operand și apoi al doilea (la && și || dacă mai e nevoie; la condițional, după caz, al doilea sau al treilea operand). Pentru ceilalți operatori, ordinea de evaluare e nespecificată, adică poate fi oricare (de exemplu, f(x) + g(x) poate apela întâi g și apoi f înainte de a face suma).
Asemănător sunt ordonate și efectele laterale (engl. side effects, atribuirile/citirile/scrierile) în cadrul unei expresii. Pentru &&  ||  , ? : efectele laterale din evaluarea primului operand au loc înainte de a evalua restul expresiei. Pentru o funcție, efectele laterale din evaluarea argumentelor (și a expresiei care ne dă funcția apelată -- obișnuit un nume de funcție, dar poate fi o expresie) au loc înaintea apelului funcției. În rest, ordinea de aplicare a efectelor laterale în cadrul evaluării unei expresii nu e precizată.
Deci, între pașii de evaluare e definită o ordine parțială (ea e specificată între anumiți pași, nu neapărat între toți). Dacă într-o expresie asupra aceluiași obiect se fac două scrieri sau o citire și o scriere care nu sunt ordonate, rezultatul e nedefinit și compilatorul dă un avertisment.
De exemplu, expresia v[i] = i++ are următorii pași de evaluare:

Notând ordonarea cu <, avem următoarele constrângeri: și evident consecințele faptului că ordinea parțială < e tranzitivă, deci a < g etc.
Observăm că avem două citiri ale lui i (pașii b și d) și o scriere (efectul lateral de la f). Avem d < f dar nu avem o ordonare între citirea b și scrierea f deci efectul atribuirii v[i] = i++ e nedefinit și un compilator conform cu standardul va avertiza.
Concret, dacă i e inițial 0, valoarea atribuită (i++) va fi întotdeauna 0. Însă, dacă b) e evaluat înainte de f), atribuirea se face la v[0], altfel, dacă f) are loc înainte de b) atribuirea se face la v[1].
De rezolvat: Pentru expresiile i = ++i și respectiv f(i++, i++) detaliați pașii de evaluare, ordinea parțială dintre ei, și argumentați dacă expresiile sunt definite sau nu, detaliind ce rezultate posibile există.

2. Map.find și excepții Scrieți o funcție care primește un dicționar de la șiruri la întregi și o listă de șiruri și returnează mulțimea tuturor valorilor din dicționar care corespund șirurilor din listă.
Parcurgeți lista cu fold_left și tratați excepția Not_found pentru a adăuga o valoare la mulțimea-acumulator doar când cheia e găsită în dicționar.

3. Maximul din dicționar Scrieți o funcție care primește o funcție și un dicționar și returnează maximul valorilor funcției pentru toate intrările dicționarului, sau generează excepția Not_found pentru un dicționar vid.
Funcția-parametru are ca argumente cheia și valoarea unei intrări, și poate returna valori arbitrare. Folosiți fold pentru parcurgere, și max (definită implicit pentru orice tip) pentru a compara valorile returnate de funcția parametru.

4. Închiderea tranzitivă Considerăm funcții parțiale reprezentate prin dicționare de la șiruri la șiruri. Ele sunt un caz particular de relații (pe șiruri), care asociază unui element cel mult un element (șirurile care nu sunt chei în dicționar nu au asociată vreo valoare).
Pornind de la exemplul de compunere a două funcții date ca dicționare
a) Scrieți o funcție care ia un dicționar reprezentând o funcție f și un număr n și returnează dicționarul reprezentând compunerea lui f cu ea însăși de n ori.
b) Privind f ca relație R (mulțime de perechi) scrieți o funcție care luând un dicționar (pentru R) și un număr n returnează mulțimea perechilor din R≤n = R ∪ R2 ∪ ... ∪ Rn.
c) Calculați închiderea tranzitivă a relației R, găsind prima valoare n pentru care R≤n = R≤n+1 . Folosiți o pereche (R≤n-1, Rn) din care calculați (R≤n, Rn+1).
d) (opțional). Tipăriți dicționarul în formatul dot după exemplul următor:

digraph {
  foo -> bar;
  bar -> baz;
}
Puteți să vizualizați apoi rezultatul aici (sau instalând pachetul Graphviz).
Dând atribute de culori pentru muchii: foo -> bar [color="red"]; (de exemplu dintr-o listă de culori) puteți vizualiza simultan relațiile Rn pentru diverse valori ale lui n.


Marius Minea
Last modified: Sat Oct 31 14:30:00 EET 2015