temporal_operator.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. """@package grass.temporal
  2. Temporal operator evaluation with PLY
  3. (C) 2013 by the GRASS Development Team
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. :authors: Thomas Leppelt and Soeren Gebbert
  8. .. code-block:: python
  9. >>> p = TemporalOperatorParser()
  10. >>> expression = "{equal| during}"
  11. >>> p.parse(expression, optype = 'relation')
  12. >>> print(p.relations, p.temporal, p.function)
  13. (['equal', 'during'], None, None)
  14. >>> p = TemporalOperatorParser()
  15. >>> expression = "{contains | starts}"
  16. >>> p.parse(expression)
  17. >>> print(p.relations, p.temporal, p.function)
  18. (['contains', 'starts'], None, None)
  19. >>> p = TemporalOperatorParser()
  20. >>> expression = "{&&, during}"
  21. >>> p.parse(expression, optype = 'boolean')
  22. >>> print(p.relations, p.temporal, p.function,p.aggregate)
  23. (['during'], 'l', '&&', '&')
  24. >>> p = TemporalOperatorParser()
  25. >>> expression = "{||, equal | during}"
  26. >>> p.parse(expression, optype = 'boolean')
  27. >>> print(p.relations, p.temporal, p.function,p.aggregate)
  28. (['equal', 'during'], 'l', '||', '|')
  29. >>> p = TemporalOperatorParser()
  30. >>> expression = "{||, equal | during, &}"
  31. >>> p.parse(expression, optype = 'boolean')
  32. >>> print(p.relations, p.temporal, p.function,p.aggregate)
  33. (['equal', 'during'], 'l', '||', '&')
  34. >>> p = TemporalOperatorParser()
  35. >>> expression = "{&&, during, |}"
  36. >>> p.parse(expression, optype = 'boolean')
  37. >>> print(p.relations, p.temporal, p.function,p.aggregate)
  38. (['during'], 'l', '&&', '|')
  39. >>> p = TemporalOperatorParser()
  40. >>> expression = "{&&, during, |, r}"
  41. >>> p.parse(expression, optype = 'boolean')
  42. >>> print(p.relations, p.temporal, p.function,p.aggregate)
  43. (['during'], 'r', '&&', '|')
  44. >>> p = TemporalOperatorParser()
  45. >>> expression = "{&&, during, u}"
  46. >>> p.parse(expression, optype = 'boolean')
  47. >>> print(p.relations, p.temporal, p.function,p.aggregate)
  48. (['during'], 'u', '&&', '&')
  49. >>> p = TemporalOperatorParser()
  50. >>> expression = "{:, during, r}"
  51. >>> p.parse(expression, optype = 'select')
  52. >>> print(p.relations, p.temporal, p.function)
  53. (['during'], 'r', ':')
  54. >>> p = TemporalOperatorParser()
  55. >>> expression = "{!:, equal | contains, d}"
  56. >>> p.parse(expression, optype = 'select')
  57. >>> print(p.relations, p.temporal, p.function)
  58. (['equal', 'contains'], 'd', '!:')
  59. >>> p = TemporalOperatorParser()
  60. >>> expression = "{#, during, r}"
  61. >>> p.parse(expression, optype = 'hash')
  62. >>> print(p.relations, p.temporal, p.function)
  63. (['during'], 'r', '#')
  64. >>> p = TemporalOperatorParser()
  65. >>> expression = "{#, equal | contains}"
  66. >>> p.parse(expression, optype = 'hash')
  67. >>> print(p.relations, p.temporal, p.function)
  68. (['equal', 'contains'], 'l', '#')
  69. >>> p = TemporalOperatorParser()
  70. >>> expression = "{+, during, r}"
  71. >>> p.parse(expression, optype = 'raster')
  72. >>> print(p.relations, p.temporal, p.function)
  73. (['during'], 'r', '+')
  74. >>> p = TemporalOperatorParser()
  75. >>> expression = "{/, equal | contains}"
  76. >>> p.parse(expression, optype = 'raster')
  77. >>> print(p.relations, p.temporal, p.function)
  78. (['equal', 'contains'], 'l', '/')
  79. >>> p = TemporalOperatorParser()
  80. >>> expression = "{+, equal | contains,intersect}"
  81. >>> p.parse(expression, optype = 'raster')
  82. >>> print(p.relations, p.temporal, p.function)
  83. (['equal', 'contains'], 'i', '+')
  84. >>> p = TemporalOperatorParser()
  85. >>> expression = "{*, contains,disjoint}"
  86. >>> p.parse(expression, optype = 'raster')
  87. >>> print(p.relations, p.temporal, p.function)
  88. (['contains'], 'd', '*')
  89. >>> p = TemporalOperatorParser()
  90. >>> expression = "{~, equal,left}"
  91. >>> p.parse(expression, optype = 'overlay')
  92. >>> print(p.relations, p.temporal, p.function)
  93. (['equal'], 'l', '~')
  94. >>> p = TemporalOperatorParser()
  95. >>> expression = "{^, over,right}"
  96. >>> p.parse(expression, optype = 'overlay')
  97. >>> print(p.relations, p.temporal, p.function)
  98. (['overlaps', 'overlapped'], 'r', '^')
  99. """
  100. try:
  101. import ply.lex as lex
  102. import ply.yacc as yacc
  103. except:
  104. pass
  105. class TemporalOperatorLexer(object):
  106. """Lexical analyzer for the GRASS GIS temporal operator"""
  107. # Functions that defines topological relations.
  108. relations = {
  109. 'equal' : "EQUAL",
  110. 'follows' : "FOLLOWS",
  111. 'precedes' : "PRECEDES",
  112. 'overlaps' : "OVERLAPS",
  113. 'overlapped' : "OVERLAPPED",
  114. 'during' : "DURING",
  115. 'starts' : "STARTS",
  116. 'finishes' : "FINISHES",
  117. 'contains' : "CONTAINS",
  118. 'started' : "STARTED",
  119. 'finished' : "FINISHED",
  120. 'over' : "OVER"
  121. }
  122. # This is the list of token names.
  123. tokens = (
  124. 'COMMA',
  125. 'LEFTREF',
  126. 'RIGHTREF',
  127. 'UNION',
  128. 'DISJOINT',
  129. 'INTERSECT',
  130. 'HASH',
  131. 'OR',
  132. 'AND',
  133. 'DISOR',
  134. 'XOR',
  135. 'NOT',
  136. 'MOD',
  137. 'DIV',
  138. 'MULT',
  139. 'ADD',
  140. 'SUB',
  141. 'T_SELECT',
  142. 'T_NOT_SELECT',
  143. 'CLPAREN',
  144. 'CRPAREN',
  145. )
  146. # Build the token list
  147. tokens = tokens + tuple(relations.values())
  148. # Regular expression rules for simple tokens
  149. t_T_SELECT = r':'
  150. t_T_NOT_SELECT = r'!:'
  151. t_COMMA = r','
  152. t_LEFTREF = '^[l|left]'
  153. t_RIGHTREF ='^[r|right]'
  154. t_UNION = '^[u|union]'
  155. t_DISJOINT = '^[d|disjoint]'
  156. t_INTERSECT = '^[i|intersect]'
  157. t_HASH = r'\#'
  158. t_OR = r'[\|]'
  159. t_AND = r'[&]'
  160. t_DISOR = r'\+'
  161. t_XOR = r'\^'
  162. t_NOT = r'\~'
  163. t_MOD = r'[\%]'
  164. t_DIV = r'[\/]'
  165. t_MULT = r'[\*]'
  166. t_ADD = r'[\+]'
  167. t_SUB = r'[-]'
  168. t_CLPAREN = r'\{'
  169. t_CRPAREN = r'\}'
  170. # These are the things that should be ignored.
  171. t_ignore = ' \t'
  172. # Track line numbers.
  173. def t_newline(self, t):
  174. r'\n+'
  175. t.lineno += len(t.value)
  176. def t_NAME(self, t):
  177. r'[a-zA-Z_][a-zA-Z_0-9]*'
  178. self.temporal_symbol(t)
  179. return t
  180. # Parse symbols
  181. def temporal_symbol(self, t):
  182. # Check for reserved words
  183. if t.value in TemporalOperatorLexer.relations.keys():
  184. t.type = TemporalOperatorLexer.relations.get(t.value)
  185. elif t.value == 'l' or t.value == 'left':
  186. t.value = 'l'
  187. t.type = 'LEFTREF'
  188. elif t.value == 'r' or t.value == 'right':
  189. t.value = 'r'
  190. t.type = 'RIGHTREF'
  191. elif t.value == 'u' or t.value == 'union':
  192. t.value = 'u'
  193. t.type = 'UNION'
  194. elif t.value == 'd' or t.value == 'disjoint':
  195. t.value = 'd'
  196. t.type = 'DISJOINT'
  197. elif t.value == 'i' or t.value == 'intersect':
  198. t.value = 'i'
  199. t.type = 'INTERSECT'
  200. #else:
  201. # t.type = 'NAME'
  202. return(t)
  203. # Handle errors.
  204. def t_error(self, t):
  205. raise SyntaxError("syntax error on line %d near '%s'" %
  206. (t.lineno, t.value))
  207. # Build the lexer
  208. def build(self,**kwargs):
  209. self.lexer = lex.lex(module=self, **kwargs)
  210. # Just for testing
  211. def test(self,data):
  212. self.name_list = {}
  213. print(data)
  214. self.lexer.input(data)
  215. while True:
  216. tok = self.lexer.token()
  217. if not tok: break
  218. print tok
  219. ###############################################################################
  220. class TemporalOperatorParser(object):
  221. """The temporal operator class"""
  222. def __init__(self):
  223. self.lexer = TemporalOperatorLexer()
  224. self.lexer.build()
  225. self.parser = yacc.yacc(module=self)
  226. self.relations = None
  227. self.temporal = None
  228. self.function = None
  229. self.aggregate = None
  230. def parse(self, expression, optype = 'relation'):
  231. self.optype = optype
  232. self.parser.parse(expression)
  233. # The parameter optype can be of type: select {:, during, r}, boolean{&&, contains, |},
  234. # raster{*, equal, |}, vector {|, starts, &},
  235. # hash{#, during, l} or relation {during}.
  236. # Error rule for syntax errors.
  237. def p_error(self, t):
  238. raise SyntaxError("Unexpected syntax error")
  239. # Get the tokens from the lexer class
  240. tokens = TemporalOperatorLexer.tokens
  241. def p_relation_operator(self, t):
  242. # The expression should always return a list of maps.
  243. """
  244. operator : CLPAREN relation CRPAREN
  245. | CLPAREN relationlist CRPAREN
  246. """
  247. # Check for correct type.
  248. if not self.optype == 'relation':
  249. raise SyntaxError("invalid syntax")
  250. else:
  251. # Set three operator components.
  252. if isinstance(t[2], list):
  253. self.relations = t[2]
  254. else:
  255. self.relations = [t[2]]
  256. self.temporal = None
  257. self.function = None
  258. t[0] = t[2]
  259. def p_relation_bool_operator(self, t):
  260. # The expression should always return a list of maps.
  261. """
  262. operator : CLPAREN OR OR COMMA relation CRPAREN
  263. | CLPAREN AND AND COMMA relation CRPAREN
  264. | CLPAREN OR OR COMMA relationlist CRPAREN
  265. | CLPAREN AND AND COMMA relationlist CRPAREN
  266. """
  267. if not self.optype == 'boolean':
  268. raise SyntaxError("invalid syntax")
  269. else:
  270. # Set three operator components.
  271. if isinstance(t[5], list):
  272. self.relations = t[5]
  273. else:
  274. self.relations = [t[5]]
  275. self.temporal = "l"
  276. self.function = t[2] + t[3]
  277. self.aggregate = t[2]
  278. t[0] = t[2]
  279. def p_relation_bool_combi_operator(self, t):
  280. # The expression should always return a list of maps.
  281. """
  282. operator : CLPAREN OR OR COMMA relation COMMA OR CRPAREN
  283. | CLPAREN OR OR COMMA relation COMMA AND CRPAREN
  284. | CLPAREN AND AND COMMA relation COMMA OR CRPAREN
  285. | CLPAREN AND AND COMMA relation COMMA AND CRPAREN
  286. | CLPAREN OR OR COMMA relationlist COMMA OR CRPAREN
  287. | CLPAREN OR OR COMMA relationlist COMMA AND CRPAREN
  288. | CLPAREN AND AND COMMA relationlist COMMA OR CRPAREN
  289. | CLPAREN AND AND COMMA relationlist COMMA AND CRPAREN
  290. """
  291. if not self.optype == 'boolean':
  292. raise SyntaxError("invalid syntax")
  293. else:
  294. # Set three operator components.
  295. if isinstance(t[5], list):
  296. self.relations = t[5]
  297. else:
  298. self.relations = [t[5]]
  299. self.temporal = "l"
  300. self.function = t[2] + t[3]
  301. self.aggregate = t[7]
  302. t[0] = t[2]
  303. def p_relation_bool_combi_operator2(self, t):
  304. # The expression should always return a list of maps.
  305. """
  306. operator : CLPAREN OR OR COMMA relation COMMA temporal CRPAREN
  307. | CLPAREN AND AND COMMA relation COMMA temporal CRPAREN
  308. | CLPAREN OR OR COMMA relationlist COMMA temporal CRPAREN
  309. | CLPAREN AND AND COMMA relationlist COMMA temporal CRPAREN
  310. """
  311. if not self.optype == 'boolean':
  312. raise SyntaxError("invalid syntax")
  313. else:
  314. # Set three operator components.
  315. if isinstance(t[5], list):
  316. self.relations = t[5]
  317. else:
  318. self.relations = [t[5]]
  319. self.temporal = t[7]
  320. self.function = t[2] + t[3]
  321. self.aggregate = t[2]
  322. t[0] = t[2]
  323. def p_relation_bool_combi_operator3(self, t):
  324. # The expression should always return a list of maps.
  325. """
  326. operator : CLPAREN OR OR COMMA relation COMMA OR COMMA temporal CRPAREN
  327. | CLPAREN OR OR COMMA relation COMMA AND COMMA temporal CRPAREN
  328. | CLPAREN AND AND COMMA relation COMMA OR COMMA temporal CRPAREN
  329. | CLPAREN AND AND COMMA relation COMMA AND COMMA temporal CRPAREN
  330. | CLPAREN OR OR COMMA relationlist COMMA OR COMMA temporal CRPAREN
  331. | CLPAREN OR OR COMMA relationlist COMMA AND COMMA temporal CRPAREN
  332. | CLPAREN AND AND COMMA relationlist COMMA OR COMMA temporal CRPAREN
  333. | CLPAREN AND AND COMMA relationlist COMMA AND COMMA temporal CRPAREN
  334. """
  335. if not self.optype == 'boolean':
  336. raise SyntaxError("invalid syntax")
  337. else:
  338. # Set three operator components.
  339. if isinstance(t[5], list):
  340. self.relations = t[5]
  341. else:
  342. self.relations = [t[5]]
  343. self.temporal = t[9]
  344. self.function = t[2] + t[3]
  345. self.aggregate = t[7]
  346. t[0] = t[2]
  347. def p_select_relation_operator(self, t):
  348. # The expression should always return a list of maps.
  349. """
  350. operator : CLPAREN select CRPAREN
  351. | CLPAREN select COMMA relation CRPAREN
  352. | CLPAREN select COMMA relationlist CRPAREN
  353. | CLPAREN select COMMA relation COMMA temporal CRPAREN
  354. | CLPAREN select COMMA relationlist COMMA temporal CRPAREN
  355. """
  356. if not self.optype == 'select':
  357. raise SyntaxError("invalid syntax")
  358. else:
  359. if len(t) == 4:
  360. # Set three operator components.
  361. self.relations = ['equal']
  362. self.temporal = "l"
  363. self.function = t[2]
  364. elif len(t) == 5:
  365. self.relations = ['equal']
  366. self.temporal = t[3]
  367. self.function = t[2]
  368. elif len(t) == 6:
  369. if isinstance(t[4], list):
  370. self.relations = t[4]
  371. else:
  372. self.relations = [t[4]]
  373. self.temporal = "l"
  374. self.function = t[2]
  375. elif len(t) == 8:
  376. if isinstance(t[4], list):
  377. self.relations = t[4]
  378. else:
  379. self.relations = [t[4]]
  380. self.temporal = t[6]
  381. self.function = t[2]
  382. t[0] = t[2]
  383. def p_hash_relation_operator(self, t):
  384. # The expression should always return a list of maps.
  385. """
  386. operator : CLPAREN HASH CRPAREN
  387. | CLPAREN HASH COMMA relation CRPAREN
  388. | CLPAREN HASH COMMA relationlist CRPAREN
  389. | CLPAREN HASH COMMA relation COMMA temporal CRPAREN
  390. | CLPAREN HASH COMMA relationlist COMMA temporal CRPAREN
  391. """
  392. if not self.optype == 'hash':
  393. raise SyntaxError("invalid syntax")
  394. else:
  395. if len(t) == 4:
  396. # Set three operator components.
  397. self.relations = ['equal']
  398. self.temporal = "l"
  399. self.function = t[2]
  400. elif len(t) == 5:
  401. self.relations = ['equal']
  402. self.temporal = t[3]
  403. self.function = t[2]
  404. elif len(t) == 6:
  405. if isinstance(t[4], list):
  406. self.relations = t[4]
  407. else:
  408. self.relations = [t[4]]
  409. self.temporal = "l"
  410. self.function = t[2]
  411. elif len(t) == 8:
  412. if isinstance(t[4], list):
  413. self.relations = t[4]
  414. else:
  415. self.relations = [t[4]]
  416. self.temporal = t[6]
  417. self.function = t[2]
  418. t[0] = t[2]
  419. def p_raster_relation_operator(self, t):
  420. # The expression should always return a list of maps.
  421. """
  422. operator : CLPAREN arithmetic CRPAREN
  423. | CLPAREN arithmetic COMMA relation CRPAREN
  424. | CLPAREN arithmetic COMMA relationlist CRPAREN
  425. | CLPAREN arithmetic COMMA relation COMMA temporal CRPAREN
  426. | CLPAREN arithmetic COMMA relationlist COMMA temporal CRPAREN
  427. """
  428. if not self.optype == 'raster':
  429. raise SyntaxError("invalid syntax")
  430. else:
  431. if len(t) == 4:
  432. # Set three operator components.
  433. self.relations = ['equal']
  434. self.temporal = "l"
  435. self.function = t[2]
  436. elif len(t) == 5:
  437. self.relations = ['equal']
  438. self.temporal = t[3]
  439. self.function = t[2]
  440. elif len(t) == 6:
  441. if isinstance(t[4], list):
  442. self.relations = t[4]
  443. else:
  444. self.relations = [t[4]]
  445. self.temporal = "l"
  446. self.function = t[2]
  447. elif len(t) == 8:
  448. if isinstance(t[4], list):
  449. self.relations = t[4]
  450. else:
  451. self.relations = [t[4]]
  452. self.temporal = t[6]
  453. self.function = t[2]
  454. t[0] = t[2]
  455. def p_overlay_relation_operator(self, t):
  456. # The expression should always return a list of maps.
  457. """
  458. operator : CLPAREN overlay CRPAREN
  459. | CLPAREN overlay COMMA relation CRPAREN
  460. | CLPAREN overlay COMMA relationlist CRPAREN
  461. | CLPAREN overlay COMMA relation COMMA temporal CRPAREN
  462. | CLPAREN overlay COMMA relationlist COMMA temporal CRPAREN
  463. """
  464. if not self.optype == 'overlay':
  465. raise SyntaxError("invalid syntax")
  466. else:
  467. if len(t) == 4:
  468. # Set three operator components.
  469. self.relations = ['equal']
  470. self.temporal = "l"
  471. self.function = t[2]
  472. elif len(t) == 5:
  473. self.relations = ['equal']
  474. self.temporal = t[3]
  475. self.function = t[2]
  476. elif len(t) == 6:
  477. if isinstance(t[4], list):
  478. self.relations = t[4]
  479. else:
  480. self.relations = [t[4]]
  481. self.temporal = "l"
  482. self.function = t[2]
  483. elif len(t) == 8:
  484. if isinstance(t[4], list):
  485. self.relations = t[4]
  486. else:
  487. self.relations = [t[4]]
  488. self.temporal = t[6]
  489. self.function = t[2]
  490. t[0] = t[2]
  491. def p_relation(self, t):
  492. # The list of relations.
  493. """
  494. relation : EQUAL
  495. | FOLLOWS
  496. | PRECEDES
  497. | OVERLAPS
  498. | OVERLAPPED
  499. | DURING
  500. | STARTS
  501. | FINISHES
  502. | CONTAINS
  503. | STARTED
  504. | FINISHED
  505. """
  506. t[0] = t[1]
  507. def p_over(self, t):
  508. # The list of relations.
  509. """
  510. relation : OVER
  511. """
  512. over_list = ["overlaps", "overlapped"]
  513. t[0] = over_list
  514. def p_relationlist(self, t):
  515. # The list of relations.
  516. """
  517. relationlist : relation OR relation
  518. | relation OR relationlist
  519. """
  520. rel_list = []
  521. rel_list.append(t[1])
  522. if isinstance(t[3], list):
  523. rel_list = rel_list + t[3]
  524. else:
  525. rel_list.append(t[3])
  526. t[0] = rel_list
  527. def p_temporal_operator(self, t):
  528. # The list of relations.
  529. """
  530. temporal : LEFTREF
  531. | RIGHTREF
  532. | UNION
  533. | DISJOINT
  534. | INTERSECT
  535. """
  536. t[0] = t[1]
  537. def p_select_operator(self, t):
  538. # The list of relations.
  539. """
  540. select : T_SELECT
  541. | T_NOT_SELECT
  542. """
  543. t[0] = t[1]
  544. def p_arithmetic_operator(self, t):
  545. # The list of relations.
  546. """
  547. arithmetic : MOD
  548. | DIV
  549. | MULT
  550. | ADD
  551. | SUB
  552. """
  553. t[0] = t[1]
  554. def p_overlay_operator(self, t):
  555. # The list of relations.
  556. """
  557. overlay : AND
  558. | OR
  559. | XOR
  560. | DISOR
  561. | NOT
  562. """
  563. t[0] = t[1]
  564. ###############################################################################
  565. if __name__ == "__main__":
  566. import doctest
  567. doctest.testmod()