accelerated.pyx 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048
  1. import numpy as np
  2. #~ from numpy cimport *
  3. cimport numpy as np
  4. cimport cython
  5. from cython.parallel import prange, parallel, threadid
  6. from libc.stdlib cimport malloc, free, calloc
  7. #~ long random()
  8. cdef import from "math.h":
  9. double log10(double) nogil
  10. double log(double) nogil
  11. double exp(double) nogil
  12. double sqrt(double) nogil
  13. double fabs(double) nogil
  14. int abs(int) nogil
  15. double floor(double) nogil
  16. double powf(double, double) nogil
  17. # External definitions from openmp headers
  18. cimport openmp
  19. cdef import from "omp.h":
  20. void omp_set_num_threads(int num_threads)
  21. ctypedef struct omp_lock_t:
  22. pass
  23. # External definitions from numpy headers
  24. cdef extern from "numpy/arrayobject.h":
  25. ctypedef int npy_intp
  26. ctypedef int intp
  27. ctypedef extern class numpy.ndarray [object PyArrayObject]:
  28. cdef char *data
  29. cdef int nd
  30. cdef intp *dimensions
  31. cdef intp *strides
  32. cdef int flags
  33. #~ void* PyArray_GetPtr(ndarray aobj, npy_intp* ind) nogil
  34. void* PyArray_GETPTR2(ndarray m, npy_intp i, npy_intp j) nogil
  35. void* PyArray_GETPTR4(ndarray m, npy_intp i, npy_intp j, npy_intp k, npy_intp l) nogil
  36. cdef double INFINITY = np.inf
  37. cdef double NEG_INFINITY = -np.inf
  38. cdef extern from "box_triangle_intersect.c":
  39. int triBoxOverlap(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float) nogil
  40. import time
  41. from random import random
  42. import logging
  43. from itertools import product
  44. import math
  45. _log = logging.getLogger()
  46. #
  47. cdef enum:
  48. UN_BLOCKED = 0
  49. BLOCKED = 1
  50. UNPASSABLE = 2
  51. AIR = 3
  52. # viterbi decoder pruning constants
  53. cdef enum:
  54. PRUNED = 1
  55. UNPRUNED = 0
  56. cdef class SortedXYZList:
  57. ''' skiplist like structure that ensures inserted elements are always sorted and that removes
  58. the smallest entries if capacity is exceeded
  59. http://igoro.com/archive/skip-lists-are-fascinating/
  60. http://code.activestate.com/recipes/576930-efficient-running-median-using-an-indexable-skipli/
  61. '''
  62. cdef public:
  63. double minimum
  64. char isfilled
  65. cdef:
  66. int maxlevels, capacity, insertion_count
  67. int *nodelinks
  68. double *nodevalues
  69. int *xyz
  70. int fill
  71. def __init__(self, int capacity):
  72. self.fill = 2 # start at position 2 as the head and the tail are allready in lists
  73. self.maxlevels = int(1 + log(capacity) / log(2))
  74. self.capacity = capacity + 2
  75. self.clear(True)
  76. @cython.cdivision(True)
  77. cdef void insert(SortedXYZList self, double value, int x, int y, int z) nogil:
  78. cdef int level, maxlevels, curr, next, new, smallest
  79. cdef int offset_curr, offset_smallest, offset_xyz
  80. maxlevels = self.maxlevels
  81. if not self.isfilled:
  82. # insert a new element
  83. new = self.fill
  84. self.fill += 1
  85. if self.fill == self.capacity:
  86. smallest = self.nodelinks[0] # the head node points to the smallest element
  87. offset_smallest = smallest * maxlevels
  88. # update the minimum to the value of the smallest element
  89. self.minimum = self.nodevalues[self.nodelinks[offset_smallest]]
  90. # check if curent value is even smaller
  91. if value < self.minimum:
  92. self.minimum = value
  93. self.isfilled = 1
  94. # update minimum
  95. #~ if value < self.minimum:
  96. #~ self.minimum = value
  97. else:
  98. if value <= self.minimum:
  99. # nothing to do - we will not insert a element
  100. # that is too small
  101. return
  102. # replace the smallest element
  103. smallest = self.nodelinks[0] # the head node points to the smallest element
  104. offset_smallest = smallest * maxlevels
  105. # update the minimum to the value of the second-smallest element
  106. self.minimum = self.nodevalues[self.nodelinks[offset_smallest]]
  107. if value < self.minimum:
  108. # the new incoming value is still smaller than the *currently* second smallest
  109. self.minimum = value
  110. # now update all next-links on head node to the outgoing links of the "node to be removed = the smallest"
  111. for level in range(maxlevels):
  112. next_on_level = self.nodelinks[offset_smallest + level]
  113. if next_on_level > 0: # will be 0 if the "historical" level_for_insert is reached
  114. self.nodelinks[level] = next_on_level
  115. # clear old entries!
  116. self.nodelinks[offset_smallest + level] = 0
  117. else:
  118. break
  119. # the new node will get the position of the smallest node (in the array)
  120. new = smallest
  121. # With a probability of 1/2, make the node a part of the lowest-level list only.
  122. # With 1/4 probability, the node will be a part of the lowest two lists.
  123. # With 1/8 probability, the node will be a part of three lists. And so forth.
  124. cdef int level_for_insert, i
  125. #~ level_for_insert = min(self.maxlevels, 1 - int(log(random()) / log(2)))
  126. for i in range(self.maxlevels - 1, -1, -1):
  127. if self.insertion_count % (1 << i) == 0:
  128. level_for_insert = i + 1
  129. break
  130. self.insertion_count += 1
  131. curr = 0 # the head node
  132. self.nodevalues[new] = value
  133. # store xyz values
  134. offset_xyz = new*3
  135. self.xyz[offset_xyz] = x
  136. self.xyz[offset_xyz + 1] = y
  137. self.xyz[offset_xyz + 2] = z
  138. for level in range(self.maxlevels - 1, -1, -1):
  139. offset_curr = curr * maxlevels + level
  140. next = self.nodelinks[offset_curr]
  141. while value > self.nodevalues[next]:
  142. curr = next
  143. offset_curr = curr * maxlevels + level
  144. next = self.nodelinks[offset_curr]
  145. if level < level_for_insert:
  146. self.nodelinks[new * maxlevels + level] = self.nodelinks[offset_curr]
  147. self.nodelinks[offset_curr] = new
  148. def getall(self):
  149. ''' debug function'''
  150. cdef int curr = 0, next, offset_curr = curr * self.maxlevels
  151. next = self.nodelinks[offset_curr]
  152. while self.nodevalues[next] < INFINITY:
  153. v = self.nodevalues[self.nodelinks[curr * self.maxlevels]]
  154. curr = next
  155. print v, curr, self.nodelinks[curr * self.maxlevels]
  156. next = self.nodelinks[curr * self.maxlevels]
  157. @cython.boundscheck(False)
  158. def xyzvAsArray(self):
  159. '''transform stored list to ascending sorted np.array'''
  160. cdef np.ndarray[np.double_t, ndim=2] result = np.zeros((self.fill - 2, 4), dtype=np.double)
  161. cdef int i, offset
  162. cdef int curr = 0, next, offset_curr = curr * self.maxlevels
  163. next = self.nodelinks[offset_curr]
  164. i = 0
  165. while self.nodevalues[next] < INFINITY:
  166. offset = self.nodelinks[curr * self.maxlevels] * 3
  167. result[i, 0] = self.xyz[offset]
  168. result[i, 1] = self.xyz[offset+1]
  169. result[i, 2] = self.xyz[offset+2]
  170. result[i, 3] = self.nodevalues[self.nodelinks[curr * self.maxlevels]]
  171. curr = next
  172. next = self.nodelinks[curr * self.maxlevels]
  173. i += 1
  174. return result
  175. @cython.boundscheck(False)
  176. def particleDataAsArray(self):
  177. '''transform stored list to ascending sorted np.array for ParticleFilter'''
  178. cdef np.ndarray[np.double_t, ndim=2] result = np.zeros((4, self.fill - 2), dtype=np.double)
  179. cdef int i, offset, sum_x = 0, sum_y = 0, sum_z = 0
  180. cdef int curr = 0, next, offset_curr = curr * self.maxlevels
  181. cdef double w, sum_w = 0
  182. next = self.nodelinks[offset_curr]
  183. i = 0
  184. while self.nodevalues[next] < INFINITY:
  185. offset = self.nodelinks[curr * self.maxlevels] * 3
  186. result[0, i] = self.xyz[offset]
  187. result[1, i] = self.xyz[offset+1]
  188. result[2, i] = self.xyz[offset+2]
  189. sum_x += self.xyz[offset]
  190. sum_y += self.xyz[offset+1]
  191. sum_z += self.xyz[offset+2]
  192. w = self.nodevalues[self.nodelinks[curr * self.maxlevels]]
  193. sum_w += w
  194. result[3, i] = w
  195. curr = next
  196. next = self.nodelinks[curr * self.maxlevels]
  197. i += 1
  198. return result, sum_w, sum_x, sum_y, sum_z
  199. @cython.boundscheck(False)
  200. cdef int updatePruningArray(SortedXYZList self, np.ndarray[np.int8_t, ndim=3] pruned,
  201. int t_shape_x, int t_shape_y, int t_shape_z, int s_shape_x, int s_shape_y, int s_shape_z,
  202. int offset_x, int offset_y, int offset_z):
  203. ''' this should be a method of the ViterbiDecoder but have no clue how to get
  204. access to self.xyz'''
  205. cdef int i, offset, sx, sy, sz, tx, ty, tz
  206. cdef int prev_idx_x, prev_idx_y, prev_idx_z
  207. # skip first 2 entries (head/tail)
  208. for i in prange(2, self.fill, nogil=True):
  209. offset = i*3
  210. sx = self.xyz[offset]
  211. sy = self.xyz[offset+1]
  212. sz = self.xyz[offset+2]
  213. # now unprune environment
  214. for tx in range(t_shape_x):
  215. prev_idx_x = sx + tx - offset_x
  216. if not 0 <= prev_idx_x < s_shape_x:
  217. continue
  218. for ty in range(t_shape_y):
  219. prev_idx_y = sy + ty - offset_y
  220. if not 0 <= prev_idx_y < s_shape_y:
  221. continue
  222. for tz in range(t_shape_z):
  223. prev_idx_z = sz + tz - offset_z
  224. if not 0 <= prev_idx_z < s_shape_z:
  225. continue
  226. # do not overwrite other PRUNED marker
  227. #~ if pruned[prev_idx_x, prev_idx_y, prev_idx_z] == PRUNED:
  228. pruned[prev_idx_x, prev_idx_y, prev_idx_z] = UNPRUNED
  229. return i
  230. cdef clear(SortedXYZList self, realloc=False):
  231. cdef int i
  232. if realloc:
  233. self.nodelinks = <int*>calloc(self.capacity * self.maxlevels, sizeof(int))
  234. self.nodevalues = <double*>calloc(self.capacity, sizeof(double))
  235. self.xyz = <int*>calloc(self.capacity * 3, sizeof(int))
  236. else:
  237. # only set links to 0
  238. for i in range(self.capacity * self.maxlevels):
  239. self.nodelinks[i] = 0
  240. # start at position 2 as the head and the tail are allready in lists
  241. self.fill = 2
  242. self.isfilled = 0
  243. # initialize head node
  244. for i in range(self.maxlevels):
  245. self.nodelinks[0 + i] = 1
  246. # initialize tail node
  247. self.nodevalues[1] = INFINITY
  248. self.insertion_count = 1 # used for generating probabilities
  249. # will be set automatically to valid values if initial loading happens
  250. self.minimum = NEG_INFINITY
  251. def __dealloc__(SortedXYZList self):
  252. free(self.nodelinks)
  253. free(self.nodevalues)
  254. @cython.boundscheck(False)
  255. cdef inline double emission_all(int numaps, double* mus, double* xs, double no_signal_delta) nogil:
  256. cdef double emission_cost = 0.0, mu
  257. cdef int j
  258. for j in range(numaps):
  259. mu = mus[j]
  260. #~ sigma = eprobs[j*2+1]
  261. if xs[j] == 2:
  262. continue
  263. elif xs[j] == 1: # no measurement
  264. if mu > -100:
  265. emission_cost = emission_cost + no_signal_delta
  266. continue
  267. emission_cost = emission_cost + fabs(mu - xs[j])
  268. return emission_cost
  269. @cython.boundscheck(False)
  270. cdef inline double emission_euclid_all(int numaps, double* mus, double* xs, double no_signal_delta) nogil:
  271. cdef double emission_cost = 0.0, mu, cost = 0.0
  272. cdef int j
  273. for j in range(numaps):
  274. mu = mus[j]
  275. if xs[j] == 2:
  276. continue
  277. elif xs[j] == 1: # no measurement
  278. if mu > -100:
  279. emission_cost = emission_cost + no_signal_delta * no_signal_delta
  280. continue
  281. cost = mu - xs[j]
  282. emission_cost = emission_cost + cost * cost
  283. return sqrt(emission_cost)
  284. @cython.boundscheck(False)
  285. cdef inline double emission_top3_mu(int numaps, double* mus, double* xs) nogil:
  286. cdef double emission_cost = 0.0, mu
  287. cdef int j
  288. cdef double top1_e, top2_e, top3_e
  289. cdef double top1_mu, top2_mu, top3_mu
  290. top1_mu = top2_mu = top3_mu = -1000
  291. for j in range(numaps):
  292. mu = mus[j]
  293. #~ sigma = eprobs[j*2+1]
  294. if xs[j] == 2:
  295. continue
  296. elif xs[j] == 1: # no measurement
  297. if mu > -100:
  298. emission_cost = emission_cost + 4
  299. continue
  300. emission_cost = fabs(mu - xs[j])
  301. if mu > top1_mu:
  302. top3_mu = top2_mu
  303. top2_mu = top1_mu
  304. top1_mu = mu
  305. top3_e = top2_e
  306. top2_e = top1_e
  307. top1_e = emission_cost
  308. elif mu > top2_mu:
  309. top3_mu = top2_mu
  310. top2_mu = mu
  311. top3_e = top2_e
  312. top2_e = emission_cost
  313. elif mu > top3_mu:
  314. top3_mu = mu
  315. top3_e = emission_cost
  316. emission_cost = top1_e + top2_e + top3_e
  317. return emission_cost
  318. @cython.boundscheck(False)
  319. cdef inline double emission_top3_deltas(int numaps, double* mus, double* xs) nogil:
  320. ''' use top3 costly deltas '''
  321. cdef int j
  322. cdef double top1_e = 0, top2_e = 0, top3_e = 0
  323. for j in range(numaps):
  324. if xs[j] > 0: # no measurement (1) or globally unseen ap (2)
  325. continue
  326. emission_cost = fabs(mus[j] - xs[j])
  327. if emission_cost > top1_e:
  328. top3_e = top2_e
  329. top2_e = top1_e
  330. top1_e = emission_cost
  331. elif emission_cost > top2_e:
  332. top3_e = top2_e
  333. top2_e = emission_cost
  334. elif emission_cost > top3_e:
  335. top3_e = emission_cost
  336. #~ return sqrt(top1_e * top1_e + top2_e * top2_e + top3_e * top3_e)
  337. return top1_e + top2_e + top3_e
  338. @cython.boundscheck(False)
  339. cdef inline double emission_euclid_top3_deltas(int numaps, double* mus, double* xs) nogil:
  340. ''' use top3 costly deltas '''
  341. cdef int j
  342. cdef double top1_e = 0, top2_e = 0, top3_e = 0
  343. for j in range(numaps):
  344. if xs[j] > 0: # no measurement (1) or globally unseen ap (2)
  345. continue
  346. emission_cost = fabs(mus[j] - xs[j])
  347. if emission_cost > top1_e:
  348. top3_e = top2_e
  349. top2_e = top1_e
  350. top1_e = emission_cost
  351. elif emission_cost > top2_e:
  352. top3_e = top2_e
  353. top2_e = emission_cost
  354. elif emission_cost > top3_e:
  355. top3_e = emission_cost
  356. return sqrt(top1_e * top1_e + top2_e * top2_e + top3_e * top3_e)
  357. cdef class ViterbiDecoder:
  358. cdef public verbose, store_pruning
  359. cdef public list estimated_paths
  360. cdef public list history
  361. cdef public double no_signal_delta
  362. cdef:
  363. int s_shape_x, s_shape_y, s_shape_z
  364. int t_shape_x, t_shape_y, t_shape_z
  365. int offset_x, offset_y, offset_z
  366. long numstates
  367. int len_measurements
  368. int emissionCostMode
  369. SortedXYZList pl
  370. np.ndarray blockedCubes
  371. np.ndarray emission_probs
  372. np.ndarray transition_probs
  373. np.ndarray last_probs
  374. def __init__(self, np.ndarray[np.int_t, ndim=3] blockedCubes, np.ndarray[np.double_t, ndim=5] emission_probs,
  375. np.ndarray[np.double_t, ndim=6] transition_probs, verbose=True, store_pruning=False, no_signal_delta=10):
  376. self.verbose = verbose
  377. self.blockedCubes = blockedCubes
  378. self.emission_probs = emission_probs
  379. self.transition_probs = transition_probs
  380. self.s_shape_x = emission_probs.shape[0]
  381. self.s_shape_y = emission_probs.shape[1]
  382. self.s_shape_z = emission_probs.shape[2]
  383. self.t_shape_x = transition_probs.shape[3]
  384. self.t_shape_y = transition_probs.shape[4]
  385. self.t_shape_z = transition_probs.shape[5]
  386. self.estimated_paths = []
  387. self.store_pruning = store_pruning
  388. self.history = []
  389. self.no_signal_delta = no_signal_delta
  390. #~ self.emissionCostMode = 1 # manhattan top 3
  391. self.emissionCostMode = 3 # euclid all
  392. #~ self.emissionCostMode = 4 # euclid top 3
  393. #cdef np.ndarray[np.double_t, ndim=3]
  394. self.last_probs = np.empty((self.s_shape_x, self.s_shape_y, self.s_shape_z), dtype=np.double)
  395. @cython.boundscheck(False)
  396. def getUnblockedIndices(self):
  397. cdef np.ndarray[np.int_t, ndim=3] blockedCubes = self.blockedCubes
  398. cdef np.ndarray[np.int_t, ndim=2] indices = np.zeros((self.s_shape_x * self.s_shape_y * self.s_shape_z, 3), dtype=np.int)
  399. cdef int i, sx, sy, sz
  400. i = 0
  401. for sx in range(self.s_shape_x):
  402. for sy in range(self.s_shape_y):
  403. for sz in range(self.s_shape_z):
  404. if blockedCubes[sx, sy, sz] == UN_BLOCKED:
  405. indices[i, 0] = sx
  406. indices[i, 1] = sy
  407. indices[i, 2] = sz
  408. i = i + 1
  409. indices = np.resize(indices, (i, 3))
  410. return indices
  411. cdef inline double _getEmissionCost(ViterbiDecoder self, int numaps, double* mus, double* xs) nogil:
  412. ''' calc emission cost for vector of rss values and vector of mus'''
  413. if self.emissionCostMode == 0:
  414. return emission_all(numaps, mus, xs, self.no_signal_delta)
  415. elif self.emissionCostMode == 1:
  416. return emission_top3_deltas(numaps, mus, xs)
  417. elif self.emissionCostMode == 2:
  418. return emission_top3_mu(numaps, mus, xs)
  419. elif self.emissionCostMode == 3:
  420. return emission_euclid_all(numaps, mus, xs, self.no_signal_delta)
  421. elif self.emissionCostMode == 4:
  422. return emission_euclid_top3_deltas(numaps, mus, xs)
  423. def getEmissionCost(self, np.ndarray[np.double_t, ndim=1] mus, np.ndarray[np.double_t, ndim=1] xs):
  424. ''' pure python access to emission costs'''
  425. res = self._getEmissionCost(len(mus), <np.double_t*>mus.data, <np.double_t*>xs.data)
  426. return res
  427. @cython.boundscheck(False)
  428. @cython.cdivision(True)
  429. def decode_with_pruning(self, np.ndarray[np.double_t, ndim=2] measurements,
  430. np.ndarray[np.double_t, ndim=3] curr_probs,
  431. np.ndarray[np.uint8_t, ndim=4] back_track,
  432. prune_to, int continueDecoding):
  433. ''' only use the TOP-N hypothesis during search (given by prune_to)'''
  434. cdef np.ndarray[np.double_t, ndim=3] last_probs = self.last_probs
  435. cdef int s_shape_x=self.s_shape_x, s_shape_y=self.s_shape_y, s_shape_z=self.s_shape_z
  436. cdef int t_shape_x=self.t_shape_x, t_shape_y=self.t_shape_y, t_shape_z=self.t_shape_z
  437. cdef int offset_x=self.offset_x, offset_y=self.offset_y, offset_z=self.offset_z
  438. cdef double mu, sq_sigma, x, transition_cost, min_transition_cost, emission_cost, cost, prev_cost
  439. cdef int sx, sy, sz, tx, ty, tz, offset, shape_idx, best_prev_state=0, i, j, k, numaps=measurements.shape[1]
  440. cdef int loggging_at = max(1, self.len_measurements / 10)
  441. cdef int num_unpruned, num_emitted = 0
  442. cdef SortedXYZList pl = SortedXYZList(prune_to)
  443. cdef np.ndarray[np.double_t, ndim=2] xyz_a
  444. cdef double sum_x, sum_y, sum_z
  445. cdef omp_lock_t mylock
  446. openmp.omp_init_lock(&mylock) # initialize
  447. cdef np.ndarray[np.int8_t, ndim=3] pruned = np.zeros((s_shape_x, s_shape_y, s_shape_z), dtype=np.int8)
  448. cdef np.ndarray[np.int_t, ndim=3] blockedCubes = self.blockedCubes
  449. cdef np.ndarray[np.double_t, ndim=5] emission_probs = self.emission_probs
  450. cdef np.ndarray[np.double_t, ndim=6] transition_probs = self.transition_probs
  451. # start only with unblocked states
  452. cdef np.ndarray[np.int_t, ndim=2] indices = self.getUnblockedIndices()
  453. num_unpruned = len(indices)
  454. seq_result = []
  455. avg_seq_result = []
  456. sum_time2 = sum_time1 = 0
  457. t = time.time()
  458. for i in range(0, self.len_measurements):
  459. #~ t2 = time.time()
  460. if self.verbose and (i % loggging_at == 0 or i == 0 or i == self.len_measurements - 1):
  461. _log.debug('calc probs col %s of %s [%dk states/sec] [%s]' % (i, self.len_measurements, (self.numstates / 1000.0 * i) / (time.time() - t + 0.000001), num_unpruned))
  462. for k in prange(num_unpruned, nogil=True):
  463. #~ tid = threadid()
  464. sx = indices[k, 0]
  465. sy = indices[k, 1]
  466. sz = indices[k, 2]
  467. #~ emission_cost = self._getEmissionCost()
  468. emission_cost = self._getEmissionCost(numaps, <double*>PyArray_GETPTR4(<ndarray>emission_probs, sx, sy, sz, 0),
  469. <double*>PyArray_GETPTR2(<ndarray>measurements, i, 0))
  470. if i == 0 and continueDecoding == 0:
  471. # first column only emissions
  472. curr_probs[sx, sy, sz] = emission_cost
  473. if -emission_cost > pl.minimum:
  474. openmp.omp_set_lock(&mylock) # acquire
  475. pl.insert(-emission_cost, sx, sy, sz)
  476. openmp.omp_unset_lock(&mylock) # release
  477. continue
  478. min_transition_cost = INFINITY
  479. shape_idx = -1
  480. with gil:
  481. for tx in range(t_shape_x):
  482. prev_idx_x = sx + tx - offset_x
  483. if not 0 <= prev_idx_x < s_shape_x:
  484. shape_idx = shape_idx + t_shape_y * t_shape_z
  485. continue
  486. for ty in range(t_shape_y):
  487. prev_idx_y = sy + ty - offset_y
  488. if not 0 <= prev_idx_y < s_shape_y:
  489. shape_idx = shape_idx + t_shape_z
  490. continue
  491. for tz in range(t_shape_z):
  492. shape_idx = shape_idx + 1
  493. prev_idx_z = sz + tz - offset_z
  494. if not 0 <= prev_idx_z < s_shape_z:
  495. continue
  496. prev_cost = last_probs[prev_idx_x, prev_idx_y, prev_idx_z]
  497. transition_cost = transition_probs[sx, sy, sz, tx, ty, tz]
  498. if transition_cost == INFINITY:
  499. cost = INFINITY
  500. else:
  501. cost = prev_cost + transition_cost# * 0
  502. if cost < min_transition_cost:
  503. min_transition_cost = cost
  504. best_prev_state = shape_idx
  505. cost = min_transition_cost + emission_cost
  506. curr_probs[sx, sy, sz] = cost
  507. if i > 0: # continueDecoding == 1
  508. back_track[i, sx, sy, sz] = best_prev_state
  509. if -cost > pl.minimum:
  510. openmp.omp_set_lock(&mylock) # acquire
  511. pl.insert(-cost, sx, sy, sz)
  512. openmp.omp_unset_lock(&mylock) # release
  513. #~ sum_time1 += (time.time() - t2)
  514. #~ t2 = time.time()
  515. # toggle arrays
  516. last_probs, curr_probs = curr_probs, last_probs
  517. curr_probs.fill(INFINITY)
  518. pruned.fill(PRUNED)
  519. #~ if self.store_pruning:
  520. xyz_a = pl.xyzvAsArray()
  521. sum_x = sum_y = sum_z = 0
  522. for k in range(len(xyz_a)-50, len(xyz_a)):
  523. sum_x += xyz_a[k, 0]
  524. sum_y += xyz_a[k, 1]
  525. sum_z += xyz_a[k, 2]
  526. seq_result.append(tuple(xyz_a[-1][:3]))
  527. avg_seq_result.append((sum_x / 50.0, sum_y / 50.0, sum_z / 50.0))
  528. self.history.append(xyz_a)
  529. pl.updatePruningArray(pruned, t_shape_x, t_shape_y, t_shape_z,
  530. s_shape_x, s_shape_y, s_shape_z,
  531. offset_x, offset_y, offset_z)
  532. # not parallelizable
  533. num_unpruned = 0
  534. for sx in range(s_shape_x):
  535. for sy in range(s_shape_y):
  536. for sz in range(s_shape_z):
  537. if pruned[sx, sy, sz] != PRUNED:
  538. indices[num_unpruned, 0] = sx
  539. indices[num_unpruned, 1] = sy
  540. indices[num_unpruned, 2] = sz
  541. num_unpruned = num_unpruned + 1
  542. # maybe we get a speedup by reducing the memory that has to be hold in cpu cache
  543. if len(indices) > num_unpruned * 3:
  544. indices = np.resize(indices, (num_unpruned * 2, 3))
  545. pl.clear()
  546. #~ sum_time2 += (time.time() - t2)
  547. openmp.omp_destroy_lock(&mylock) # deallocate the lock
  548. self.last_probs[:] = last_probs
  549. #~ print 'phase1: %.3f phase2: %.3f' % (sum_time1, sum_time2)
  550. return seq_result, avg_seq_result
  551. @cython.boundscheck(False)
  552. @cython.cdivision(True)
  553. def decode_all(self, np.ndarray[np.double_t, ndim=2] measurements,
  554. np.ndarray[np.double_t, ndim=3] last_probs,
  555. np.ndarray[np.double_t, ndim=3] curr_probs,
  556. np.ndarray[np.uint8_t, ndim=4] back_track):
  557. ''' decode the complete searchspace without pruning
  558. (Out of Date? - only with pruning was used in the end in Dirks DA)
  559. '''
  560. cdef int s_shape_x=self.s_shape_x, s_shape_y=self.s_shape_y, s_shape_z=self.s_shape_z
  561. cdef int t_shape_x=self.t_shape_x, t_shape_y=self.t_shape_y, t_shape_z=self.t_shape_z
  562. cdef int offset_x=self.offset_x, offset_y=self.offset_y, offset_z=self.offset_z
  563. cdef double mu, sq_sigma, x, min_cost, min_transition_cost, emission_cost, cost, prev_cost
  564. cdef int sx, sy, sz, tx, ty, tz, len_indices, shape_idx, best_prev_state=0, i, j, k, numaps=measurements.shape[1]
  565. cdef int loggging_at = max(1, self.len_measurements / 10)
  566. cdef np.ndarray[np.double_t, ndim=5] emission_probs = self.emission_probs
  567. cdef np.ndarray[np.double_t, ndim=6] transition_probs = self.transition_probs
  568. #~ len_indices =
  569. cdef np.ndarray[np.int_t, ndim=2] indices = self.getUnblockedIndices()
  570. t = time.time()
  571. # xs -> emitted vector
  572. for i in range(0, self.len_measurements):
  573. if self.verbose and (i % loggging_at == 0 or i == 1 or i == self.len_measurements - 1):
  574. _log.debug('calc probs col %s of %s [%dk states/sec] [%s]' % (i, self.len_measurements, (self.numstates * i / 1000) / (time.time() - t + 0.000001), indices.shape[0]))
  575. for k in prange(indices.shape[0], nogil=True):
  576. sx = indices[k, 0]
  577. sy = indices[k, 1]
  578. sz = indices[k, 2]
  579. # calc emission prob for vector with rss values
  580. emission_cost = 0.0
  581. for j in range(numaps):
  582. mu = emission_probs[sx, sy, sz, 0, j]
  583. sq_sigma = emission_probs[sx, sy, sz, 1, j]
  584. x = measurements[i, j]
  585. if x == -1: # no measurement
  586. continue
  587. emission_cost = emission_cost + fabs(mu - x)
  588. if i == 0:
  589. # first column only emissions
  590. curr_probs[sx, sy, sz] = emission_cost
  591. continue
  592. min_transition_cost = INFINITY
  593. shape_idx = -1
  594. with gil:
  595. for tx in range(t_shape_x):
  596. prev_idx_x = sx + tx - offset_x
  597. if not 0 <= prev_idx_x < s_shape_x:
  598. shape_idx = shape_idx + t_shape_y * t_shape_z
  599. continue
  600. for ty in range(t_shape_y):
  601. prev_idx_y = sy + ty - offset_y
  602. if not 0 <= prev_idx_y < s_shape_y:
  603. shape_idx = shape_idx + t_shape_z
  604. continue
  605. for tz in range(t_shape_z):
  606. shape_idx = shape_idx + 1
  607. prev_idx_z = sz + tz - offset_z
  608. if not 0 <= prev_idx_z < s_shape_z:
  609. continue
  610. #~ prev_prob = all_probs[i-1, prev_idx_x, prev_idx_y, prev_idx_z]
  611. prev_cost = last_probs[prev_idx_x, prev_idx_y, prev_idx_z]
  612. cost = prev_cost + transition_probs[sx, sy, sz, tx, ty, tz]
  613. if cost < min_transition_cost:
  614. min_transition_cost = cost
  615. best_prev_state = shape_idx
  616. curr_probs[sx, sy, sz] = min_transition_cost + emission_cost
  617. back_track[i, sx, sy, sz] = best_prev_state
  618. last_probs, curr_probs = curr_probs, last_probs
  619. return last_probs
  620. def decode(self, np.ndarray[np.double_t, ndim=2] measurements, int prune_to=0, int num_threads=0, full=False, continueDecoding=False):
  621. self.history[:] = []
  622. cdef int s_shape_x=self.s_shape_x, s_shape_y=self.s_shape_y, s_shape_z=self.s_shape_z
  623. cdef int t_shape_x=self.t_shape_x, t_shape_y=self.t_shape_y, t_shape_z=self.t_shape_z
  624. # we have to locate the (previous) state referenced by the transition index
  625. # if the transition_shape is (5, 5, 3) then (tx=2, ty2, tz=1) then previous state is the current state
  626. cdef int offset_x, offset_y, offset_z
  627. self.offset_x = t_shape_x / 2
  628. self.offset_y = t_shape_y / 2
  629. self.offset_z = t_shape_z / 2
  630. # last column in dynamic programming matrix
  631. # curr column in dynamic programming matrix
  632. cdef np.ndarray[np.double_t, ndim=3] curr_probs = np.empty((s_shape_x, s_shape_y, s_shape_z), dtype=np.double)
  633. if not continueDecoding:
  634. self.last_probs.fill(INFINITY)
  635. # TODO: rename curr_probs to curr_costs
  636. curr_probs.fill(INFINITY)
  637. # backtracking pointers to find best path through dynamic programming matrix
  638. # we store the only the index of transition shape
  639. assert t_shape_x * t_shape_y * t_shape_z < 256, 'you have to increase the backpointer array from uint8 to uint16'
  640. cdef np.ndarray[np.uint8_t, ndim=4] back_track = np.zeros((len(measurements), s_shape_x, s_shape_y, s_shape_z), dtype=np.uint8)
  641. if self.verbose:
  642. _log.info('using %.3f GB Memory for backpointer array' % (back_track.size / 1024.0**3))
  643. self.numstates = s_shape_x * s_shape_y * s_shape_z
  644. self.len_measurements = len(measurements)
  645. if self.verbose:
  646. _log.debug('%sk states per col, total: %.1f mio states' % (self.numstates / 1000, self.numstates / 10.0**6 * self.len_measurements))
  647. omp_set_num_threads(num_threads)
  648. try:
  649. if prune_to == 0:
  650. #~ last_probs = self.decode_all(measurements, last_probs, curr_probs, back_track)
  651. seq_res, avg_seq_res = [], []
  652. else:
  653. seq_res, avg_seq_res = self.decode_with_pruning(measurements, curr_probs, back_track, prune_to, continueDecoding)
  654. finally:
  655. omp_set_num_threads(0)
  656. # find starting point of best backtracking path
  657. cdef int i, j, best_last_state_x = 0, best_last_state_y = 0, best_last_state_z = 0
  658. cdef double min_cost = INFINITY, cost
  659. cdef SortedXYZList best_estimates
  660. if full:
  661. best_estimates = SortedXYZList(s_shape_x * s_shape_y * s_shape_z)
  662. for sx in range(s_shape_x):
  663. for sy in range(s_shape_y):
  664. for sz in range(s_shape_z):
  665. cost = self.last_probs[sx, sy, sz]
  666. if full:
  667. best_estimates.insert(-cost, sx, sy, sz)
  668. else:
  669. if cost < min_cost:
  670. best_last_state_x, best_last_state_y, best_last_state_z = sx, sy, sz
  671. min_cost = cost
  672. if full:
  673. a = best_estimates.xyzvAsArray()
  674. #~ np.savetxt('r:/out.txt', a, fmt=('%d', '%d', '%d', '%.1f'))
  675. self.estimated_paths[:] = []
  676. # follow backtracking links from best path
  677. for i in range(-1, - (prune_to if prune_to > 0 else len(a)), -1):
  678. estimated_path = []
  679. curr_state = a[i, 0], a[i, 1], a[i, 2]
  680. curr_prob = min_cost
  681. for j in range(self.len_measurements-1, -1, -1):
  682. estimated_path.append((curr_state, 0))
  683. if j > -1:
  684. sx, sy, sz = curr_state[0], curr_state[1], curr_state[2]
  685. shape_idx = back_track[j, sx, sy, sz]
  686. tx = shape_idx / (t_shape_y * t_shape_z)
  687. ty = (shape_idx / t_shape_z) % t_shape_y
  688. tz = shape_idx % t_shape_z
  689. curr_state = sx + tx - self.offset_x, sy + ty - self.offset_y, sz + tz - self.offset_z
  690. self.estimated_paths.append(list(reversed(estimated_path)))
  691. estimated_path = [e[0] for e in self.estimated_paths[0]]
  692. else:
  693. if self.verbose:
  694. _log.debug('best last state: (%s, %s, %s) with cost %s' % (best_last_state_x, best_last_state_y, best_last_state_z, min_cost))
  695. # follow backtracking links from best path
  696. estimated_path = []
  697. curr_state = best_last_state_x, best_last_state_y, best_last_state_z
  698. curr_prob = min_cost
  699. for j in range(self.len_measurements-1, -1, -1):
  700. estimated_path.append(curr_state)
  701. if j > -1:
  702. sx, sy, sz = curr_state[0], curr_state[1], curr_state[2]
  703. shape_idx = back_track[j, sx, sy, sz]
  704. tx = shape_idx / (t_shape_y * t_shape_z)
  705. ty = (shape_idx / t_shape_z) % t_shape_y
  706. tz = shape_idx % t_shape_z
  707. curr_state = sx + tx - self.offset_x, sy + ty - self.offset_y, sz + tz - self.offset_z
  708. estimated_path = list(reversed(estimated_path))
  709. return estimated_path, seq_res, avg_seq_res
  710. cdef class LMSE:
  711. cdef public int verbose
  712. cdef public int with_history
  713. cdef public list history
  714. cdef:
  715. int s_shape_x, s_shape_y, s_shape_z
  716. np.ndarray emission_probs
  717. def __init__(self, np.ndarray[np.double_t, ndim=5] emission_probs, verbose=True, with_history=False):
  718. self.emission_probs = emission_probs
  719. self.s_shape_x = emission_probs.shape[0]
  720. self.s_shape_y = emission_probs.shape[1]
  721. self.s_shape_z = emission_probs.shape[2]
  722. self.verbose = verbose
  723. self.with_history = with_history
  724. self.history = []
  725. @cython.boundscheck(False)
  726. @cython.cdivision(True)
  727. def decode(self, np.ndarray[np.double_t, ndim=2] measurements):
  728. t = time.time()
  729. cdef int s_shape_x=self.s_shape_x, s_shape_y=self.s_shape_y, s_shape_z=self.s_shape_z
  730. cdef np.ndarray[np.double_t, ndim=5] emission_probs = self.emission_probs
  731. cdef int numaps = len(measurements[0])
  732. # we dont track XYZ but only the particle index on X
  733. cdef SortedXYZList top_mse = SortedXYZList(1000)
  734. #~ cdef np.ndarray[np.double_t, ndim=2] top_mse_a
  735. cdef int sx, sy, sz
  736. cdef int i, j
  737. cdef double d, sum_d, sqrt_d, min_d, x
  738. cdef int best_x, best_y, best_z
  739. seq_res = []
  740. for j in range(len(measurements)):
  741. with nogil:
  742. min_d = INFINITY
  743. for sx in range(s_shape_x):
  744. for sy in range(s_shape_y):
  745. for sz in range(s_shape_z):
  746. sum_d = 0
  747. for i in range(numaps):
  748. x = measurements[j, i]
  749. if x > 0: # either 1, 2
  750. continue
  751. d = emission_probs[sx, sy, sz, 0, i] - x
  752. sum_d = sum_d + d * d
  753. # sqrt does not change maximum
  754. #~ sqrt_d = sqrt(sum_d)
  755. sqrt_d = sum_d
  756. if sqrt_d < min_d:
  757. min_d = sqrt_d
  758. best_x = sx; best_y = sy; best_z = sz
  759. if self.with_history and -sqrt_d > top_mse.minimum:
  760. #~ openmp.omp_set_lock(&mylock) # acquire
  761. top_mse.insert(-sqrt_d, sx, sy, sz)
  762. #~ openmp.omp_unset_lock(&mylock) # release
  763. seq_res.append((best_x, best_y, best_z))
  764. if self.with_history:
  765. self.history.append(top_mse.xyzvAsArray())
  766. top_mse.clear()
  767. return seq_res
  768. cdef inline long lround(double d) nogil:
  769. return <long>floor(d + 0.5)
  770. cdef class ParticleFilter:
  771. cdef public int verbose
  772. cdef public int with_history
  773. cdef public list history
  774. cdef:
  775. int s_shape_x, s_shape_y, s_shape_z
  776. np.ndarray blockedCubes
  777. np.ndarray emission_probs
  778. np.ndarray sampling_pool
  779. def __init__(self, np.ndarray[np.int_t, ndim=3] blockedCubes, np.ndarray[np.double_t, ndim=5] emission_probs,
  780. np.ndarray[np.double_t, ndim=2] sampling_pool, verbose=True, with_history=False,
  781. ):
  782. self.blockedCubes = blockedCubes
  783. self.emission_probs = emission_probs
  784. self.sampling_pool = sampling_pool
  785. self.s_shape_x = emission_probs.shape[0]
  786. self.s_shape_y = emission_probs.shape[1]
  787. self.s_shape_z = emission_probs.shape[2]
  788. self.verbose = verbose
  789. self.with_history = with_history
  790. self.history = []
  791. @cython.boundscheck(False)
  792. @cython.cdivision(True)
  793. def decode(self, np.ndarray[np.double_t, ndim=2] measurements, int num_particles,
  794. int do_blocking=1, int over_sample_limit=50, int average_over_particles=0,
  795. double smooth=1.0, double replace_below=1e-10, int max_replace=100, double sigma=3.0, double turnoff_blocking=1e3):
  796. t = time.time()
  797. cdef int s_shape_x=self.s_shape_x, s_shape_y=self.s_shape_y, s_shape_z=self.s_shape_z
  798. cdef np.ndarray[np.double_t, ndim=5] emission_probs = self.emission_probs
  799. cdef np.ndarray[np.int_t, ndim=3] blockedCubes = self.blockedCubes
  800. seq_res = []
  801. if average_over_particles > 0:
  802. seq_avg_res = []
  803. else:
  804. seq_avg_res = None
  805. cdef int numaps = len(measurements[0])
  806. cdef int i, j, k, ii
  807. #~ cdef np.ndarray[np.double_t, ndim=1] sigmas = np.empty((numaps, ), dtype=np.double)
  808. #~ sigmas.fill(9)
  809. cdef int with_history = self.with_history
  810. cdef SortedXYZList sorted_weights = SortedXYZList(num_particles)
  811. self.history[:] = []
  812. # we dont track XYZ but only the particle index on X
  813. cdef SortedXYZList top_particles = SortedXYZList(average_over_particles)
  814. cdef np.ndarray[np.double_t, ndim=2] top_particles_a
  815. cdef np.ndarray[np.int_t, ndim=3] local_block_map = np.zeros((s_shape_x, s_shape_y, s_shape_z), dtype=np.int)
  816. cdef np.ndarray[np.uint32_t, ndim=2] back_track_links = np.zeros((len(measurements), num_particles), dtype=np.uint32)
  817. cdef np.ndarray[np.uint32_t, ndim=2] back_track_positions = np.zeros((len(measurements), num_particles), dtype=np.uint32)
  818. cdef int OVER_ALLOCATE = num_particles * 2 # if more than half the scene is freespace (UN_BLOCKED), this should be enough
  819. cdef np.ndarray[np.int_t, ndim=2] particles, new_particles, random_particle_pool
  820. random_particle_pool = np.dstack(np.random.randint(0, size, OVER_ALLOCATE)
  821. for size in (s_shape_x, s_shape_y, s_shape_z))[0]
  822. cdef int random_particle_pool_idx = 0, num_replaced = 0
  823. particles = random_particle_pool.copy()
  824. new_particles = np.zeros((num_particles, 3), dtype=np.int)
  825. j = 0
  826. for i in range(OVER_ALLOCATE):
  827. if blockedCubes[random_particle_pool[i, 0], random_particle_pool[i, 1], random_particle_pool[i, 2]] != UN_BLOCKED:
  828. continue
  829. particles[j, 0] = random_particle_pool[i, 0]
  830. particles[j, 1] = random_particle_pool[i, 1]
  831. particles[j, 2] = random_particle_pool[i, 2]
  832. j += 1
  833. if j == num_particles:
  834. break
  835. cdef np.ndarray[np.double_t, ndim=1] weights = np.zeros((num_particles, ), dtype=np.double)
  836. cdef np.ndarray[np.double_t, ndim=2] sampling_pool = self.sampling_pool
  837. cdef int pool_size = len(sampling_pool), curr_pool_idx = 0, sampling_pool_idx = 0, over_sample_limit_reached = 0
  838. cdef int total_spawned=0, idx, num_spawned, num_spawn_particles
  839. cdef int px, py, pz, best_idx, best_px, best_py, best_pz, new_px, new_py, new_pz
  840. cdef int blocked_path, p_back_track_idx, curr_x_i, curr_y_i, curr_z_i, dxi, dyi, dzi
  841. cdef double sum_w_new, w_new, mu, sq_sigma, x, dx, dy, dz, w
  842. cdef double step_x, step_y, step_z, curr_x, curr_y, curr_z, distance
  843. cdef double gauss_C1 = sqrt(2 * math.pi * sigma**2)
  844. cdef double gauss_C2 = -(2 * sigma**2)
  845. for j in range(len(measurements)):
  846. if self.verbose and (j % 10 == 0 or j == len(measurements) - 1):
  847. _log.debug('m: %s of %s' % (j, len(measurements)))
  848. with nogil:
  849. w_max = NEG_INFINITY
  850. sum_w_new = 0
  851. #~ idx = random_particle_pool_idx
  852. num_replaced = 0
  853. for k in range(num_particles):
  854. px = particles[k, 0]
  855. py = particles[k, 1]
  856. pz = particles[k, 2]
  857. if px == -1:
  858. continue
  859. w_new = 1
  860. for i in range(numaps):
  861. x = measurements[j, i]
  862. if x > 0: # either 1, 2
  863. continue
  864. mu = emission_probs[px, py, pz, 0, i]
  865. w_new = w_new * gauss_C1 * exp((x - mu) * (x - mu) / gauss_C2)
  866. if w_new == 1:
  867. # mo measurements at this position
  868. w_new = 0 # hmpf, ugly
  869. if w_new < replace_below and num_replaced < max_replace:
  870. # replace low prob sample with with random from pool
  871. # this will prevent "starving" since new random particels
  872. # are permanently fed into the system
  873. i = random_particle_pool_idx % OVER_ALLOCATE
  874. random_particle_pool_idx += 1
  875. num_replaced += 1
  876. px = particles[k, 0] = random_particle_pool[i, 0]
  877. py = particles[k, 1] = random_particle_pool[i, 1]
  878. pz = particles[k, 2] = random_particle_pool[i, 2]
  879. w_new = 1
  880. for i in range(numaps):
  881. x = measurements[j, i]
  882. if x > 0: # either 1, 2
  883. continue
  884. mu = emission_probs[px, py, pz, 0, i]
  885. w_new = w_new * gauss_C1 * exp((x - mu) * (x - mu) / gauss_C2)
  886. if w_new == 1:
  887. w_new = 0 # hmpf, ugly
  888. #XXX: how can we formalize this sqrt
  889. weights[k] = powf(w_new, smooth)
  890. #~ weights[k] = w_new
  891. sum_w_new = sum_w_new + weights[k]
  892. if average_over_particles > 0:
  893. top_particles.insert(w_new, px, py, pz)
  894. if with_history:
  895. sorted_weights.insert(w_new, px, py, pz)
  896. if w_new > w_max:
  897. w_max = w_new
  898. best_px = px
  899. best_py = py
  900. best_pz = pz
  901. best_idx = k
  902. #~ print random_particle_pool_idx -idx
  903. #~ print sum_w_new
  904. #~ w_max = 10**9
  905. #~ sum_w_new = 0
  906. #~ for k in range(num_particles):
  907. #~ px = particles[k, 0]
  908. #~ py = particles[k, 1]
  909. #~ pz = particles[k, 2]
  910. #~ if px == -1:
  911. #~ continue
  912. #~ w_new = 0
  913. #~ for i in range(numaps):
  914. #~ x = measurements[j, i]
  915. #~ if x == 2:
  916. #~ continue
  917. #~ elif x == 1: # no measurement
  918. #~ #if mu > -100:
  919. #~ #w_new = w_new + 4 * 4
  920. #~ continue
  921. #~ mu = emission_probs[px, py, pz, 0, i]
  922. #~ w_new = w_new + (x - mu) * (x - mu)
  923. #~ w_new = sqrt(w_new)
  924. #~ if w_new == 0:
  925. #~ w_new = INFINITY
  926. #~ weights[k] = 1.0 / w_new
  927. #~ sum_w_new = sum_w_new + weights[k]
  928. #~ if average_over_particles > 0:
  929. #~ top_particles.insert(-w_new, px, py, pz)
  930. #~ if with_history:
  931. #~ sorted_weights.insert(-w_new, px, py, pz)
  932. #~ if w_new < w_max:
  933. #~ w_max = w_new
  934. #~ best_px = px
  935. #~ best_py = py
  936. #~ best_pz = pz
  937. #~ best_idx = k
  938. #~ print w_max
  939. # renormalize
  940. for k in range(num_particles):
  941. weights[k] = weights[k] / sum_w_new
  942. total_spawned = 0
  943. for k in range(num_particles):
  944. w = weights[k]
  945. px = particles[k, 0]
  946. py = particles[k, 1]
  947. pz = particles[k, 2]
  948. num_spawn_particles = lround(num_particles * w)
  949. # prevent overflow, due to rounding
  950. if total_spawned + num_spawn_particles > num_particles:
  951. num_spawn_particles = num_particles - total_spawned
  952. idx = total_spawned
  953. num_spawned = 0
  954. for i in range(num_spawn_particles * over_sample_limit): # limit retries
  955. if num_spawned == num_spawn_particles:
  956. break
  957. curr_pool_idx = sampling_pool_idx % pool_size
  958. dx = sampling_pool[curr_pool_idx, 0]
  959. dy = sampling_pool[curr_pool_idx, 1]
  960. dz = sampling_pool[curr_pool_idx, 2]
  961. sampling_pool_idx += 1
  962. dxi = lround(dx)
  963. dyi = lround(dy)
  964. dzi = lround(dz)
  965. new_px = px + dxi
  966. new_py = py + dyi
  967. new_pz = pz + dzi
  968. # check if we are still in the allowed space
  969. if not (0 <= new_px < s_shape_x and 0 <= new_py < s_shape_y and 0 <= new_pz < s_shape_z):
  970. continue # try again
  971. # check if if we know that the new_p cannot be reached
  972. if local_block_map[new_px, new_py, new_pz] == k:
  973. continue # try again
  974. # check if destination is blocked
  975. if blockedCubes[new_px, new_py, new_pz] != UN_BLOCKED:
  976. continue # try again
  977. if do_blocking == 1 and sum_w_new > turnoff_blocking:
  978. #~ print
  979. # scan space between p and new_p for BLOCKED cubes
  980. # and reject sample if True
  981. distance = sqrt(dxi * dxi + dyi * dyi + dzi * dzi) # euclidian
  982. if distance == 0:
  983. continue
  984. step_x = dxi / distance
  985. step_y = dyi / distance
  986. step_z = dzi / distance
  987. curr_x = px
  988. curr_y = py
  989. curr_z = pz
  990. curr_x_i = int(curr_x); curr_y_i = int(curr_y); curr_z_i = int(curr_z)
  991. blocked_path = 0
  992. for ii in range(<int>distance):
  993. #~ while not(curr_x_i == new_px or curr_y_i == new_py or curr_z_i == new_pz):
  994. curr_x = curr_x + step_x
  995. curr_y = curr_y + step_y
  996. curr_z = curr_z + step_z
  997. curr_x_i = int(curr_x); curr_y_i = int(curr_y); curr_z_i = int(curr_z)
  998. #~ print curr_x, curr_y, curr_z, ':', dx, dy, dz, ':', px, py, pz
  999. if 0 <= curr_x_i < s_shape_x and 0 <= curr_y_i < s_shape_y and 0 <= curr_z_i < s_shape_z:
  1000. if blockedCubes[curr_x_i, curr_y_i, curr_z_i] != UN_BLOCKED:
  1001. blocked_path = 1
  1002. #mark es blocked with current block indicator
  1003. local_block_map[curr_x_i, curr_y_i, curr_z_i] = k
  1004. break
  1005. if blocked_path == 1:
  1006. # mark all cubes after the blocked hit also with current block indicator
  1007. for ii in range(ii+1, <int>distance):
  1008. curr_x = curr_x + step_x
  1009. curr_y = curr_y + step_y
  1010. curr_z = curr_z + step_z
  1011. curr_x_i = int(curr_x); curr_y_i = int(curr_y); curr_z_i = int(curr_z)
  1012. if 0 <= curr_x_i < s_shape_x and 0 <= curr_y_i < s_shape_y and 0 <= curr_z_i < s_shape_z:
  1013. local_block_map[curr_x_i, curr_y_i, curr_z_i] = k
  1014. #~ print 'blocked..., resample'
  1015. continue # try again
  1016. # ok, we got a valid sample
  1017. new_particles[idx, 0] = new_px
  1018. new_particles[idx, 1] = new_py
  1019. new_particles[idx, 2] = new_pz
  1020. # link to predessor
  1021. back_track_links[j, idx] = k
  1022. # current encoded position
  1023. back_track_positions[j, idx] = new_px * s_shape_y * s_shape_z + new_py * s_shape_z + new_pz
  1024. idx += 1
  1025. num_spawned += 1
  1026. total_spawned += num_spawn_particles
  1027. if i == num_spawn_particles * over_sample_limit - 1:
  1028. over_sample_limit_reached += 1
  1029. for i in range(total_spawned, num_particles):
  1030. new_particles[i, 0] = -1
  1031. # END nogil
  1032. seq_res.append((best_px, best_py, best_pz))
  1033. if with_history:
  1034. self.history.append(sorted_weights.xyzvAsArray())
  1035. sorted_weights.clear()
  1036. #~ print best_px, best_py, best_pz
  1037. if average_over_particles > 0:
  1038. top_particles_a, sum_w, sum_x, sum_y, sum_z = top_particles.particleDataAsArray()
  1039. #~ for i in range(len(top_particles_a[0])):
  1040. #~ print top_particles_a[0, i],
  1041. #~ print top_particles_a[1, i],
  1042. #~ print top_particles_a[2, i],
  1043. #~ print top_particles_a[3, i]
  1044. #~ print len(top_particles_a[0]), sum_w, sum_x, sum_y, sum_z
  1045. tpx, tpy, tpz = (int(top_particles_a[0, -1]), int(top_particles_a[1, -1]), int(top_particles_a[2, -1]))
  1046. assert seq_res[-1] == (tpx, tpy, tpz), '%s != %s' % (seq_res[-1], (tpx, tpy, tpz))
  1047. k = len(top_particles_a[0])
  1048. seq_avg_res.append((int(sum_x / k), int(sum_y / k), int(sum_z / k)))
  1049. # toggle
  1050. new_particles, particles = particles, new_particles
  1051. # reset
  1052. new_particles.fill(0)
  1053. weights.fill(0)
  1054. local_block_map.fill(0)
  1055. top_particles.clear()
  1056. back_tracked_res = []
  1057. curr_idx = best_idx
  1058. curr_px, curr_py, curr_pz = seq_res[-1]
  1059. for j in range(len(measurements)-1, -1, -1):
  1060. position = back_track_positions[j, curr_idx]
  1061. curr_px = position / (s_shape_y * s_shape_z)
  1062. curr_py = (position / s_shape_z) % s_shape_y
  1063. curr_pz = position % s_shape_z
  1064. back_tracked_res.append((curr_px, curr_py, curr_pz))
  1065. curr_idx = back_track_links[j, curr_idx]
  1066. if self.verbose:
  1067. needed_samples = num_particles * len(measurements)
  1068. _log.info('sampling stats: poolaccess: %.2e, rejected: %.2e, reject factor: %.1f, oversample limit reached: %s' %
  1069. (sampling_pool_idx, sampling_pool_idx - needed_samples,
  1070. (sampling_pool_idx - needed_samples) / needed_samples,
  1071. over_sample_limit_reached)
  1072. )
  1073. _log.info('duration: %.3f secs' % (time.time() -t ))
  1074. back_tracked_res = list(reversed(back_tracked_res))
  1075. return back_tracked_res, seq_res, seq_avg_res
  1076. @cython.boundscheck(False)
  1077. def uncube(np.ndarray[np.double_t, ndim=3] data, orgshape):
  1078. cdef np.ndarray[np.double_t, ndim=3] result
  1079. cdef int size_x = orgshape[0]
  1080. cdef int size_y = orgshape[1]
  1081. cdef int size_z = orgshape[2]
  1082. result = np.zeros((size_x, size_y, size_z), dtype=np.double)
  1083. cdef int x, y, z, _x, _y, _z
  1084. cdef int cube_width = orgshape[0] / data.shape[0]
  1085. for x in range(data.shape[0]):
  1086. for y in range(data.shape[1]):
  1087. for z in range(data.shape[2]):
  1088. for _x in range(x * cube_width, x * cube_width + cube_width):
  1089. for _y in range(y * cube_width, y * cube_width + cube_width):
  1090. for _z in range(z * cube_width, z * cube_width + cube_width):
  1091. result[_x, _y, _z] = data[x, y, z]
  1092. return result
  1093. def normalize(x, deviceAdaptionValues, adaptMin=-150.0, isInDB=True):
  1094. '''this is slow of course'''
  1095. if isInDB:
  1096. x = 10**(x / 10.0)
  1097. return toNormalizedDecibelwithDeviceAdaption(np.array([[[x]]]).astype(np.float32), deviceAdaptionValues, adaptMin)[0][0][0]
  1098. @cython.boundscheck(False)
  1099. @cython.cdivision(True)
  1100. def compareForDeviceAdaption(da_values, np.ndarray[np.float32_t, ndim=3] estimated, station2apid_locid2measurement):
  1101. cdef int i, j
  1102. cdef double delta, total = 0
  1103. cdef int num_deltas = 0
  1104. cdef np.ndarray[np.double_t, ndim=3] normalized_estimated
  1105. cdef np.ndarray[np.double_t, ndim=2] measured
  1106. for station in da_values:
  1107. normalized_estimated = toNormalizedDecibelwithDeviceAdaption(estimated, da_values[station])
  1108. measured = station2apid_locid2measurement[station]
  1109. with nogil:
  1110. for i in range(normalized_estimated.shape[0]):
  1111. for j in range(normalized_estimated.shape[1]):
  1112. delta = fabs(normalized_estimated[i, j, 0] - measured[i, j])
  1113. # delta != delta -> isnan() check
  1114. if delta != delta or delta > 100:
  1115. continue
  1116. if not normalized_estimated[i, j, 0] > -100:
  1117. continue
  1118. total = total + delta
  1119. num_deltas = num_deltas + 1
  1120. return total / num_deltas
  1121. @cython.boundscheck(False)
  1122. @cython.cdivision(True)
  1123. def toNormalizedDecibelwithDeviceAdaption(np.ndarray[np.float32_t, ndim=3] data, deviceAdaptionValues, double adaptMin=-150.0):
  1124. cdef int x, y, z, i
  1125. cdef int shape_x=data.shape[0], shape_y=data.shape[1], shape_z=data.shape[2]
  1126. cdef double v, left_intv, right_intv, left_val, right_val, m
  1127. cdef int dacount = len(deviceAdaptionValues)
  1128. assert dacount < 500
  1129. cdef double[500] daintervals
  1130. cdef double[500] davalues
  1131. deviceAdaptionValues = [(adaptMin, -100 - adaptMin)] + deviceAdaptionValues
  1132. for i, (dai, dav) in enumerate(deviceAdaptionValues):
  1133. daintervals[i] = dai
  1134. davalues[i] = dav
  1135. cdef np.ndarray[np.double_t, ndim=3] _data = np.zeros((shape_x, shape_y, shape_z), dtype=np.double)
  1136. for x in prange(shape_x, nogil=True):
  1137. for y in range(shape_y):
  1138. for z in range(shape_z):
  1139. v = data[x, y, z]
  1140. # convert to db
  1141. if v > 0:
  1142. v = 10 * log10(v)
  1143. if v < adaptMin:
  1144. v = -100
  1145. else:
  1146. #apply deviceAdaptation
  1147. with gil:
  1148. for i in range(dacount):
  1149. left_intv = daintervals[i]
  1150. right_intv = daintervals[i+1]
  1151. left_val = davalues[i]
  1152. right_val = davalues[i+1]
  1153. if left_intv <= v < right_intv:
  1154. # it would be easy to cache m as well
  1155. diff1 = right_intv - left_intv
  1156. diff2 = right_intv + right_val - (left_intv + left_val)
  1157. m = diff2 / diff1
  1158. v = left_intv + left_val + (v - left_intv) * m
  1159. break
  1160. else:
  1161. v = -100.0
  1162. _data[x, y, z] = v
  1163. return _data
  1164. def findpath(x, y, z, level):
  1165. #~ print '--- !', x, y, z
  1166. res = []
  1167. for i, j, k in product([-1, 0, 1], [-1, 0, 1], [-1, 0, 1]):
  1168. #~ print i, j, k
  1169. if x + i == 0 and y + j == 0 and z + k == 0:
  1170. return [[(x,y,z)]]
  1171. elif level > 0:
  1172. children = findpath(x + i, y + j, z + k, level-1)
  1173. for l in children:
  1174. l = list(l)
  1175. l.insert(0, (x, y, z))
  1176. res.append(l)
  1177. return res
  1178. @cython.boundscheck(False)
  1179. @cython.cdivision(True)
  1180. def buildTransitionProbs(cubed_data_shape, transition_shape, np.ndarray[np.int_t, ndim=3] blockedCubes, int cubewidth, int freespace_scan):
  1181. cdef int s_shape_x, s_shape_y, s_shape_z, t_shape_x, t_shape_y, t_shape_z
  1182. s_shape_x, s_shape_y, s_shape_z = cubed_data_shape
  1183. t_shape_x, t_shape_y, t_shape_z = transition_shape
  1184. assert (t_shape_x, t_shape_y, t_shape_z) in {(3,3,1), (3,3,3), (5,5,3)}, 'unsuported transition_shape %s' % transition_shape
  1185. cdef np.ndarray[np.double_t, ndim=6] transition_probs = np.zeros((s_shape_x, s_shape_y, s_shape_z, t_shape_x, t_shape_y, t_shape_z), dtype=np.double)
  1186. # the combined transition probs leading TO this cube
  1187. #~ cdef np.ndarray[np.double_t, ndim=3] combined_transition_probs = np.zeros((s_shape_x, s_shape_y, s_shape_z), dtype=np.double)
  1188. # distribute probability evenly over all states s with sum(p(s) for s in S) = 1.0
  1189. cdef double p_s = 1.0 / (s_shape_x * s_shape_y * s_shape_z)
  1190. cdef double cost_p_s = -log(1.0 / (s_shape_x * s_shape_y * s_shape_z))
  1191. #~ cdef double p_s_s
  1192. cdef int sx, sy, sz, tx, ty, tz, numblocked, numunblocked, curr_x, curr_y, curr_z
  1193. #~ cdef double
  1194. cdef int freespace, shape_idx, max_freespace_for_transition
  1195. max_freespace = 0 # 20 highest res cubes - 4 meter if resolution is 0.2m
  1196. cdef double renormalize_target, renormalize_ratio, renormalize_sum # debugging stuff
  1197. cdef int prev_idx_x, prev_idx_y, prev_idx_z
  1198. cdef int offset_x = t_shape_x / 2
  1199. cdef int offset_y = t_shape_y / 2
  1200. cdef int offset_z = t_shape_z / 2
  1201. # for (5, 5, 3) model
  1202. MAX_PATH_LENGTH = 1
  1203. MAX_PATHS = 9
  1204. cdef int unblocked_path_found = 0, x, y, z, i
  1205. cdef np.ndarray[np.int_t, ndim=6] path_to_center = np.zeros((t_shape_x, t_shape_y, t_shape_z, MAX_PATHS, MAX_PATH_LENGTH, 3), dtype=np.int)
  1206. cdef np.ndarray[np.int_t, ndim=1] numblocked_on_level = np.zeros((3), dtype=np.int)
  1207. cdef np.ndarray[np.double_t, ndim=1] p_s_s_on_level = np.zeros((3), dtype=np.double)
  1208. cdef np.ndarray[np.int_t, ndim=1] freespace_for_transition = np.zeros((t_shape_x * t_shape_y * t_shape_z), dtype=np.int)
  1209. for tx in range(t_shape_x):
  1210. for ty in range(t_shape_y):
  1211. for tz in range(t_shape_z):
  1212. if tx == 0 or tx == 4 or ty == 0 or ty == 4:
  1213. all_p = findpath(tx-offset_x, ty-offset_y, tz-offset_z, MAX_PATH_LENGTH)
  1214. for i, p in enumerate(all_p):
  1215. for j, (x, y, z) in enumerate(p[1:]):
  1216. path_to_center[tx, ty, tz, i, j, 0] = x + offset_x
  1217. path_to_center[tx, ty, tz, i, j, 1] = y + offset_y
  1218. path_to_center[tx, ty, tz, i, j, 2] = z + offset_z
  1219. cdef int level0_cubes = 1
  1220. cdef int level1_cubes = 27 - level0_cubes
  1221. cdef int level2_cubes = (5 * 5 * 3) - level1_cubes - level0_cubes
  1222. for sx in range(s_shape_x):
  1223. for sy in range(s_shape_y):
  1224. for sz in range(s_shape_z):
  1225. numblocked = 0
  1226. for tx in range(t_shape_x):
  1227. prev_idx_x = sx + tx - offset_x
  1228. if not 0 <= prev_idx_x < s_shape_x:
  1229. numblocked = numblocked + t_shape_y * t_shape_z
  1230. continue
  1231. for ty in range(t_shape_y):
  1232. prev_idx_y = sy + ty - offset_y
  1233. if not 0 <= prev_idx_y < s_shape_y:
  1234. numblocked = numblocked + t_shape_z
  1235. continue
  1236. for tz in range(t_shape_z):
  1237. prev_idx_z = sz + tz - offset_z
  1238. if not 0 <= prev_idx_z < s_shape_z:
  1239. numblocked += 1
  1240. continue
  1241. if blockedCubes[prev_idx_x, prev_idx_y, prev_idx_z] != UN_BLOCKED:
  1242. # from cube is directly blocked
  1243. transition_probs[sx, sy, sz, tx, ty, tz] = INFINITY
  1244. numblocked += 1
  1245. elif blockedCubes[sx, sy, sz] != UN_BLOCKED:
  1246. # current cube is blocked
  1247. transition_probs[sx, sy, sz, tx, ty, tz] = INFINITY
  1248. numblocked += 1
  1249. elif (t_shape_x == 5 and t_shape_y == 5) and (tx == 0 or tx == 4 or ty == 0 or ty == 4):
  1250. unblocked_path_found = 0
  1251. for i in range(MAX_PATH_LENGTH):
  1252. x = path_to_center[tx, ty, tz, i, 0, 0]
  1253. y = path_to_center[tx, ty, tz, i, 0, 1]
  1254. z = path_to_center[tx, ty, tz, i, 0, 2]
  1255. if x == 0 and y == 0 and z == 0:
  1256. continue
  1257. x = x - offset_x
  1258. y = y - offset_y
  1259. z = z - offset_z
  1260. if blockedCubes[sx + x, sy + y, sz + z] == UN_BLOCKED:
  1261. unblocked_path_found = 1
  1262. break
  1263. if unblocked_path_found == 0:
  1264. transition_probs[sx, sy, sz, tx, ty, tz] = INFINITY
  1265. numblocked += 1
  1266. if freespace_scan == -1:
  1267. # mode blocked cubes infinity and unblocked cubes zero costs
  1268. continue
  1269. # elif == 0: no forward scan, constant costs 1/3 1/3 1/3 costs for each hull level
  1270. numblocked_on_level[0] = 0
  1271. numblocked_on_level[1] = 0
  1272. numblocked_on_level[2] = 0
  1273. #~ if numblocked < t_shape_x * t_shape_y * t_shape_z :
  1274. #~ p_s_s = -log(p_s / (t_shape_x * t_shape_y * t_shape_z - numblocked))
  1275. #~ else:
  1276. #~ p_s_s = INFINITY
  1277. for tx in range(t_shape_x):
  1278. for ty in range(t_shape_y):
  1279. for tz in range(t_shape_z):
  1280. #~ if transition_probs[sx, sy, sz, tx, ty, tz] == 0:
  1281. #~ transition_probs[sx, sy, sz, tx, ty, tz] = p_s_s
  1282. if abs(tx - offset_x) == 2 or abs(ty - offset_y) == 2:
  1283. if transition_probs[sx, sy, sz, tx, ty, tz] == INFINITY:
  1284. numblocked_on_level[2] += 1
  1285. elif abs(tx - offset_x) == 1 or abs(ty - offset_y) == 1:
  1286. if transition_probs[sx, sy, sz, tx, ty, tz] == INFINITY:
  1287. numblocked_on_level[1] += 1
  1288. else:
  1289. if transition_probs[sx, sy, sz, tx, ty, tz] == INFINITY:
  1290. numblocked_on_level[0] += 1
  1291. if numblocked < t_shape_x * t_shape_y * t_shape_z :
  1292. #~ p_s_s_on_level[0] = -log(p_s / level0_cubes / 3.0)
  1293. #~ p_s_s_on_level[1] = -log(p_s / (level1_cubes - numblocked_on_level[1]) / 3.0)
  1294. #~ p_s_s_on_level[2] = -log(p_s / (level2_cubes - numblocked_on_level[2]) / 3.0)
  1295. p_s_s_on_level[0] = -log(p_s / level0_cubes / 3.0) # numblocked_on_level[0] is handled by local INFINITY check
  1296. if numblocked_on_level[0] == 1:
  1297. # move probability mass of first level (add all mass from zero level)
  1298. # double p, half costs
  1299. p_s_s_on_level[1] = -log((p_s + p_s) / (level1_cubes - numblocked_on_level[1]) / 3.0)
  1300. else:
  1301. p_s_s_on_level[1] = -log(p_s / (level1_cubes - numblocked_on_level[1]) / 3.0)
  1302. p_s_s_on_level[2] = -log(p_s / (level2_cubes - numblocked_on_level[2]) / 3.0)
  1303. #~ print level1_cubes, numblocked_on_level[1], level2_cubes, numblocked_on_level[2]
  1304. #~ print p_s_s_on_level[0], p_s_s_on_level[1], p_s_s_on_level[2]
  1305. #~ p_s_s_on_level[0] = 0#-log((1.0 / 3) * p_s / level0_cubes)
  1306. #~ p_s_s_on_level[1] = 0#-log((1.0 / 3) * p_s / (level1_cubes - numblocked_on_level[1]))
  1307. #~ p_s_s_on_level[2] = 0#-log((1.0 / 3) * p_s / (level2_cubes - numblocked_on_level[2]))
  1308. # find max freespace and normalize in the next step by that maximum
  1309. shape_idx = 0
  1310. max_freespace_for_transition = 0
  1311. for tx in range(t_shape_x):
  1312. for ty in range(t_shape_y):
  1313. for tz in range(t_shape_z):
  1314. # forward scan to determine number of unblocked cubes ahead (in direction of jump) to modify cost/p_s_s
  1315. delta_x = tx - offset_x
  1316. delta_y = ty - offset_y
  1317. delta_z = tz - offset_z
  1318. if delta_x != 0 or delta_y != 0 or delta_z != 0:
  1319. numunblocked = 0
  1320. curr_x = sx
  1321. curr_y = sy
  1322. curr_z = sz
  1323. while 0 <= curr_x < s_shape_x and 0 <= curr_y < s_shape_y and 0 <= curr_z < s_shape_z and numunblocked < freespace_scan / cubewidth:
  1324. if blockedCubes[curr_x, curr_y, curr_z] == UN_BLOCKED:
  1325. numunblocked = numunblocked + 1
  1326. curr_x = curr_x - delta_x
  1327. curr_y = curr_y - delta_y
  1328. # if we dont manipulate the z-delta handling jumping in z-order
  1329. # will be very unlikely as there is normally no free space
  1330. if abs(delta_x) > 0 or abs(delta_y) > 0:
  1331. pass # do not touch z
  1332. else:
  1333. curr_z = curr_z - delta_z
  1334. else:
  1335. break
  1336. freespace = numunblocked * cubewidth
  1337. #~ if abs(delta_z) > 0:
  1338. #~ freespace = freespace * 3
  1339. if freespace > max_freespace_for_transition:
  1340. max_freespace_for_transition = freespace
  1341. freespace_for_transition[shape_idx] = freespace
  1342. shape_idx = shape_idx + 1
  1343. shape_idx = 0
  1344. renormalize_target = 0
  1345. cost_p_s_1 = 0
  1346. for tx in range(t_shape_x):
  1347. for ty in range(t_shape_y):
  1348. for tz in range(t_shape_z):
  1349. delta_x = tx - offset_x
  1350. delta_y = ty - offset_y
  1351. delta_z = tz - offset_z
  1352. freespace = freespace_for_transition[shape_idx]
  1353. if abs(delta_x) == 2 or abs(delta_y) == 2:
  1354. if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1355. transition_probs[sx, sy, sz, tx, ty, tz] = p_s_s_on_level[2] * (max_freespace_for_transition - freespace + 1)
  1356. cost_p_s_1 = cost_p_s_1 + p_s_s_on_level[2]
  1357. elif abs(delta_x) == 1 or abs(delta_y) == 1 or abs(delta_z) == 1:
  1358. if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1359. transition_probs[sx, sy, sz, tx, ty, tz] = p_s_s_on_level[1] * (max_freespace_for_transition - freespace + 1) #* (1.0 - freespace / <double>max_freespace)
  1360. cost_p_s_1 = cost_p_s_1 + p_s_s_on_level[1]
  1361. else:
  1362. if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1363. transition_probs[sx, sy, sz, tx, ty, tz] = p_s_s_on_level[0] * 3
  1364. cost_p_s_1 = cost_p_s_1 + p_s_s_on_level[0]
  1365. #~ if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1366. #~ print delta_x, delta_y, delta_z, transition_probs[sx, sy, sz, tx, ty, tz]
  1367. if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1368. renormalize_target = renormalize_target + transition_probs[sx, sy, sz, tx, ty, tz]
  1369. shape_idx = shape_idx + 1
  1370. renormalize_ratio = cost_p_s_1 / renormalize_target
  1371. renormalize_sum = 0
  1372. for tx in range(t_shape_x):
  1373. for ty in range(t_shape_y):
  1374. for tz in range(t_shape_z):
  1375. if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1376. transition_probs[sx, sy, sz, tx, ty, tz] = transition_probs[sx, sy, sz, tx, ty, tz] * renormalize_ratio
  1377. #~ if transition_probs[sx, sy, sz, tx, ty, tz] != INFINITY:
  1378. #~ renormalize_sum = renormalize_sum + transition_probs[sx, sy, sz, tx, ty, tz]
  1379. #~ assert renormalize_sum == 0 or (renormalize_sum - 0.1 < cost_p_s < renormalize_sum + 0.1), '%s %s' % (cost_p_s, renormalize_sum)
  1380. return transition_probs
  1381. @cython.boundscheck(False)
  1382. @cython.cdivision(True)
  1383. def buildStatesWithEmissionProbs(data_shape, apdata_list, int cube_width=3, double default_sq_variance=1, pooled_variance=0):
  1384. ''' build states from accesspoint volume images (apvis should have equal dimensions)
  1385. @param apdata: list of accesspoints volumeimages
  1386. @param cube_width: size of cube for state
  1387. '''
  1388. assert len(apdata_list) > 0
  1389. # number of voxels in a state
  1390. cdef int cube_count = cube_width * cube_width * cube_width
  1391. cdef int vidi_x = data_shape[0], vidi_y = data_shape[1], vidi_z = data_shape[2]
  1392. cdef int size_x = vidi_x / cube_width, size_y = vidi_y / cube_width, size_z = vidi_z / cube_width
  1393. # first 3 dims x, y, z in state-space
  1394. # dim 4 (mean, variance)
  1395. # dim 5 apidx
  1396. cdef np.ndarray[np.double_t, ndim=5] states
  1397. states = np.zeros((size_x, size_y, size_z, 2, len(apdata_list)), dtype=np.double)
  1398. cdef np.ndarray[np.double_t, ndim=3] vidata = np.zeros((vidi_x, vidi_y, vidi_z), dtype=np.double)
  1399. # in state space
  1400. cdef int sx, sy, sz
  1401. # in volume image space
  1402. cdef int vx, vy, vz
  1403. cdef int bound_x1, bound_y1, bound_z1, bound_x2, bound_y2, bound_z2
  1404. # auxilary vars
  1405. cdef int apidx # accesspoint index
  1406. cdef double s, delta, mean, squared_variance
  1407. for apidx, vidata in enumerate(apdata_list):
  1408. for sx in range(size_x):
  1409. bound_x1 = cube_width * sx
  1410. bound_x2 = bound_x1 + cube_width
  1411. if (bound_x2 >= vidi_x):
  1412. # degenerated boundary cube - will contain less voxels
  1413. # meaybe it would be better to sort them out
  1414. bound_x2 = vidi_x
  1415. for sy in range(size_y):
  1416. bound_y1 = cube_width * sy
  1417. bound_y2 = bound_y1 + cube_width
  1418. if (bound_y2 >= vidi_y):
  1419. # degenerated boundary cube
  1420. bound_y2 = vidi_y
  1421. for sz in range(size_z):
  1422. bound_z1 = cube_width * sz
  1423. bound_z2 = bound_z1 + cube_width
  1424. if (bound_z2 >= vidi_z):
  1425. # degenerated boundary cube
  1426. bound_z2 = vidi_z
  1427. # traverse cube coordinates in volume image
  1428. #to calc mean
  1429. s = 0
  1430. for vx in range(bound_x1, bound_x2):
  1431. for vy in range(bound_y1, bound_y2):
  1432. for vz in range(bound_z1, bound_z2):
  1433. s += vidata[vx, vy, vz]
  1434. mean = s / cube_count
  1435. states[sx, sy, sz, 0, apidx] = mean
  1436. if pooled_variance > 0:
  1437. states[sx, sy, sz, 1, apidx] = pooled_variance
  1438. else:
  1439. # now calculate variance
  1440. s = 0
  1441. for vx in range(bound_x1, bound_x2):
  1442. for vy in range(bound_y1, bound_y2):
  1443. for vz in range(bound_z1, bound_z2):
  1444. delta = mean - vidata[vx, vy, vz]
  1445. s += delta * delta
  1446. # store squared variance
  1447. squared_variance = s / cube_count
  1448. if squared_variance == 0:
  1449. # fully flat voxel data - will lead to singular gaussian
  1450. squared_variance = default_sq_variance
  1451. states[sx, sy, sz, 1, apidx] = squared_variance
  1452. return states
  1453. @cython.boundscheck(False)
  1454. @cython.cdivision(True)
  1455. def buildTriangleCubeIntersection(np.ndarray[np.float_t, ndim=3] bl_triangles,
  1456. np.ndarray[np.float_t, ndim=3] unpass_triangles,
  1457. np.ndarray[np.float_t, ndim=3] unbl_triangles,
  1458. cubed_data_shape, int cube_width, vi_dimensions):
  1459. di = vi_dimensions
  1460. # do not confuse disx and sx
  1461. # disx is the x-width of a voxel in the volume image dimension and sx is the x-loop var for the state space (the cubes)
  1462. cdef float disx=di.sx, disy=di.sy, disz=di.sz, ditx=di.tx, dity=di.ty, ditz=di.tz
  1463. cdef int size_x, size_y, size_z
  1464. size_x, size_y, size_z = cubed_data_shape[0], cubed_data_shape[1], cubed_data_shape[2]
  1465. cdef np.ndarray[np.int_t, ndim=3] blockedCubes = np.zeros((size_x, size_y, size_z), dtype=np.int)
  1466. cdef int sx, sy, sz # in state space
  1467. cdef int vx, vy, vz # in volume image space (raytracer space)
  1468. cdef float x, y, z # in real world space
  1469. cdef float real_cube_half_width_x = (cube_width * disx) / 2.0
  1470. cdef float real_cube_half_width_y = (cube_width * disy) / 2.0
  1471. cdef float real_cube_half_width_z = (cube_width * disz) / 2.0
  1472. cdef int i, len_triangles, set_to_val
  1473. cdef float bc0, bc1, bc2, bhs0, bhs1, bhs2, tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8, xx
  1474. bhs0 = real_cube_half_width_x
  1475. bhs1 = real_cube_half_width_y
  1476. bhs2 = real_cube_half_width_z
  1477. cdef np.ndarray[np.float_t, ndim=3] triangles
  1478. for triangles, set_to_val in ((bl_triangles, BLOCKED), (unpass_triangles, UNPASSABLE), (unbl_triangles, UN_BLOCKED)):
  1479. len_triangles = len(triangles)
  1480. for i in prange(len_triangles, nogil=True):
  1481. tv0 = triangles[i, 0, 0]
  1482. tv1 = triangles[i, 0, 1]
  1483. tv2 = triangles[i, 0, 2]
  1484. tv3 = triangles[i, 1, 0]
  1485. tv4 = triangles[i, 1, 1]
  1486. tv5 = triangles[i, 1, 2]
  1487. tv6 = triangles[i, 2, 0]
  1488. tv7 = triangles[i, 2, 1]
  1489. tv8 = triangles[i, 2, 2]
  1490. for sx in range(size_x):
  1491. vx = sx * cube_width
  1492. x = vx * disx + ditx
  1493. bc0 = x + real_cube_half_width_x
  1494. for sy in range(size_y):
  1495. vy = sy * cube_width
  1496. y = vy * disy + dity
  1497. bc1 = y + real_cube_half_width_y
  1498. for sz in range(size_z):
  1499. vz = sz * cube_width
  1500. z = vz * disz + ditz
  1501. bc2 = z + real_cube_half_width_z
  1502. if triBoxOverlap(bc0, bc1, bc2, bhs0, bhs1, bhs2, tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8):
  1503. blockedCubes[sx, sy, sz] = set_to_val
  1504. return blockedCubes
  1505. @cython.boundscheck(False)
  1506. @cython.cdivision(True)
  1507. def evalUnreachableAirCubes(np.ndarray[np.int_t, ndim=3] blockedCubes, cube_height, max_reachable_height):
  1508. cdef int size_x, size_y, size_z
  1509. size_x, size_y, size_z = blockedCubes.shape[0], blockedCubes.shape[1], blockedCubes.shape[2]
  1510. cdef int max_cubes_above = max_reachable_height / cube_height
  1511. cdef int sx, sy, sz, zi # in state space
  1512. for sz in range(size_z):
  1513. for sx in range(size_x):
  1514. for sy in range(size_y):
  1515. # find a currently unblocked/unmarked element
  1516. if blockedCubes[sx, sy, sz] == UN_BLOCKED:
  1517. # scan in z+ direction and mark everything > max_cubes_above as unreachable
  1518. # stop if next blocking element hit, probably the floor above us
  1519. zi = sz
  1520. while zi < size_z and blockedCubes[sx, sy, zi] == UN_BLOCKED:
  1521. if zi - sz > max_cubes_above:
  1522. blockedCubes[sx, sy, zi] = AIR # mark as ureachable air cube
  1523. zi = zi + 1
  1524. elif blockedCubes[sx, sy, sz] == UNPASSABLE:
  1525. # scan in z+ direction and if a UN_BLOCKED chain is starting - mark every UN_BLOCKED to UNPASSABLE
  1526. # stop if next blocking element hit, probably the floor above us
  1527. zi = sz + 1
  1528. while zi < size_z and blockedCubes[sx, sy, zi] == UN_BLOCKED:
  1529. blockedCubes[sx, sy, zi] = UNPASSABLE # mark as unpassable air cube
  1530. zi = zi + 1
  1531. @cython.boundscheck(False)
  1532. def viewPruningHistory(histories, idx, orgshape, int cubewidth, count, int view_values=1, int raw_values=0):
  1533. cdef np.ndarray[np.double_t, ndim=2] history = histories[idx]
  1534. cdef np.ndarray[np.double_t, ndim=3] result
  1535. cdef int size_x = orgshape[0]
  1536. cdef int size_y = orgshape[1]
  1537. cdef int size_z = orgshape[2]
  1538. result = np.zeros((size_x, size_y, size_z), dtype=np.double)
  1539. if count > history.shape[0]:
  1540. count = history.shape[0] - 1
  1541. cdef double cost, min_cost = INFINITY
  1542. cdef int i
  1543. for i in range(history.shape[0] - count, history.shape[0]):
  1544. cost = history[i, 3]
  1545. if cost < min_cost:
  1546. min_cost = cost
  1547. cdef int x, y, z, j1, j2, j3, start, end
  1548. start = history.shape[0] - count
  1549. end = history.shape[0]
  1550. for i in prange(start, end, nogil=True):
  1551. x = <int>history[i, 0] * cubewidth
  1552. y = <int>history[i, 1] * cubewidth
  1553. z = <int>history[i, 2] * cubewidth
  1554. cost = history[i, 3]
  1555. for j1 in range(cubewidth):
  1556. if x + j1 >= size_x:
  1557. continue
  1558. for j2 in range(cubewidth):
  1559. if y + j2 >= size_y:
  1560. continue
  1561. for j3 in range(cubewidth):
  1562. if z + j3 >= size_z:
  1563. continue
  1564. if view_values:
  1565. if raw_values:
  1566. result[x + j1, y + j2, z + j3] = -min_cost
  1567. else:
  1568. result[x + j1, y + j2, z + j3] = cost - min_cost
  1569. else:
  1570. # view positions
  1571. result[x + j1, y + j2, z + j3] = i - start
  1572. return result