PageRenderTime 43ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/jena-2.6.3/com/hp/hpl/jena/reasoner/rulesys/impl/Generator.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 427 lines | 208 code | 45 blank | 174 comment | 55 complexity | 8d6c9b0b9f9f4ab78c73aba117c76e26 MD5 | raw file
  1. /******************************************************************
  2. * File: Generator.java
  3. * Created by: Dave Reynolds
  4. * Created on: 06-Aug-2003
  5. *
  6. * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
  7. * [See end of file]
  8. * $Id: Generator.java,v 1.1 2009/06/29 08:55:33 castagna Exp $
  9. *****************************************************************/
  10. package com.hp.hpl.jena.reasoner.rulesys.impl;
  11. import java.util.*;
  12. import com.hp.hpl.jena.reasoner.TriplePattern;
  13. /**
  14. * A generator represents a set of memoized results for a single
  15. * tabled subgoal. The generator may be complete (in which case it just
  16. * contains the complete cached set of results for a goal), ready (not complete
  17. * but likely to product more results if called) or blocked (not complete and
  18. * awaiting results from a dependent generator).
  19. * <p>
  20. * Each generator may have multiple associated consumer choice points
  21. * representing different choices in satisfying the generator's goal.
  22. * </p>
  23. *
  24. * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
  25. * @version $Revision: 1.1 $ on $Date: 2009/06/29 08:55:33 $
  26. */
  27. public class Generator implements LPAgendaEntry, LPInterpreterContext {
  28. /** The intepreter instance which generates the results for this goal,
  29. * null if the generator is complete */
  30. protected LPInterpreter interpreter;
  31. /** The ordered set of results available for the goal */
  32. protected ArrayList<Object> results = new ArrayList<Object>();
  33. /** A indexed version of the result set, used while the generator is live
  34. * to detect duplicate results */
  35. protected Set<Object> resultSet;
  36. /** set to true if the dependent generator has new results ready for us */
  37. protected boolean isReady = true;
  38. /** set to true if at least one branch has block so an active readiness check is required */
  39. protected boolean checkReadyNeeded = false;
  40. /** The set of choice points producing results for us to use */
  41. protected Set<ConsumerChoicePointFrame> generatingCPs = new HashSet<ConsumerChoicePointFrame>();
  42. /** The list of active consumer choice points consuming results from this generator */
  43. protected Set<ConsumerChoicePointFrame> consumingCPs = new HashSet<ConsumerChoicePointFrame>();
  44. /** Flags whether the generator is live/dead/unknown during completion checking */
  45. protected LFlag completionState;
  46. /** The goal the generator is satisfying - just used in debugging */
  47. protected TriplePattern goal;
  48. /** True if this generator can produce at most one answer */
  49. protected boolean isSingleton;
  50. // /** Distance of generator from top level goal, used in scheduling */
  51. // protected int depth = DEFAULT_DEPTH;
  52. //
  53. // /** Default depth if not known */
  54. // public static final int DEFAULT_DEPTH = 100;
  55. /**
  56. * Constructor.
  57. *
  58. * @param interpreter an initialized interpreter instance that will answer
  59. * results for this generator.
  60. */
  61. public Generator(LPInterpreter interpreter, TriplePattern goal) {
  62. this.interpreter = interpreter;
  63. this.goal = goal; // Just used for debugging
  64. isSingleton = goal.isGround();
  65. if (!isSingleton) resultSet = new HashSet<Object>();
  66. }
  67. /**
  68. * Return the number of results available from this context.
  69. */
  70. public int numResults() {
  71. return results.size();
  72. }
  73. /**
  74. * Return true if the generator is ready to be scheduled (i.e. it is not
  75. * known to be complete and not known to be waiting for a dependent generator).
  76. */
  77. public boolean isReady() {
  78. if (isComplete()) return false;
  79. if (checkReadyNeeded) {
  80. isReady = false;
  81. for (Iterator<ConsumerChoicePointFrame> i = generatingCPs.iterator(); i.hasNext(); ) {
  82. if ( i.next().isReady() ) {
  83. isReady = true;
  84. break;
  85. }
  86. }
  87. checkReadyNeeded = false;
  88. return isReady;
  89. } else {
  90. return isReady;
  91. }
  92. }
  93. /**
  94. * Directly set that this generator is ready (because the generator
  95. * for one of its generatingCPs has produced new results).
  96. */
  97. public void setReady(ConsumerChoicePointFrame ccp) {
  98. if (!isComplete()) {
  99. interpreter.engine.schedule(ccp);
  100. isReady = true;
  101. checkReadyNeeded = false;
  102. }
  103. }
  104. /**
  105. * Return true if the generator is complete.
  106. */
  107. public boolean isComplete() {
  108. return interpreter == null;
  109. }
  110. // /**
  111. // * Return the estimated number of generators between the top level goal and this one.
  112. // */
  113. // public int getDepth() {
  114. // return depth;
  115. // }
  116. // /**
  117. // * Set the depth of this generator, it will not be propagated until
  118. // * a further depednents are found.
  119. // */
  120. // public void setDepth(int d) {
  121. // depth = d;
  122. // }
  123. /**
  124. * Signal that this generator is complete, no more results can be created.
  125. */
  126. public void setComplete() {
  127. if (!isComplete()) {
  128. interpreter.close();
  129. interpreter = null;
  130. resultSet = null;
  131. isReady = false;
  132. completionState = LFlag.DEAD;
  133. // Anyone we were generating results for is now finished
  134. for (Iterator<ConsumerChoicePointFrame> i = consumingCPs.iterator(); i.hasNext(); ) {
  135. ConsumerChoicePointFrame ccp = i.next();
  136. if ( ! ccp.isReady()) {
  137. ccp.setFinished();
  138. }
  139. }
  140. generatingCPs = null;
  141. consumingCPs.clear();
  142. }
  143. }
  144. /**
  145. * Add a new client choince point to consume results from this generator.
  146. */
  147. public void addConsumer(ConsumerChoicePointFrame ccp) {
  148. consumingCPs.add(ccp);
  149. // // Update distance from top goal
  150. // int newDepth = ccp.context == null ? 1 : ccp.context.getDepth() + 1;
  151. // if (newDepth < depth) depth = newDepth;
  152. }
  153. /**
  154. * Remove a terminated consuming choice point from the state set.
  155. */
  156. public void removeConsumer(ConsumerChoicePointFrame ccp) {
  157. consumingCPs.remove(ccp);
  158. // We used to set it complete if there were no consumers left.
  159. // However, a generator might be part of one query, incompletely consumed
  160. // and then opened again on a different query,
  161. // it seems better to omit this. TODO review
  162. // if (!isComplete() &&consumingCPs.isEmpty()) {
  163. // setComplete();
  164. // }
  165. }
  166. /**
  167. * Signal dependents that we have new results.
  168. */
  169. public void notifyResults() {
  170. LPBRuleEngine engine = interpreter.getEngine();
  171. for (Iterator<ConsumerChoicePointFrame> i = consumingCPs.iterator(); i.hasNext(); ) {
  172. ConsumerChoicePointFrame cons = i.next();
  173. cons.setReady();
  174. }
  175. }
  176. /**
  177. * Notify that the interpreter has now blocked on the given choice point.
  178. */
  179. public void notifyBlockedOn(ConsumerChoicePointFrame ccp) {
  180. generatingCPs.add(ccp);
  181. checkReadyNeeded = true;
  182. }
  183. /**
  184. * Notify this context that the given choice point has terminated
  185. * and can be remove from the wait list.
  186. */
  187. public void notifyFinished(ConsumerChoicePointFrame ccp) {
  188. if (generatingCPs != null) {
  189. generatingCPs.remove(ccp);
  190. }
  191. checkReadyNeeded = true;
  192. }
  193. /**
  194. * Start this generator running for the first time.
  195. * Should be called from within an appropriately synchronized block.
  196. */
  197. public void pump() {
  198. pump(this);
  199. }
  200. /**
  201. * Start this generator running from the given previous blocked generating
  202. * choice point.
  203. * Should be called from within an appropriately synchronized block.
  204. */
  205. public void pump(LPInterpreterState context) {
  206. if (isComplete()) return;
  207. interpreter.setState(context);
  208. int priorNresults = results.size();
  209. while (true) {
  210. Object result = interpreter.next();
  211. if (result == StateFlag.FAIL) {
  212. checkReadyNeeded = true;
  213. break;
  214. } else {
  215. // Simple triple result
  216. if (isSingleton) {
  217. results.add(result);
  218. isReady = false;
  219. break;
  220. } else if (resultSet.add(result)) {
  221. results.add(result);
  222. }
  223. }
  224. }
  225. if (results.size() > priorNresults) {
  226. notifyResults();
  227. }
  228. // Early termination check, close a singleton as soon as we have the ans
  229. if (isSingleton && results.size() == 1) {
  230. setComplete();
  231. }
  232. if (LPBRuleEngine.CYCLES_BETWEEN_COMPLETION_CHECK == 0) {
  233. checkForCompletions();
  234. }
  235. }
  236. /**
  237. * Return the generator associated with this entry (might be the entry itself)
  238. */
  239. public Generator getGenerator() {
  240. return this;
  241. }
  242. /**
  243. * Check for deadlocked states where none of the generators we are (indirectly)
  244. * dependent on can run.
  245. */
  246. public void checkForCompletions() {
  247. HashSet<Generator> visited = new HashSet<Generator>();
  248. if (runCompletionCheck(visited) != LFlag.LIVE) {
  249. postCompletionCheckScan(visited);
  250. }
  251. }
  252. /**
  253. * Check for deadlocked states across a collection of generators which have
  254. * been run.
  255. */
  256. public static void checkForCompletions(Collection<? extends Generator> completions) {
  257. HashSet<Generator> visited = new HashSet<Generator>();
  258. boolean atLeastOneZombie = false;
  259. for (Iterator<? extends Generator> i = completions.iterator(); i.hasNext(); ) {
  260. Generator g = i.next();
  261. if (g.runCompletionCheck(visited) != LFlag.LIVE) {
  262. atLeastOneZombie = true;
  263. }
  264. }
  265. if (atLeastOneZombie) {
  266. postCompletionCheckScan(visited);
  267. }
  268. }
  269. /**
  270. * Check whether this generator is live (indirectly dependent on a ready
  271. * generator), dead (complete) or in a deadlock loop which might or
  272. * might not be live (unknown).
  273. */
  274. protected LFlag runCompletionCheck(Set<Generator> visited) {
  275. if (isComplete()) return LFlag.DEAD;
  276. if (! visited.add(this)) return this.completionState;
  277. completionState = LFlag.UNKNOWN;
  278. if (isReady()) {
  279. completionState = LFlag.LIVE;
  280. } else {
  281. for (Iterator<ConsumerChoicePointFrame> i = generatingCPs.iterator(); i.hasNext(); ) {
  282. ConsumerChoicePointFrame ccp = i.next();
  283. if (ccp.isReady()) {
  284. completionState = LFlag.LIVE;
  285. break;
  286. } else if ( ccp.generator.runCompletionCheck(visited) == LFlag.LIVE) {
  287. completionState = LFlag.LIVE;
  288. break;
  289. }
  290. }
  291. }
  292. return completionState;
  293. }
  294. /**
  295. * Scan the result of a (set of) completion check(s) to detect which of the
  296. * unknowns are actually live and set the remaining (deadlocked) states
  297. * to complete.
  298. */
  299. protected static void postCompletionCheckScan(Set<Generator> visited ) {
  300. for (Iterator<Generator> iv = visited.iterator(); iv.hasNext(); ) {
  301. Generator g = iv.next();
  302. if (g.completionState == LFlag.LIVE) {
  303. for (Iterator<ConsumerChoicePointFrame> i = g.consumingCPs.iterator(); i.hasNext(); ) {
  304. LPInterpreterContext link = i.next().getConsumingContext();
  305. if (link instanceof Generator) {
  306. ((Generator)link).propagateLive(visited);
  307. }
  308. }
  309. }
  310. }
  311. for (Iterator<Generator> iv = visited.iterator(); iv.hasNext(); ) {
  312. Generator g = iv.next();
  313. if (g.completionState != LFlag.LIVE) {
  314. g.setComplete();
  315. }
  316. }
  317. return;
  318. }
  319. /**
  320. * Propagate liveness state forward to consuming generators, but only those
  321. * within the filter set.
  322. */
  323. protected void propagateLive(Set<Generator> filter) {
  324. if (completionState != LFlag.LIVE) {
  325. completionState = LFlag.LIVE;
  326. for (Iterator<ConsumerChoicePointFrame> i = consumingCPs.iterator(); i.hasNext(); ) {
  327. LPInterpreterContext link = i.next().getConsumingContext();
  328. if (link instanceof Generator) {
  329. ((Generator)link).propagateLive(filter);
  330. }
  331. }
  332. }
  333. }
  334. /**
  335. * Inner class used to flag generator states during completeness check.
  336. */
  337. private static class LFlag {
  338. /** Label for printing */
  339. private String label;
  340. public static final LFlag LIVE = new LFlag("Live");
  341. public static final LFlag DEAD = new LFlag("Dead");
  342. public static final LFlag UNKNOWN = new LFlag("Unknown");
  343. /** Constructor */
  344. private LFlag(String label) {
  345. this.label = label;
  346. }
  347. /** Print string */
  348. @Override
  349. public String toString() {
  350. return label;
  351. }
  352. }
  353. }
  354. /*
  355. (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
  356. All rights reserved.
  357. Redistribution and use in source and binary forms, with or without
  358. modification, are permitted provided that the following conditions
  359. are met:
  360. 1. Redistributions of source code must retain the above copyright
  361. notice, this list of conditions and the following disclaimer.
  362. 2. Redistributions in binary form must reproduce the above copyright
  363. notice, this list of conditions and the following disclaimer in the
  364. documentation and/or other materials provided with the distribution.
  365. 3. The name of the author may not be used to endorse or promote products
  366. derived from this software without specific prior written permission.
  367. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  368. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  369. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  370. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  371. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  372. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  373. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  374. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  375. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  376. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  377. */