Advertisement
Guest User

Untitled

a guest
Nov 17th, 2019
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.93 KB | None | 0 0
  1. \documentclass[a4]{tufte-handout}
  2. % The documentclass can be changed, but keep fonts at a reasonable size.
  3.  
  4. % comments
  5. \usepackage{comment}
  6.  
  7. % code environments
  8. \usepackage{listings}
  9. \lstnewenvironment{code}{
  10. \lstset{language=haskell, basicstyle=\ttfamily }}{}
  11. \lstnewenvironment{spec}{
  12. \lstset{language=haskell, basicstyle=\ttfamily }}{}
  13. \lstset{language=haskell, basicstyle=\ttfamily }
  14.  
  15.  
  16. \title{CO202: Coursework 1}
  17. \date{Autumn Term, 2019}
  18. \author{Group \#number}
  19.  
  20.  
  21. \begin{document}
  22. \maketitle
  23.  
  24. The source of this document is \texttt{Submision.lhs}, and should form the
  25. basis of your report as well as contain all the code for your submission. You
  26. should remove text (such as all the text in this section) that is here for your
  27. information only and that does not contribute to your submission.
  28. You should start by modifying the \verb|\author{}| command above to include
  29. your group number.
  30.  
  31. The source code of the provided \texttt{Submission.lhs} contains code and
  32. comments that are hidden from the final \texttt{pdf} file, so you should
  33. inspect it carefully. For instance, the code declares the use of various
  34. language features that are used in this code base. You can learn more about
  35. these language features in the language extensions section of the GHC
  36. documentation at
  37. \url{https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html}
  38. if you wish, but for the most part you need not worry about them.
  39. \begin{comment}
  40. The code in commented blocks such as this one is required for this file to
  41. compile.
  42. \begin{code}
  43. {-# LANGUAGE FlexibleInstances #-}
  44. {-# LANGUAGE ScopedTypeVariables #-}
  45. {-# LANGUAGE FunctionalDependencies #-}
  46. {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  47. {-# LANGUAGE StandaloneDeriving #-}
  48. {-# LANGUAGE InstanceSigs #-}
  49. {-# LANGUAGE UndecidableInstances #-}
  50. {-# LANGUAGE TypeApplications #-}
  51. \end{code}
  52. \end{comment}
  53.  
  54. The following imports various modules that are used. You should avoid depending
  55. on any libraries other than those distributed with GHC:
  56. \href{http://hackage.haskell.org/package/base}{\texttt{base}} and
  57. \href{https://hackage.haskell.org/package/containers}{\texttt{containers}}
  58. ought to contain everything you need.
  59. \begin{comment}
  60. \begin{code}
  61. module Submission where
  62.  
  63. import Prelude hiding (maximum)
  64. import Data.Maybe (fromJust)
  65. import Data.Coerce (coerce)
  66. import Data.Function (on)
  67.  
  68. import Data.Array
  69. import Data.List (nub, sortBy, maximumBy, minimumBy, tails, inits, mapAccumL, (\\))
  70. import Data.Map (Map)
  71. import qualified Data.Map as M
  72.  
  73. \end{code}
  74. \end{comment}
  75.  
  76. All of the necessary types and definitions from the specification of this
  77. coursework have been given to you in the source of this document. You need not repeat
  78. that code in your submission, but it is required within the \verb|\begin{code}| and \verb|\end{code}| markers so that it can be compiled.
  79.  
  80. Before submitting your coursework, you should ensure that your code compiles
  81. properly. Use the following command with the supplied
  82. \texttt{Submission.lhs-boot} file to check that it can be marked:
  83. \begin{spec}
  84. ghc -fforce-recomp -c Submission.lhs-boot Submission.lhs
  85. \end{spec}
  86. This checks to see if all the type signatures of exposed functions are as
  87. expected.
  88.  
  89.  
  90. \begin{comment}
  91. \begin{code}
  92. data Player = Player1 | Player2
  93. data Planet = Planet Owner Ships Growth
  94. newtype Ships = Ships Int
  95. newtype Growth = Growth Int
  96. data Owner = Neutral | Owned Player
  97. newtype PlanetId = PlanetId Int
  98. type Planets = Map PlanetId Planet
  99. data Wormhole = Wormhole Source Target Turns
  100.  
  101. newtype Source = Source PlanetId
  102. newtype Target = Target PlanetId
  103. newtype Turns = Turns Int
  104. newtype WormholeId = WormholeId Int
  105. type Wormholes = Map WormholeId Wormhole
  106. data Fleet = Fleet Player Ships WormholeId Turns
  107. type Fleets = [Fleet]
  108. data GameState = GameState Planets Wormholes Fleets
  109. data Order = Order WormholeId Ships
  110. \end{code}
  111. \end{comment}
  112.  
  113. \begin{comment}
  114. \begin{code}
  115. fib :: Int -> Integer
  116. fib 0 = 0
  117. fib 1 = 1
  118. fib n = fib (n-2) + fib (n-1)
  119.  
  120. fib' :: Int -> Integer
  121. fib' n = table ! n
  122. where
  123. table :: Array Int Integer
  124. table = tabulate (0, n) mfib
  125.  
  126. mfib 0 = 0
  127. mfib 1 = 1
  128. mfib n = table ! (n-1) + table ! (n-2)
  129.  
  130. tabulate :: Ix i => (i,i) -> (i -> a) -> Array i a
  131. tabulate (u,v) f = array (u,v) [ (i, f i) | i <- range (u, v)]
  132. \end{code}
  133. \end{comment}
  134.  
  135. \begin{comment}
  136. \begin{code}
  137. example1 :: GameState
  138. example1 = GameState planets wormholes fleets where
  139. planets = M.fromList
  140. [ (PlanetId 0, Planet (Owned Player1) (Ships 300) (Growth 0))
  141. , (PlanetId 1, Planet Neutral (Ships 200) (Growth 50))
  142. , (PlanetId 2, Planet Neutral (Ships 150) (Growth 10))
  143. , (PlanetId 3, Planet Neutral (Ships 30) (Growth 5))
  144. , (PlanetId 4, Planet Neutral (Ships 100) (Growth 20))
  145. ]
  146. wormholes = M.fromList
  147. [ (WormholeId 0, Wormhole homePlanet (Target 1) (Turns 1))
  148. , (WormholeId 1, Wormhole homePlanet (Target 2) (Turns 1))
  149. , (WormholeId 2, Wormhole homePlanet (Target 3) (Turns 1))
  150. , (WormholeId 3, Wormhole homePlanet (Target 4) (Turns 1))
  151. ] where homePlanet = Source 0
  152. fleets = []
  153.  
  154. targetPlanets :: GameState -> Source -> [(PlanetId, Ships, Growth)]
  155. targetPlanets st s
  156. = map (planetDetails . target) (M.elems (wormholesFrom s st))
  157. where
  158. planetDetails :: PlanetId -> (PlanetId, Ships, Growth)
  159. planetDetails pId = (pId, ships, growth)
  160. where Planet _ ships growth = lookupPlanet pId st
  161.  
  162. shipsOnPlanet :: GameState -> PlanetId -> Ships
  163. shipsOnPlanet st pId = ships
  164. where Planet _ ships _ = lookupPlanet pId st
  165.  
  166. lookupPlanet :: PlanetId -> GameState -> Planet
  167. lookupPlanet pId (GameState ps _ _) = fromJust (M.lookup pId ps)
  168.  
  169. wormholesFrom :: Source -> GameState -> Wormholes
  170. wormholesFrom pId (GameState _ ws _)
  171. = M.filter (\(Wormhole s _ _) -> s == pId) ws
  172.  
  173. wormholesTo :: Target -> GameState -> Wormholes
  174. wormholesTo pId (GameState _ ws _)
  175. = M.filter (\(Wormhole _ t _) -> t == pId) ws
  176.  
  177. knapsack :: (Ord weight, Num weight, Ord value, Num value) =>
  178. [(name, weight, value)] -> weight -> value
  179. knapsack wvs c = maximum 0 [ v + knapsack wvs (c - w) | (_,w,v) <- wvs , w <= c ]
  180.  
  181. maximum :: Ord a => a -> [a] -> a
  182. maximum x xs = foldr max x xs
  183. \end{code}
  184. \end{comment}
  185.  
  186. \marginnote{Make sure that the problems you are solving are clearly indicated.
  187. Using a section is a good idea. You should endeavor to concisely explain the
  188. code you have written. Feel free to make use of your own margin notes, and do
  189. please remove this one.}
  190. \section*{Problem 1: Dynamic Knapsack}
  191.  
  192. \begin{code}
  193. knapsack' :: forall name weight value .
  194. (Ix weight, Num weight, Ord value, Num value) =>
  195. [(name, weight, value)] -> weight -> value
  196. knapsack' wvs c = table ! c
  197. where
  198. table :: Array weight value
  199. table = tabulate (0,c) mknapsack
  200.  
  201. mknapsack :: weight -> value
  202. mknapsack c = maximum 0 [ v + table ! (c - w) | (_,w,v) <- wvs , w <= c ]
  203. \end{code}
  204.  
  205. \section*{Problem 2: Knapsack Elements}
  206.  
  207. \begin{code}
  208. knapsack'' :: forall name weight value .
  209. (Ix weight, Num weight, Ord value, Num value) =>
  210. [(name, weight, value)] -> weight -> (value, [name])
  211. knapsack'' wvs c = table ! c
  212. where
  213. table :: Array weight (value, [name])
  214. table = tabulate (0,c) mknapsack
  215.  
  216. mknapsack :: weight -> (value, [name])
  217. mknapsack c = maximumBy (compare `on` fst) xs
  218. where
  219. xs = (0, []) : [(v + v', n : es) | (n,w,v) <- wvs , w <= c, let (v', es) = table ! (c - w)]
  220. \end{code}
  221.  
  222. \section*{Problem 3: Bounded Knapsack}
  223. \begin{code}
  224. bknapsack
  225. :: (Ord weight, Num weight, Ord value, Num value)
  226. => [(name, weight, value)] -> weight -> (value, [name])
  227. bknapsack = undefined
  228. \end{code}
  229.  
  230. \section*{Problem 4: Reasonable Indexes}
  231.  
  232. \section*{Problem 5: Bounded Knapsack Revisited}
  233.  
  234. \begin{code}
  235. bknapsack' :: forall name weight value .
  236. (Ord weight, Num weight, Ord value, Num value) =>
  237. [(name, weight, value)] -> Int ->
  238. weight -> (value, [name])
  239. bknapsack' = undefined
  240. \end{code}
  241.  
  242. \section*{Problem 6: Dynamic Bounded Knapsack}
  243.  
  244. \begin{code}
  245. bknapsack'' :: forall name weight value .
  246. (Ord name, Ix weight, Ord weight, Num weight,
  247. Ord value, Num value) =>
  248. [(name, weight, value)] -> weight -> (value, [name])
  249. bknapsack'' = undefined
  250. \end{code}
  251.  
  252. \section*{Problem 7: Dijkstra Dualized}
  253.  
  254. \begin{comment}
  255. \begin{code}
  256. optimise :: GameState -> Source -> (Growth, [PlanetId])
  257. optimise st s@(Source p) = bknapsack'' (targetPlanets st s) (shipsOnPlanet st p)
  258.  
  259. type Weight = Integer
  260.  
  261. class Eq v => Edge e v | e -> v where
  262. source :: e -> v
  263. target :: e -> v
  264. weight :: e -> Weight
  265.  
  266. instance Edge (String, String, Integer) String where
  267. source (s, _, _) = s
  268. target (_, t, _) = t
  269. weight (_, _, i) = i
  270.  
  271. instance Edge Wormhole PlanetId where
  272. source (Wormhole (Source s) _ _) = s
  273. target (Wormhole _ (Target t) _) = t
  274. weight (Wormhole _ _ (Turns turns)) = toInteger turns
  275.  
  276. instance Edge (WormholeId, Wormhole) PlanetId where
  277. source (_, w) = source w
  278. target (_, w) = target w
  279. weight (_, w) = weight w
  280.  
  281. data Path e = Path Weight [e]
  282. \end{code}
  283.  
  284. \begin{code}
  285. pathFromEdge :: Edge e v => e -> Path e
  286. pathFromEdge e = Path (weight e) [e]
  287. \end{code}
  288.  
  289. \begin{code}
  290. extend :: Edge e v => Path e -> e -> Path e
  291. extend (Path _ []) _ = error "extend: Empty path"
  292. extend (Path d (e:es)) e'
  293. | target e == source e' = Path (d + weight e') (e':e:es)
  294. | otherwise = error "extend: Incompatible endpoints"
  295. \end{code}
  296.  
  297. \begin{code}
  298. pathFromEdges :: Edge e v => [e] -> Path e
  299. pathFromEdges (x : xs) = foldl extend (pathFromEdge x) xs
  300. pathFromEdges [] = error "pathFromEdges: Empty list of edges"
  301. \end{code}
  302.  
  303. \begin{code}
  304. instance Edge e v => Edge (Path e) v where
  305. source (Path _ es) = source (last es)
  306. target (Path _ es) = target (head es)
  307. weight (Path w _) = w
  308. \end{code}
  309.  
  310. \begin{code}
  311. class Edge e v => Graph g e v | g -> e where
  312. vertices :: g -> [v]
  313. edges :: g -> [e]
  314. edgesFrom :: g -> v -> [e]
  315. edgesTo :: g -> v -> [e]
  316. velem :: v -> g -> Bool
  317. eelem :: e -> g -> Bool
  318. \end{code}
  319.  
  320. \begin{code}
  321. instance (Eq e, Edge e v) => Graph [e] e v where
  322. vertices es = nub (map source es ++ map target es)
  323. edges es = es
  324. edgesFrom es v = [ e | e <- es, v == source e ]
  325. edgesTo es v = [ e | e <- es, v == target e ]
  326. velem v es = v `elem` vertices es
  327. eelem v es = v `elem` edges es
  328. \end{code}
  329.  
  330. \begin{code}
  331. example2 :: [(String, String, Integer)]
  332. example2 = [("s","t",10), ("s","y",5), ("t","x",1), ("t","y",2), ("y","t",3),
  333. ("y","x", 9), ("x","z",4), ("z","x",6), ("y","z",2), ("z","s",7)]
  334. \end{code}
  335.  
  336. \begin{code}
  337. instance Graph GameState (WormholeId, Wormhole) PlanetId where
  338. vertices (GameState ps _ _) = M.keys ps
  339. edges (GameState _ ws _) = M.assocs ws
  340. edgesTo st pId = M.toList (wormholesTo (Target pId) st)
  341. edgesFrom st pId = M.toList (wormholesFrom (Source pId) st)
  342. velem pId (GameState ps _ _) = M.member pId ps
  343. eelem (wId, _) (GameState _ ws _) = M.member wId ws
  344. \end{code}
  345. \end{comment}
  346.  
  347. \begin{comment}
  348. \begin{code}
  349. lte :: (a -> a -> Ordering) -> (a -> a -> Bool)
  350. lte cmp x y = cmp x y /= GT
  351.  
  352. eq :: (a -> a -> Ordering) -> (a -> a -> Bool)
  353. eq cmp x y = cmp x y == EQ
  354. \end{code}
  355.  
  356. \begin{code}
  357. class PQueue pqueue where
  358. toPQueue :: (a -> a -> Ordering) -> [a] -> pqueue a
  359. fromPQueue :: pqueue a -> [a]
  360.  
  361. priority :: pqueue a -> (a -> a -> Ordering)
  362.  
  363. empty :: (a -> a -> Ordering) -> pqueue a
  364. isEmpty :: pqueue a -> Bool
  365.  
  366. insert :: a -> pqueue a -> pqueue a
  367. delete :: a -> pqueue a -> pqueue a
  368.  
  369. extract :: pqueue a -> a
  370. discard :: pqueue a -> pqueue a
  371. detach :: pqueue a -> (a, pqueue a)
  372.  
  373. data PList a = PList (a -> a -> Ordering) [a]
  374.  
  375. instance PQueue PList where
  376.  
  377. toPQueue cmp xs = PList cmp (sortBy cmp xs)
  378.  
  379. fromPQueue (PList _ xs) = xs
  380.  
  381. empty cmp = PList cmp []
  382.  
  383. isEmpty (PList _ xs) = null xs
  384.  
  385. priority (PList cmp _) = cmp
  386.  
  387. insert x (PList cmp []) = PList cmp [x]
  388. insert x ps@(PList cmp xs)
  389. | x <= y = cons x ps
  390. | otherwise = cons y (insert x ys)
  391. where (<=) = lte cmp
  392. (y, ys) = detach ps
  393. cons x (PList cmp xs) = PList cmp (x:xs)
  394.  
  395. delete x (PList cmp []) = PList cmp []
  396. delete x ps@(PList cmp _)
  397. | x == y = ys
  398. | otherwise = cons y (delete x ys)
  399. where (==) = eq cmp
  400. (y, ys) = detach ps
  401. cons x (PList cmp xs) = PList cmp (x:xs)
  402.  
  403. extract (PList cmp (x:xs)) = x
  404.  
  405. discard (PList cmp (x:xs)) = PList cmp xs
  406.  
  407. detach (PList cmp (x:xs)) = (x, PList cmp xs)
  408.  
  409. cmpPath :: Path v -> Path v -> Ordering
  410. cmpPath (Path d _) (Path d' _) = compare d d'
  411. \end{code}
  412. \end{comment}
  413.  
  414. \begin{comment}
  415. \begin{code}
  416. shortestPaths :: forall g e v. Graph g e v => g -> v -> [Path e]
  417. shortestPaths g v = dijkstra g (vertices g \\ [v]) ps
  418. where
  419. ps :: PList (Path e)
  420. ps = foldr insert (empty cmpPath) (map pathFromEdge (edgesFrom g v))
  421. \end{code}
  422.  
  423. \begin{code}
  424. example3 :: GameState
  425. example3 = GameState planets wormholes fleets where
  426. planets = M.fromList
  427. [ (PlanetId 0, Planet (Owned Player1) (Ships 300) (Growth 0))
  428. , (PlanetId 1, Planet Neutral (Ships 200) (Growth 50))
  429. , (PlanetId 2, Planet Neutral (Ships 150) (Growth 10))
  430. , (PlanetId 3, Planet Neutral (Ships 30) (Growth 5))
  431. , (PlanetId 4, Planet Neutral (Ships 100) (Growth 20))
  432. , (PlanetId 5, Planet Neutral (Ships 100) (Growth 20))
  433. ]
  434. wormholes = M.fromList
  435. [ (WormholeId 0, Wormhole homePlanet (Target 1) (Turns 1))
  436. , (WormholeId 1, Wormhole homePlanet (Target 2) (Turns 2))
  437. , (WormholeId 2, Wormhole homePlanet (Target 3) (Turns 3))
  438. , (WormholeId 3, Wormhole homePlanet (Target 4) (Turns 4))
  439. , (WormholeId 4, Wormhole (Source 4) (Target 5) (Turns 1))
  440. , (WormholeId 5, Wormhole (Source 2) (Target 5) (Turns 1))
  441. ] where homePlanet = Source 0
  442. fleets = []
  443. \end{code}
  444.  
  445. \begin{code}
  446. dijkstra :: (Graph g e v, PQueue pqueue) =>
  447. g -> [v] -> pqueue (Path e) -> [Path e]
  448. dijkstra g [] ps = []
  449. dijkstra g us ps
  450. | isEmpty ps = []
  451. | v `elem` us = p : dijkstra g (us \\ [v])
  452. (foldr insert ps' (map (extend p) (edgesFrom g v)))
  453. | otherwise = dijkstra g us ps'
  454. where
  455. (p, ps') = detach ps
  456. v = target p
  457. \end{code}
  458. \end{comment}
  459.  
  460. \section*{Problem 8: Heap Operations}
  461.  
  462.  
  463. \begin{code}
  464. data Heap a = Heap (a -> a -> Ordering) (Tree a)
  465. data Tree a = Nil | Node Int (Tree a) a (Tree a)
  466.  
  467. instance PQueue Heap where
  468. toPQueue = undefined
  469. fromPQueue = undefined
  470.  
  471. priority :: Heap a -> (a -> a -> Ordering)
  472. priority = undefined
  473.  
  474. empty :: (a -> a -> Ordering) -> Heap a
  475. empty p = undefined
  476.  
  477. isEmpty :: Heap a -> Bool
  478. isEmpty = undefined
  479.  
  480. insert :: a -> Heap a -> Heap a
  481. insert = undefined
  482.  
  483. delete :: a -> Heap a -> Heap a
  484. delete = undefined
  485.  
  486. extract :: Heap a -> a
  487. extract = undefined
  488.  
  489. discard :: Heap a -> Heap a
  490. discard = undefined
  491.  
  492. detach :: Heap a -> (a, Heap a)
  493. detach = undefined
  494. \end{code}
  495.  
  496. \begin{comment}
  497. \begin{code}
  498. shortestPaths' :: forall g e v . Graph g e v => g -> v -> [Path e]
  499. shortestPaths' g v = dijkstra g (vertices g) ps
  500. where
  501. ps :: Heap (Path e)
  502. ps = foldr insert (empty cmpPath) (map pathFromEdge (edgesFrom g v))
  503. \end{code}
  504. \end{comment}
  505.  
  506. \section*{Problem 9: Adjacency List Graphs}
  507.  
  508. \begin{code}
  509. newtype AdjList e v = AdjList [(v, [e])]
  510.  
  511. instance (Eq e, Edge e v) => Graph (AdjList e v) e v where
  512. vertices (AdjList ves) = undefined
  513. edges (AdjList ves) = undefined
  514. edgesFrom (AdjList ves) s = undefined
  515. edgesTo (AdjList ves) t = undefined
  516. velem v (AdjList ves) = undefined
  517. eelem e (AdjList ves) = undefined
  518. \end{code}
  519.  
  520. \section*{Problem 10: Conflict Zones}
  521.  
  522. \begin{code}
  523. conflictZones :: GameState -> PlanetId -> PlanetId
  524. -> ([PlanetId], [PlanetId], [PlanetId])
  525. conflictZones g p q = undefined
  526. \end{code}
  527.  
  528. \begin{comment}
  529. \begin{code}
  530. deriving instance Show Player
  531. deriving instance Read Player
  532. deriving instance Show Owner
  533. deriving instance Read Owner
  534. deriving instance Show Planet
  535. deriving instance Read Planet
  536. deriving instance Show Fleet
  537. deriving instance Read Fleet
  538.  
  539. deriving instance Show Wormhole
  540. deriving instance Read Wormhole
  541.  
  542. deriving instance Show Order
  543. deriving instance Read Order
  544. deriving instance Show GameState
  545. deriving instance Read GameState
  546.  
  547. deriving instance Ord PlanetId
  548. deriving instance Eq PlanetId
  549. deriving instance Num PlanetId
  550. instance Show PlanetId where
  551. show (PlanetId x) = show x
  552. instance Read PlanetId where
  553. readsPrec = coerce (readsPrec @Int)
  554.  
  555. deriving instance Ord Turns
  556. deriving instance Eq Turns
  557. deriving instance Num Turns
  558. instance Show Turns where
  559. show (Turns x) = show x
  560. instance Read Turns where
  561. readsPrec = coerce (readsPrec @Int)
  562.  
  563. deriving instance Ord Source
  564. deriving instance Eq Source
  565. instance Show Source where
  566. show (Source x) = show x
  567. instance Read Source where
  568. readsPrec = coerce (readsPrec @Int)
  569.  
  570. deriving instance Num Growth
  571. deriving instance Ord Growth
  572. deriving instance Eq Growth
  573. instance Show Growth where
  574. show (Growth x) = show x
  575. instance Read Growth where
  576. readsPrec = coerce (readsPrec @Int)
  577.  
  578. deriving instance Ix Ships
  579. deriving instance Num Ships
  580. deriving instance Ord Ships
  581. deriving instance Eq Ships
  582. instance Show Ships where
  583. show (Ships x) = show x
  584. instance Read Ships where
  585. readsPrec = coerce (readsPrec @Int)
  586.  
  587. deriving instance Ord Target
  588. deriving instance Eq Target
  589. instance Show Target where
  590. show (Target x) = show x
  591. instance Read Target where
  592. readsPrec = coerce (readsPrec @Int)
  593.  
  594. deriving instance Eq WormholeId
  595. deriving instance Ord WormholeId
  596. instance Show WormholeId where
  597. show (WormholeId x) = show x
  598. instance Read WormholeId where
  599. readsPrec = coerce (readsPrec @Int)
  600.  
  601. deriving instance Eq e => Eq (Path e)
  602. deriving instance Show e => Show (Path e)
  603. instance Show a => Show (PList a) where
  604. show (PList _ xs) = show xs
  605.  
  606. \end{code}
  607. \end{comment}
  608.  
  609. \end{document}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement