1 | package felix.operator; |
2 | |
3 | |
4 | import felix.dstruct.FelixClause; |
5 | import felix.dstruct.FelixPredicate; |
6 | import felix.dstruct.FelixQuery; |
7 | import felix.dstruct.StatOperator; |
8 | import felix.dstruct.FelixPredicate.FPProperty; |
9 | import felix.parser.FelixCommandOptions; |
10 | import felix.util.FelixConfig; |
11 | import felix.util.FelixUIMan; |
12 | |
13 | |
14 | import java.util.HashMap; |
15 | import java.util.HashSet; |
16 | |
17 | |
18 | |
19 | import tuffy.db.RDB; |
20 | import tuffy.ground.Grounding; |
21 | import tuffy.ground.KBMC; |
22 | import tuffy.ground.partition.PartitionScheme; |
23 | import tuffy.infer.DataMover; |
24 | import tuffy.infer.InferPartitioned; |
25 | import tuffy.infer.MRF; |
26 | import tuffy.mln.Clause; |
27 | import tuffy.mln.MarkovLogicNetwork; |
28 | import tuffy.mln.Predicate; |
29 | import tuffy.ra.ConjunctiveQuery; |
30 | import tuffy.ra.Expression; |
31 | import tuffy.util.Config; |
32 | import tuffy.util.Settings; |
33 | import tuffy.util.Timer; |
34 | import tuffy.util.UIMan; |
35 | |
36 | |
37 | /** |
38 | * A Tuffy operator in Felix. |
39 | * @author Ce Zhang |
40 | * |
41 | */ |
42 | public class TUFFYOperator extends StatOperator{ |
43 | |
44 | /** |
45 | * The grounding worker of this Tuffy operator. |
46 | */ |
47 | Grounding grounding; |
48 | |
49 | /** |
50 | * Markov logic network used by this Tuffy operator. |
51 | */ |
52 | MarkovLogicNetwork mln; |
53 | |
54 | /** |
55 | * The constructor of TUFFYOperator. |
56 | * @param _fq Felix query. |
57 | * @param _goalPredicates target predicates of this coref operator. |
58 | * @param _opt Command line options of this Felix run. |
59 | */ |
60 | public TUFFYOperator(FelixQuery _fq, HashSet<FelixPredicate> _goalPredicates, |
61 | FelixCommandOptions _opt) { |
62 | super(_fq, _goalPredicates, _opt); |
63 | this.type = OPType.TUFFY; |
64 | this.precedence = 1; |
65 | |
66 | for(FelixClause fc : this.allRelevantFelixClause){ |
67 | |
68 | int nOpen = 0; |
69 | |
70 | for(Predicate p : fc.getReferencedPredicates()){ |
71 | |
72 | if(!p.isClosedWorld() || p.getName().endsWith("_map")){ |
73 | this.commonCandidate.add(fq.getPredByName(p.getName())); |
74 | } |
75 | } |
76 | |
77 | } |
78 | |
79 | } |
80 | |
81 | boolean prepared = false; |
82 | |
83 | /** |
84 | * Prepares operator for execution. |
85 | */ |
86 | @Override |
87 | public void prepare() { |
88 | |
89 | if(!prepared){ |
90 | |
91 | UIMan.println(">>> Start Running " + this); |
92 | |
93 | try { |
94 | |
95 | |
96 | } catch (Exception e) { |
97 | e.printStackTrace(); |
98 | } |
99 | |
100 | prepared = true; |
101 | } |
102 | |
103 | } |
104 | |
105 | |
106 | /** |
107 | * Executes operator. |
108 | */ |
109 | @Override |
110 | public void run() { |
111 | |
112 | UIMan.println(">>> Start Running " + this); |
113 | |
114 | db = RDB.getRDBbyConfig(Config.db_schema); |
115 | |
116 | Timer.start("Timer - TUFFY - " + this.getId()); |
117 | |
118 | mln = new MarkovLogicNetwork(); |
119 | |
120 | mln.setDB(db); |
121 | |
122 | HashSet<Predicate> registeredPredicates = new HashSet<Predicate>(); |
123 | |
124 | HashMap<Predicate, Boolean> oriClosedWorld = new HashMap<Predicate, Boolean>(); |
125 | |
126 | |
127 | for(FelixPredicate fp : this.inputPredicates){ |
128 | oriClosedWorld.put(fp, fp.isClosedWorld()); |
129 | fp.setClosedWorld(true); |
130 | if(this.isMarginal){ |
131 | if(fp.isCorefPredicate == false && fp.isCorefMapPredicate == false){ |
132 | if(!options.useDualDecomposition || FelixConfig.isFirstRunOfDD){ |
133 | fp.setHasSoftEvidence(true); |
134 | }else{ |
135 | fp.setHasSoftEvidence(false); |
136 | } |
137 | } |
138 | } |
139 | |
140 | } |
141 | |
142 | for(Predicate fp : this.outputPredicates){ |
143 | oriClosedWorld.put(fp, fp.isClosedWorld()); |
144 | fp.setClosedWorld(this.currentState); |
145 | fp.setCompeletelySpecified(this.currentState); |
146 | |
147 | } |
148 | |
149 | for(FelixPredicate fp : this.dd_CommonOutput){ |
150 | |
151 | fp.setHasSoftEvidence(true); |
152 | fp.setCompeletelySpecified(true); |
153 | oriClosedWorld.put(fp, fp.isClosedWorld()); |
154 | fp.setClosedWorld(!this.currentState); |
155 | |
156 | } |
157 | |
158 | HashSet<FelixClause> allClause = allRelevantFelixClause; |
159 | allClause.addAll(this.dd_PriorClauses); |
160 | |
161 | for(FelixClause fc : this.allRelevantFelixClause){ |
162 | |
163 | boolean isNotUseful = true; |
164 | |
165 | Clause cloned = fc.clone(); |
166 | |
167 | if(this.clauseConstraints.get(fc) != null){ |
168 | |
169 | for(Expression e : this.clauseConstraints.get(fc)){ |
170 | cloned.getConstraints().add(e.clone()); |
171 | } |
172 | } |
173 | |
174 | mln.registerClause(cloned); |
175 | |
176 | for(Predicate fp : fc.getReferencedPredicates()){ |
177 | if(registeredPredicates.contains(fp)){ |
178 | continue; |
179 | } |
180 | fp.getRelatedClauses().clear(); |
181 | mln.registerPred(fp); |
182 | |
183 | registeredPredicates.add(fp); |
184 | } |
185 | |
186 | } |
187 | |
188 | for(ConjunctiveQuery sr : fq.getScopingRules()){ |
189 | mln.registerScopingRule(sr.clone()); |
190 | } |
191 | |
192 | mln.normalizeClauses(); |
193 | |
194 | for(Predicate p : mln.getAllPred()){ |
195 | p.setDB(db); |
196 | } |
197 | mln.finalizeClauseDefinitions(db); |
198 | |
199 | |
200 | //mln.prepareDB4Mobius(db); |
201 | |
202 | //mln.cleanUnknownPredTables(); |
203 | |
204 | KBMC kbmc = new KBMC(mln); |
205 | kbmc.run(); |
206 | mln.applyAllScopes(); |
207 | FelixUIMan.println(1, ">>> Marking queries..."); |
208 | mln.storeAllQueries(); |
209 | |
210 | grounding = new Grounding(mln); |
211 | grounding.constructMRF(); |
212 | |
213 | DataMover dmover = new DataMover(mln); |
214 | |
215 | if(options.maxFlips == 0){ |
216 | options.maxFlips = 10 * grounding.getNumAtoms(); |
217 | } |
218 | if(options.maxTries == 0){ |
219 | options.maxTries = 1; |
220 | } |
221 | |
222 | MRF mrf = null; |
223 | |
224 | if(options.disablePartition){ |
225 | if(!options.marginal || options.dual){ |
226 | UIMan.println(">>> Running MAP inference..."); |
227 | String mapfout = options.fout; |
228 | if(options.dual) mapfout += ".map"; |
229 | |
230 | UIMan.println(" Loading MRF from DB to RAM..."); |
231 | mrf = dmover.loadMrfFromDb(mln.relAtoms, mln.relClauses); |
232 | mrf.inferWalkSAT(options.maxTries, options.maxFlips); |
233 | dmover.flushAtomStates(mrf.atoms.values(), mln.relAtoms); |
234 | |
235 | UIMan.println("### Best answer has cost " + UIMan.decimalRound(2,mrf.lowCost)); |
236 | //UIMan.println(">>> Writing answer to file: " + mapfout); |
237 | //dmover.dumpTruthToFile(mln.relAtoms, mapfout); |
238 | } |
239 | |
240 | if(options.marginal || options.dual){ |
241 | UIMan.println(">>> Running marginal inference..."); |
242 | String mfout = options.fout; |
243 | if(options.dual) mfout += ".marginal"; |
244 | |
245 | if(mrf == null){ |
246 | mrf = new MRF(mln); |
247 | dmover.loadMrfFromDb(mrf, mln.relAtoms, mln.relClauses); |
248 | } |
249 | |
250 | double sumCost = mrf.mcsat(options.mcsatSamples, options.maxFlips); |
251 | dmover.flushAtomStates(mrf.atoms.values(), mln.relAtoms); |
252 | |
253 | UIMan.println("### Average Cost = " + UIMan.decimalRound(2,sumCost/options.mcsatSamples)); |
254 | |
255 | //UIMan.println(">>> Writing answer to file: " + mfout); |
256 | //dmover.dumpProbsToFile(mln.relAtoms, mfout); |
257 | } |
258 | }else{ |
259 | |
260 | InferPartitioned ip = new InferPartitioned(grounding, dmover); |
261 | PartitionScheme pmap = ip.getPartitionScheme(); |
262 | int ncomp = pmap.numComponents(); |
263 | int nbuck = ip.getNumBuckets(); |
264 | String sdata = UIMan.comma(ncomp) + (ncomp > 1 ? " components" : "component"); |
265 | sdata += " (grouped into "; |
266 | sdata += UIMan.comma(nbuck) + (nbuck > 1 ? " buckets" : " bucket)"); |
267 | |
268 | |
269 | Settings settings = new Settings(); |
270 | Double fpa = ((double)options.maxFlips)/grounding.getNumAtoms(); |
271 | |
272 | if(!options.marginal || options.dual){ |
273 | UIMan.println(">>> Running MAP inference on " + sdata); |
274 | String mapfout = options.fout; |
275 | if(options.dual) mapfout += ".map"; |
276 | |
277 | settings.put("task", "MAP"); |
278 | settings.put("ntries", new Integer(options.maxTries)); |
279 | settings.put("flipsPerAtom", fpa); |
280 | double lowCost = ip.infer(settings); |
281 | |
282 | UIMan.println("### Best answer has cost " + UIMan.decimalRound(2,lowCost)); |
283 | //UIMan.println(">>> Writing answer to file: " + mapfout); |
284 | //dmover.dumpTruthToFile(mln.relAtoms, mapfout); |
285 | } |
286 | |
287 | if(options.marginal || options.dual){ |
288 | UIMan.println(">>> Running marginal inference on " + sdata); |
289 | String mfout = options.fout; |
290 | if(options.dual) mfout += ".marginal"; |
291 | |
292 | settings.put("task", "MARGINAL"); |
293 | settings.put("nsamples", new Integer(options.mcsatSamples)); |
294 | settings.put("flipsPerAtom", fpa); |
295 | double aveCost = ip.infer(settings); |
296 | |
297 | UIMan.println("### Average Cost = " + UIMan.decimalRound(2,aveCost)); |
298 | |
299 | //UIMan.println(">>> Writing answer to file: " + mfout); |
300 | //dmover.dumpProbsToFile(mln.relAtoms, mfout); |
301 | } |
302 | |
303 | } |
304 | |
305 | this.belongsToBucket.addMLNRelTable(mln.relAtoms); |
306 | |
307 | for(Predicate fp : oriClosedWorld.keySet()){ |
308 | fp.setClosedWorld(oriClosedWorld.get(fp)); |
309 | } |
310 | |
311 | FelixUIMan.println(0,0,">>> {" + this + "} uses " + Timer.elapsed("Timer - TUFFY - " + this.getId())); |
312 | FelixUIMan.println(0, 0, ""); |
313 | |
314 | //System.out.println("--------------[Timer - TUFFY - " + this.getId() + "]: " + |
315 | // Timer.elapsed("Timer - TUFFY - " + this.getId())); |
316 | |
317 | db.close(); |
318 | |
319 | if(!options.useDualDecomposition){ |
320 | this.belongsToBucket.runNextOperatorInBucket(); |
321 | } |
322 | |
323 | } |
324 | |
325 | @Override |
326 | public String explain() { |
327 | return null; |
328 | } |
329 | |
330 | @Override |
331 | public void learn() { |
332 | |
333 | } |
334 | |
335 | } |