Løsningsforslag, INF212, uke 15 Harald Askestad med innspill fra klassen og de andre gruppelærerne April 11, 2002 Exercise 9.1.3 a) integer firepower(); b) Set<Ship> sisterShips() raises (noSisters); c) Set<Ship> sunk(IN Battle b) raises (didNotPartitipate); d) Ship new (IN string name, IN integer yearLaunched) raises (shipExists); Exercise 9.1.5 a) Find the names of the classes of ships with at least nine guns. SELECT FROM WHERE c.name Classes c s.numGuns >=9 b) Find the ships (objects, not ship names) with at least nine guns. SELECT FROM WHERE s Ships s s.classOf.numGuns >= 9 Or an alternative which exploits the use of nested loops that are explained on page 429. 1 SELECT FROM WHERE s Classes c, c.ships s c.numGuns >= 9 c) Find the names of the ships with a displacement under 30,000 tons. Make the results a list, ordered by earliest launch year first, and if there are ties, alphabetically by ship name. SELECT FROM WHERE ORDER BY s.name Ships s s.classOf.displacement < 30000 s.launched, s.name d) Find the pairs of objects that are sister ships (i.e., ships of the same class). SELECT FROM WHERE Struct{ship1: s1, ship2: s2} Ships s1, Ships s2 s1.classOf = s2.classOf AND s1.name > s2.name Or the alternative: SELECT FROM WHERE Struct{ship1: s, ship2: sister} Ships s, s.classOf.ships sister s.name < sister.name e) Find the names of the battles in which ships of at least two different countries were sunk. SELECT FROM WHERE b.name Battles b COUNT(SELECT DISTINCT c.country FROM b.results r, r.theShip.classOf c WHERE r.status = sunk) >=2 f) Find the names of the battles in which no ship was listed as damaged. SELECT FROM WHERE b.name Battles b not exists x in b.results: x.status = damaged 2 Exercise 9.2.2 a) Find those classes of ship all of whose ships were launched prior to 1919. SELECT FROM WHERE c Classes c for all x in c.ships: x.launched < 1919 Alternately, using exists: SELECT FROM WHERE c Classes c not exists x in c.ships: x.launched >= 1919 b) Find the maximum displacement of any class. MAX (SELECT c.displacement FROM Classes c) c) For each gun bore, find the earliest year in which any ship of that bore was launched. SELECT FROM GROUP BY bore, MIN(SELECT s.year FROM partition p, p.c.ships s) Classes c bore: c.bore d) For each class of ships at least one of which was launched prior to 1919, find the number of ships of that class sunk in battle. SELECT FROM WHERE c.name, COUNT (SELECT FROM WHERE s c.ships s exists y in s.inBattles: y.status = sunk) as ships_sunk Classes c exists x in c.ships: x.launched < 1919 The authors give the following solution: 3 SELECT class, COUNT(SELECT part.s FROM partition part WHERE EXISTS outcome IN Outcomes : outcome.theShip = part.s AND outcome.status = sunk) FROM Ships s GROUP BY class: s.classOf HAVING MIN(SELECT part.s.launched FROM partition part) < 1919 e) Find the average number of ships in a class. AVG(SELECT COUNT(c.ships) FROM Classes c) All container classes like Set, Bag, List, Array etc. have all the builtin functions that we would expect of a thypical ADT. This can be used in this query as follows: AVG(SELECT c.ships.size() FROM Classes c) f) Find the average displacement of a ship (The question is interpreted as Find the average displacement of all the ships). AVG(SELECT s.classOf.displacement FROM Ships s) Or an alternative that avoids dotting: AVG(SELECT c.displacement FROM Classes c, c.ships s) g) Find the battles (objects, not names) in which at least one ship from Great Britain took part and in which at least two ships were sunk. SELECT FROM WHERE b Battles b (exists x in b.results: x.theShip.classOf.country = "Great Britain") AND COUNT (SELECT r FROM b.results r WHERE r.status = sunk) >= 2 4 Exercise 9.2.4 Is it ever possible for FOR ALL x IN S: C(x) to be true, while EXISTS x IN S: C(x) is false? Yes. If no x in a nonempty set S satisfies the condition C, then obviously, not all x will satisfy it. But if S is empty, then FOR ALL x IN S: C(x) will allways be true, whatever the condition C, but no x will exist that satisfies C. Another way to reason is to regard the well known equivalence: FOR ALL x IN S: C(x) ≡ NOT EXISTS x IN S: NOT C(x) If S is non-empty and EXISTS x IN S: C(x) is false, then C(x) must be false for all x in S. That makes the query NOT EXISTS x IN S: NOT C(x) false. To see this, note that NOT C(x) is true for all x, meaning that EXISTS x IN S: NOT C(x) is true. By the equivalence, FOR ALL x IN S: C(x) will also become false. If S is empty, then EXISTS x ... is false, and NOT EXISTS x ... is true. By the equivalence, FOR ALL x IN S: C(x) will also become true. Exercise 9.4.1 a) Type declaration for NameType CREATE TYPE NameType AS ( firstName CHAR(30), middleName CHAR(30), lastName CHAR(30), title CHAR(30), ); b) Type declaration for PersonType CREATE TYPE PersonType AS ( name NameType, mother REF(PersonType), father REF(PersonType), ); c) Type declaration for MarriageType 5 CREATE TYPE MarriageType AS ( dateMarried DATE, wife REF(PersonType), husband REF(PersonType), ); Where DATE is the date type of the database. 6