p150.scm 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. ;; Searching a triangle array for a sub-triangle having minimum-sum
  2. (define-module (unsolved p150))
  3. (use-modules (unsolved p150h)
  4. (euler generators)
  5. (srfi srfi-1)
  6. (rnrs base))
  7. ;; Going to pretend that I don't have indexes
  8. ;; We probably want to do indices actually, since we need to know history
  9. ;; This might be a good macro opportunity
  10. ;; Looks like it's faster to do pattern matching
  11. (define-public (min-sub-triangle-sum triangle)
  12. (define row-length (- (triangle-rows triangle) 1))
  13. (define side-sums (make-sides triangle))
  14. (define intersect-sums (make-intersections triangle))
  15. (let lp ([l-idx 0] [r-idx 0] [b-idx 0] [max-sum 0])
  16. (cond
  17. [(> l-idx row-length) (- (triangle-sum triangle) max-sum)]
  18. [(> r-idx (- row-length l-idx)) (lp (1+ l-idx) 0 0 max-sum)]
  19. [(> b-idx (- row-length (+ l-idx r-idx))) (lp l-idx (1+ r-idx) 0 max-sum)]
  20. [else
  21. (lp
  22. l-idx r-idx (1+ b-idx)
  23. (let ([curr-sum
  24. (- (+
  25. (vector-ref (car side-sums) l-idx)
  26. (vector-ref (cadr side-sums) r-idx)
  27. (vector-ref (last side-sums) b-idx))
  28. (+
  29. (vector-ref (vector-ref (car intersect-sums) l-idx) r-idx)
  30. (vector-ref (vector-ref (cadr intersect-sums) l-idx) b-idx)
  31. (vector-ref (vector-ref (last intersect-sums) r-idx) b-idx)))])
  32. (if (> curr-sum max-sum) curr-sum max-sum)))])))
  33. (define (temp-stuff)
  34. (when (and (= 3 l-idx) (= 1 r-idx))
  35. (display curr-sum)
  36. (newline)
  37. (display
  38. (vector-ref (car side-sums) l-idx))
  39. (newline)
  40. (display
  41. (vector-ref (cadr side-sums) r-idx))
  42. (newline)
  43. (display
  44. (vector-ref (last side-sums) b-idx))
  45. (newline)
  46. (newline)
  47. (display
  48. (vector-ref (vector-ref (car intersect-sums) l-idx) r-idx))
  49. (newline)
  50. (display
  51. (vector-ref (vector-ref (cadr intersect-sums) l-idx) b-idx))
  52. (newline)
  53. (display
  54. (vector-ref (vector-ref (last intersect-sums) r-idx) b-idx))
  55. (newline)))
  56. ;; Now that we have these lists, we don't need the triangle!
  57. ;; To find min-sub, we find max external region!
  58. ;; Pattern matching would be great here!
  59. (define-public (min-sub-triangle-sum-b triangle)
  60. (let ([side-sums (make-sides triangle)]
  61. [intersect-sums (make-intersections triangle)])
  62. ;; Using -1 since we are doing a do, while
  63. (let lp ([l-idx -1] [r-idx -1] [b-idx 0]
  64. [intersections (init-intersections triangle)]
  65. [curr-sum curr-sum] [min-sum curr-sum])
  66. (cond
  67. [(>= l-idx row-length) min-sum]
  68. [(>= r-idx row-length)
  69. (update-intersections! triangle intersections)
  70. (lp (1+ l-idx) -1 0 intersections curr-sum min-sum)]
  71. [(>= b-idx row-length)
  72. (update-intersections! triangle intersections)
  73. (lp l-idx (1+ r-idx) 0 intersections curr-sum min-sum)]
  74. [else
  75. (lp l-idx
  76. r-idx (1+ b-idx)
  77. intersections
  78. curr-sum
  79. min-sum)]))))
  80. (define-public (make-triangle values rows)
  81. (let ([triangle (make-vector rows 0)])
  82. (let lp ([curr-row 1] [values values])
  83. (if (> curr-row rows) triangle
  84. (begin
  85. (vector-set! triangle
  86. (1- curr-row)
  87. (list->vector (take values curr-row)))
  88. (lp (1+ curr-row) (drop values curr-row)))))))
  89. ;;; Triangles for tests
  90. (define-public test-triangle1 (make-triangle '(1 2 3 4 5 6 1 1 1 1) 4))
  91. (define test-triangle2 (make-triangle '(2 4 5 1 1 1) 3))
  92. (define test-triangle3 (make-triangle '(1 2 3 4 5 6 1 1 1 1 1 1 1 1 1) 5))
  93. (define test-triangle4 (make-triangle '(2 4 5 1 1 1 1 1 1 1) 4))
  94. (define-public problem-triangle
  95. (make-triangle (linear-congruential-generator 500500) 1000))
  96. (define-public problem-triangle-small
  97. (make-triangle (linear-congruential-generator 500500) 300))
  98. (define large-triangle
  99. (make-triangle (iota 500500 1 -1) 400))
  100. (define-public example-triangle
  101. (make-triangle
  102. '(15 -14 -7 20 -13 -5 -3 8 23 -26 1 -4 -5 -18 5 -16 31 2 9 28 3)
  103. 6))
  104. ;;; Old stuff:
  105. ;; What takes a long time: creating the sub-triangles
  106. ;; summing the whole triangle
  107. ;; Slow for large triangles
  108. (define-public (triangle-sum triangle)
  109. (fold (lambda (row acc)
  110. (apply + acc (vector->list row)))
  111. 0
  112. (vector->list triangle)))
  113. (define-public (triangle-rows triangle)
  114. (vector-length triangle))
  115. ;; Need to add right/left sums
  116. ;; This takes 2 and 1/2 minutes to run when accessing row-vector cache
  117. (define (sub-triangle-sums triangle vect row-idx vert-idx curr-sum)
  118. (let lp ([curr-row-idx (1- (triangle-rows triangle))]
  119. [sub-sums (list curr-sum)])
  120. (if (<= curr-row-idx (1+ row-idx)) sub-sums
  121. (lp
  122. (1- curr-row-idx)
  123. (cons (- (car sub-sums)
  124. (row-sum-vect vect
  125. ;triangle
  126. ; curr-row-idx vert-idx
  127. ; (- (1+ curr-row-idx) row-idx)
  128. ))
  129. sub-sums)))))
  130. ;; TODO: eventually turn these two into the same function
  131. (define (right-sub-sum triangle parent-row-idx parent-vert-idx parent-sum)
  132. (let lp ([curr-row-idx parent-row-idx] [curr-sum parent-sum])
  133. (if (>= curr-row-idx (triangle-rows triangle))
  134. curr-sum
  135. (lp (1+ curr-row-idx)
  136. (- curr-sum (vector-ref
  137. (vector-ref triangle curr-row-idx)
  138. parent-vert-idx))))))
  139. (define (left-sub-sum triangle parent-row-idx parent-vert-idx parent-sum)
  140. (let lp ([curr-row-idx parent-row-idx]
  141. [curr-val-idx parent-vert-idx] [curr-sum parent-sum])
  142. (if (>= curr-row-idx (triangle-rows triangle))
  143. curr-sum
  144. (lp (1+ curr-row-idx)
  145. (1+ curr-val-idx)
  146. (- curr-sum (vector-ref
  147. (vector-ref triangle curr-row-idx)
  148. curr-val-idx))))))
  149. (define hash-t
  150. (let ([hash-tab (make-hash-table 1000)])
  151. (do [(i 0 (1+ i))]
  152. [(> i (expt 10 6)) hash-tab]
  153. (hashv-set! hash-tab (list i i) i))))
  154. (define counter 0)
  155. (define limit (expt 10 3))
  156. (define (row-sum-fast)
  157. (set! counter (if (>= counter limit) 0 (1+ counter)))
  158. (hashq-ref hash-t counter))
  159. (define (row-sum-vect vect)
  160. (set! counter (if (>= counter limit) 0 (1+ counter)))
  161. (vector-ref (vector-ref vect counter) counter))
  162. (define (row-sum-fastest) 0)
  163. ;; I wonder if this is what is taking so long...
  164. (define (row-sum triangle row-idx val-idx row-size)
  165. (apply +
  166. (take (drop (vector->list (vector-ref triangle row-idx))
  167. val-idx)
  168. row-size)))
  169. ;; TODO: figure out the most elegant way of traversing the triangle
  170. ;; Okay need to figure out the case when vert-idx = row-idx
  171. ;; For now, doing case where we recur down right off the bat
  172. (define-public (min-sum-sub-triangle triangle)
  173. (define vect
  174. (vector-map (lambda (val index)
  175. (make-vector index index))
  176. (make-vector (expt 10 4) 0)
  177. (list->vector (iota (expt 10 4) 1))))
  178. (let ([curr-sum (triangle-sum triangle)])
  179. (let lp ([row-idx 0]
  180. [vert-idx 0] [curr-sum curr-sum]
  181. [min-sum curr-sum])
  182. ;; Need to get the proper min sum here...
  183. ;; Note: i am not being tal
  184. (cond
  185. [(<= (- (triangle-rows triangle) row-idx) 1) min-sum]
  186. [(= vert-idx row-idx)
  187. ;; lp to the left then right
  188. (let ([left-min-sum
  189. (lp (1+ row-idx) vert-idx
  190. (left-sub-sum triangle row-idx vert-idx curr-sum)
  191. (apply min min-sum
  192. (left-sub-sums triangle vect row-idx vert-idx curr-sum)))])
  193. ;; Now looping to the right
  194. (lp (1+ row-idx) (1+ vert-idx)
  195. (right-sub-sum triangle row-idx vert-idx curr-sum)
  196. (apply min left-min-sum
  197. (right-sub-sums triangle vect row-idx vert-idx curr-sum))))]
  198. [else
  199. (lp (1+ row-idx)
  200. vert-idx (left-sub-sum triangle row-idx vert-idx curr-sum)
  201. (apply min min-sum
  202. (left-sub-sums triangle vect row-idx vert-idx curr-sum)))]))))
  203. (define (left-sub-sums triangle vect parent-row-idx parent-vert-idx parent-sum)
  204. (sub-triangle-sums triangle
  205. vect (1+ parent-row-idx) parent-vert-idx
  206. (left-sub-sum triangle
  207. parent-row-idx parent-vert-idx
  208. parent-sum)))
  209. (define (right-sub-sums triangle vect row-idx vert-idx curr-sum)
  210. (sub-triangle-sums triangle vect (1+ row-idx) (1+ vert-idx)
  211. (right-sub-sum triangle row-idx vert-idx curr-sum)))
  212. ;;; Not useful for large triangles
  213. (define (make-sub-triangle triangle row-idx val-idx)
  214. (let ([sub-triangle (make-vector
  215. (- (vector-length triangle) row-idx)
  216. #f)])
  217. (do [(sub-row-idx 0 (1+ sub-row-idx))]
  218. [(>= (+ row-idx sub-row-idx) (triangle-rows triangle)) sub-triangle]
  219. (let ([sub-row (make-vector (1+ sub-row-idx) #f)])
  220. (vector-move-left! (vector-ref triangle (+ sub-row-idx row-idx))
  221. val-idx (+ 1 val-idx sub-row-idx) sub-row
  222. 0)
  223. (vector-set! sub-triangle sub-row-idx sub-row)))))
  224. ;; Would be intersted to figure out a better way to generate
  225. ;; Mini test suite
  226. (define (test-sub-triangle-sums triangle)
  227. (let ([sum (triangle-sum triangle)])
  228. (assert (= (left-sub-sum triangle 0 0 sum)
  229. (triangle-sum (make-sub-triangle triangle 1 0))))
  230. (assert (= (right-sub-sum triangle 0 0 sum)
  231. (triangle-sum (make-sub-triangle triangle 1 1))))
  232. (display (right-sub-sums triangle 0 0 sum))
  233. (display (sub-triangle-sums triangle 1 1 (right-sub-sum triangle 0 0 sum)))
  234. (assert (equal? (left-sub-sums triangle 0 0 sum)
  235. (sub-triangle-sums triangle 1 0 (left-sub-sum triangle 0 0 sum))))))
  236. ;; Note to self: I should have checked how long the sum would take before I implement my solution, since it is all useless now...