Advertisement
Guest User

Untitled

a guest
May 22nd, 2019
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.16 KB | None | 0 0
  1. (ns edaa40.lab4)
  2.  
  3. (use 'clojure.set)
  4. (use 'edaa40.core)
  5.  
  6.  
  7. (declare create-square-sum-relation)
  8.  
  9. (declare H)
  10. (declare H')
  11.  
  12. (declare next-positions)
  13. (declare create-knights-move-relation)
  14.  
  15. ;;
  16. ;; test functions
  17. ;;
  18.  
  19. (defn- square-sum-sequence?
  20. "tests whether S is a square sum sequence, or whether it is a
  21. square sum sequence of the first n positive natural numbers"
  22.  
  23. (
  24. [S]
  25.  
  26. (case (count S)
  27. 0 true
  28. 1 true
  29. (and (square? (+ (first S) (second S))) (square-sum-sequence? (rest S)))
  30. )
  31. )
  32. (
  33. [S n]
  34.  
  35. (and (= n (count S))
  36. (= (set S) (set (range 1 (inc n))))
  37. (square-sum-sequence? S)
  38. )
  39. )
  40. )
  41.  
  42. (declare board)
  43.  
  44. (defn- knights-tour?
  45. "checks whether the path P is in fact a knight's tour on board B"
  46.  
  47. (
  48. [P B]
  49.  
  50. (if (<= (count P) 1)
  51. (= (set P) B)
  52. (and
  53. (B (first P))
  54. ((next-positions (first P) B) (second P))
  55. (knights-tour? (rest P) (disj B (first P)))
  56. )
  57. )
  58. )
  59. (
  60. [P n m]
  61.  
  62. (knights-tour? P (board n m))
  63. )
  64. )
  65.  
  66.  
  67. ;;
  68. ;; Part A: square sum problem
  69. ;;
  70.  
  71.  
  72. (defn create-square-sum-relation
  73. ;; "given a set A of integers, produces a relation that includes tuple [a b],
  74. ;; iff a and b are in A and their sum is a square number"
  75. ;;
  76. [A]
  77.  
  78.  
  79. (set (for [a A b A :when (square? (+ a b))] (vector a b)))
  80.  
  81.  
  82. ;;
  83. ;; ;; this one should be easy
  84. ;; ;; use square? to test whether a number is a square
  85. ;;
  86. )
  87. ;;
  88. (test? "create-square-sum-relation 1" (create-square-sum-relation #{3 6}) #{[3 6] [6 3]})
  89. (test? "create-square-sum-relation 2" (create-square-sum-relation #{3 7 19}) #{})
  90. (test? "create-square-sum-relation 3" (create-square-sum-relation (set (range 1 11))) #{[5 4] [2 2] [8 8] [4 5] [7 9] [1 3] [3 6] [6 10] [2 7] [1 8] [8 1] [7 2] [10 6] [6 3] [3 1] [9 7]})
  91.  
  92.  
  93. (defn square-sum-sequence
  94. "computes a list of the n first positive natural numbers such that any two
  95. consecutive numbers in that list add up to a square; returns nil if no
  96. such sequence exists"
  97.  
  98. [n]
  99.  
  100. (let
  101. [A (set (range 1 (inc n)))]
  102.  
  103. (H A (create-square-sum-relation A))
  104. )
  105. )
  106.  
  107.  
  108. ;;
  109. ;; Part B: Hamiltonian path
  110. ;;
  111.  
  112. (defn- H'
  113. ;;
  114. ;; "This is the helper function for computing the Hamiltonian path.
  115. ;; E is the relation, i.e. the graph, we are looking for a path in.
  116. ;; a is the current node.
  117. ;; S is the set of nodes we haven't visited yet.
  118. ;; P is the path we have traveled so far.
  119. ;;
  120. ;; H' should return a Hamiltonian path through E
  121. ;; that begins with P, then goes through a, and then visits every vertex
  122. ;; in the set S.
  123. ;; If no such path exists, it should return nil."
  124. ;;
  125. [E a S P]
  126. ;;
  127. {
  128. :pre [
  129. (not (contains? S a))
  130. (not (contains? (set P) a))
  131. (empty? (intersection S (set P)))
  132. ]
  133. :post [
  134. (or (empty? %) (= (set %) (union S (set P) #{a})))
  135. (or (empty? %) (= (count %) (+ (count S) (count P) 1)))
  136. ]
  137. }
  138. ;;
  139. ;;
  140. ;;
  141. ;; CAUTION: make sure you write the body of the function HERE
  142. ;; after the :pre/:post condition map.
  143. (if (empty? S) (concat P [a])
  144. (if (empty? (intersection (image-of E a) S))
  145. nil
  146. (some #(H' E % (disj S %) (concat P [a])) (intersection (image-of E a) S))
  147. )
  148. )
  149. ;;
  150. ;; ;; in my implementation, I used concat, disj, intersection, some, empty?
  151. ;; ;; and our old buddy image-of
  152. ;; ;; (concat P [a]) will append a to the end of P
  153. ;;
  154.  
  155. )
  156.  
  157. (defn H
  158. "compute a Hamiltonian path in the graph (V, E); returns a list of the elements in V in the
  159. order of that path, or nil if no such path exists"
  160.  
  161. [V E]
  162.  
  163. (some #(H' E % (disj V %) '()) V)
  164. )
  165.  
  166.  
  167. (test? "square-sum-sequence 1" (count (square-sum-sequence 14)) 0)
  168. (test? "square-sum-sequence 2" (square-sum-sequence? (square-sum-sequence 15) 15))
  169. (test? "square-sum-sequence 3" (square-sum-sequence? (square-sum-sequence 16) 16))
  170. (test? "square-sum-sequence 4" (square-sum-sequence? (square-sum-sequence 17) 17))
  171. (test? "square-sum-sequence 5" (count (square-sum-sequence 18)) 0)
  172. (test? "square-sum-sequence 6" (count (square-sum-sequence 19)) 0)
  173. (test? "square-sum-sequence 7" (count (square-sum-sequence 22)) 0)
  174. (test? "square-sum-sequence 8" (square-sum-sequence? (square-sum-sequence 23) 23))
  175. (test? "square-sum-sequence 9" (count (square-sum-sequence 24)) 0)
  176. (test? "square-sum-sequence 10" (square-sum-sequence? (square-sum-sequence 25) 25))
  177. (test? "square-sum-sequence 11" (square-sum-sequence? (square-sum-sequence 26) 26))
  178. (test? "square-sum-sequence 12" (square-sum-sequence? (square-sum-sequence 27) 27))
  179.  
  180.  
  181. ;;
  182. ;; You can now try to get a few square sum sequences in the REPL, e.g.
  183. ;; (square-sum-sequence 15)
  184. ;;
  185.  
  186.  
  187. ;;
  188. ;; Part C: knight's tour problem
  189. ;;
  190.  
  191. (defn board
  192. "computes the set of all positions on an n by m board; each position is a tuple of integers,
  193. from 0 to n-1 and 0 to m-1, respectively"
  194.  
  195. [n m]
  196.  
  197. (set (for [a (range 0 n) b (range 0 m)] [a b]))
  198. )
  199.  
  200.  
  201. (def Moves #{ [1 2] [2 1] [2 -1] [1 -2] [-1 -2] [-2 -1] [-2 1] [-1 2] })
  202.  
  203.  
  204. (defn add-move
  205. "adds a move, i.e. relative coordinates, to a position, resulting in the coordinates
  206. of the target position after the move (which may be outside the board)"
  207.  
  208. [pos move]
  209.  
  210. (vec (map + pos move))
  211. )
  212.  
  213. (defn next-positions
  214. ;; "given a position pos and a board B, this computes the set of all positions on the board
  215. ;; after any of the moves in Moves"
  216. ;;
  217. [pos B]
  218. ;;
  219. ;; ;; I used map, set, intersection to write this
  220. ;;
  221. (intersection #{
  222. [(+ (first pos) 1) (- (second pos) 2)]
  223. [(+ (first pos) 2) (- (second pos) 1)]
  224.  
  225. [(+ (first pos) 2) (+ (second pos) 1)]
  226. [(+ (first pos) 1) (+ (second pos) 2)]
  227.  
  228. [(- (first pos) 1) (+ (second pos) 2)]
  229. [(- (first pos) 2) (+ (second pos) 1)]
  230.  
  231. [(- (first pos) 2) (- (second pos) 1)]
  232. [(- (first pos) 1) (- (second pos) 2)]
  233. }
  234. B)
  235. )
  236. ;;
  237. (test? "next-positions 1" (next-positions [0 0] (board 3 3)) #{[2 1] [1 2]})
  238. (test? "next-positions 2" (next-positions [1 1] (board 3 3)) #{})
  239. (test? "next-positions 3" (next-positions [2 3] (board 8 8)) #{[4 4] [1 1] [3 5] [0 2] [0 4] [1 5] [3 1] [4 2]})
  240.  
  241.  
  242. (defn create-knights-move-relation
  243. ;;
  244. [B]
  245. ;;
  246. ;; ;; if you got this far, this should be no big deal
  247.  
  248. (set (for [x B y (next-positions x B)] [x, y]))
  249.  
  250. )
  251. ;;
  252. (test? "create-knights-move-relation 1" (create-knights-move-relation (board 2 3)) #{[[1 2] [0 0]] [[0 0] [1 2]] [[1 0] [0 2]] [[0 2] [1 0]]})
  253. (test? "create-knights-move-relation 2" (create-knights-move-relation (board 3 3)) #{[[0 0] [2 1]] [[0 1] [2 2]] [[2 2] [1 0]] [[1 2] [0 0]] [[0 0] [1 2]] [[2 1] [0 0]] [[2 2] [0 1]] [[1 0] [2 2]] [[2 0] [0 1]] [[2 1] [0 2]] [[2 0] [1 2]] [[1 0] [0 2]] [[1 2] [2 0]] [[0 1] [2 0]] [[0 2] [1 0]] [[0 2] [2 1]]})
  254. (test? "create-knights-move-relation 3" (create-knights-move-relation (board 2 2)) #{})
  255. (test? "create-knights-move-relation 4" #{} #{})
  256.  
  257.  
  258. (defn knights-tour
  259.  
  260. [n m]
  261.  
  262. (let
  263. [B (board n m)]
  264.  
  265. (H B (create-knights-move-relation B))
  266. )
  267. )
  268.  
  269.  
  270. (test? "knights-tour 1" (knights-tour 3 3) nil)
  271. (test? "knights-tour 2" (knights-tour? (knights-tour 3 4) 3 4))
  272. (test? "knights-tour 3" (knights-tour? (knights-tour 4 5) 4 5))
  273.  
  274.  
  275.  
  276. ;; Now try to find a few knight's tours:
  277. ;; (the results below are examples --- depending on the details of your implementation, the path you
  278. ;; find may be different)
  279.  
  280. ;; (knights-tour 3 3)
  281. ;; nil
  282. ;;
  283. ;; (knights-tour 3 4)
  284. ;; ([1 3] [0 1] [2 0] [1 2] [0 0] [2 1] [0 2] [2 3] [1 1] [0 3] [2 2] [1 0])
  285. ;;
  286. ;; (knights-tour 5 6)
  287. ;; ([4 0] [3 2] [1 1] [3 0] [4 2] [3 4] [1 5] [0 3] [2 2] [4 1] [2 0] [0 1] [1 3] [0 5] [2 4] [4 5] [3 3] [1 4] [0 2] [1 0] [3 1] [4 3] [3 5] [2 3] [4 4] [2 5] [0 4] [1 2] [0 0] [2 1])
  288. ;;
  289. ;; (knights-tour 6 6)
  290. ;; ([2 5] [4 4] [5 2] [4 0] [2 1] [3 3] [1 4] [3 5] [5 4] [4 2] [5 0] [3 1] [4 3] [5 5] [3 4] [1 5] [0 3] [1 1] [3 0] [5 1] [3 2] [2 0] [4 1] [5 3] [4 5] [2 4] [0 5] [1 3] [0 1] [2 2] [1 0] [0 2] [2 3] [0 4] [1 2] [0 0])]
  291. ;;
  292. ;; (knights-tour 6 7)
  293. ;; ([5 6] [3 5] [4 3] [5 1] [3 0] [4 2] [5 0] [3 1] [2 3] [1 1] [0 3] [1 5] [3 6] [5 5] [3 4] [1 3] [0 5] [2 6] [1 4] [0 6] [2 5] [4 6] [5 4] [3 3] [4 1] [2 0] [0 1] [2 2] [1 0] [0 2] [2 1] [4 0] [5 2] [4 4] [3 2] [5 3] [4 5] [2 4] [1 6] [0 4] [1 2] [0 0])
  294.  
  295. ;; The running time for this algorithm explodes very quickly as the boards get larger.
  296. ;; My old little laptop takes about 20min or so to find a path on a 6 by 7 board (time can vary wildly depending on the order in which nodes are being
  297. ;; explored, so comparisons of single runs don't really mean much), I have run out of patience for 8 by 8.
  298. ;; For timing the algorithm, you can use time-eval (the source is in the core package) as follows:
  299. ;; (time-eval (knights-tour 6 6))
  300. ;; It returns a two-element vector, the first component is the running time (in nanoseconds), and the second the value returned.
  301. ;;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement