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