| 1 | package felix.compiler; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.HashMap; |
| 5 | import java.util.HashSet; |
| 6 | import java.util.Iterator; |
| 7 | |
| 8 | import tuffy.mln.Literal; |
| 9 | import tuffy.mln.Term; |
| 10 | import tuffy.ra.Expression; |
| 11 | import tuffy.ra.Function; |
| 12 | import tuffy.util.ExceptionMan; |
| 13 | import tuffy.util.StringMan; |
| 14 | import tuffy.util.Timer; |
| 15 | |
| 16 | |
| 17 | import felix.dstruct.FelixClause; |
| 18 | import felix.dstruct.FelixPredicate; |
| 19 | import felix.dstruct.FelixQuery; |
| 20 | import felix.dstruct.FelixPredicate.FPProperty; |
| 21 | import felix.dstruct.StatOperator.OPType; |
| 22 | import felix.parser.FelixCommandOptions; |
| 23 | |
| 24 | /** |
| 25 | * The class of static analyzer that parses a given |
| 26 | * MLN program. It takes as input |
| 27 | * the whole MLN program, and assign properties to each |
| 28 | * predicate. Properties include |
| 29 | * whether a predicate is SYMM, REFLEX, TRANS etc., or |
| 30 | * whether a clause specifies a CRF |
| 31 | * chain etc. |
| 32 | * |
| 33 | * @author Ce Zhang |
| 34 | * |
| 35 | */ |
| 36 | public class StaticAnalyzer { |
| 37 | |
| 38 | /** |
| 39 | * Felix Query. |
| 40 | */ |
| 41 | FelixQuery fq; |
| 42 | |
| 43 | /** |
| 44 | * Command line options. |
| 45 | */ |
| 46 | FelixCommandOptions options; |
| 47 | |
| 48 | /** |
| 49 | * The constructor. |
| 50 | * @param _fq |
| 51 | * @param _opt |
| 52 | */ |
| 53 | public StaticAnalyzer(FelixQuery _fq, FelixCommandOptions _opt){ |
| 54 | fq = _fq; |
| 55 | options = _opt; |
| 56 | } |
| 57 | |
| 58 | |
| 59 | /** |
| 60 | * Analyze the input MLN program and assign properties to each predicate. |
| 61 | */ |
| 62 | public void parse(){ |
| 63 | |
| 64 | //classify clauses and register them to predicates |
| 65 | //Note: the invocation order matters! |
| 66 | this.parseKeyConstraintRelation(); |
| 67 | this.parseReflexiveRelation(); |
| 68 | this.parseSymmetricRelation(); |
| 69 | this.parseTransitiveRelation(); |
| 70 | this.parseChainRecursiveRelation(); |
| 71 | this.parseNonRecursiveRelation(); |
| 72 | this.parseOtherRecursiveRelation(); |
| 73 | this.parseSpecialPredicate(); |
| 74 | this.parseEmbededWeightRule(); |
| 75 | //this.parseSymmetricRelationPi2P(); |
| 76 | } |
| 77 | |
| 78 | /** |
| 79 | * Parse the predicate serves as the linear-representation of COREF. |
| 80 | */ |
| 81 | public void parseSpecialPredicate(){ |
| 82 | |
| 83 | for(FelixPredicate p : fq.getAllPred()){ |
| 84 | String name = p.getName(); |
| 85 | if(name.endsWith("_map")){ |
| 86 | |
| 87 | String oriName = name.replaceAll("_map$", ""); |
| 88 | |
| 89 | if(fq.getPredByName(oriName) == null){ |
| 90 | ExceptionMan.die("Cannot use predicate P_map without predicate P, please change to another name."); |
| 91 | } |
| 92 | |
| 93 | FelixPredicate orip = fq.getPredByName(oriName); |
| 94 | |
| 95 | if(orip.isClosedWorld()){ |
| 96 | ExceptionMan.die("Cannot use predicate P with predicate P as closed. Please change P to co-ref predicate, or" + |
| 97 | " change the name of P_map"); |
| 98 | } |
| 99 | |
| 100 | if(!p.isClosedWorld()){ |
| 101 | ExceptionMan.die("Cannot use predicate P_map with open-world setting. Plase change P_map to closed-world, or" + |
| 102 | " change the name of P_map"); |
| 103 | } |
| 104 | |
| 105 | orip.mustbe = OPType.COREF; |
| 106 | p.oriCorefPredicate = orip; |
| 107 | p.isCorefMapPredicate = true; |
| 108 | |
| 109 | orip.corefMAPPredicate = p; |
| 110 | |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Parse predicate with key constraints. |
| 118 | */ |
| 119 | public void parseKeyConstraintRelation(){ |
| 120 | |
| 121 | // get key constraint from predicate declaration |
| 122 | for(FelixPredicate fp : fq.getAllPred()){ |
| 123 | if(fp.hasDependentAttributes()){ |
| 124 | |
| 125 | Object[] _labelpos = fp.getLabelAttrPositions().toArray(); |
| 126 | int[] labelpos = new int[_labelpos.length]; |
| 127 | |
| 128 | for(int i=0;i<_labelpos.length;i++){ |
| 129 | labelpos[i] = (Integer) _labelpos[i]; |
| 130 | } |
| 131 | |
| 132 | fp.registerProperty( |
| 133 | FelixPredicate.FPProperty.KEY_CONSTRAINT, |
| 134 | null, |
| 135 | labelpos); |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | // discover rules like R(a,b1), [b1!=b2], => !R(a,b2) |
| 140 | for(FelixClause fc : fq.getAllClause()){ |
| 141 | |
| 142 | if(fc.getRegLiterals().size() != 2 || |
| 143 | fc.isHardClause() == false){ |
| 144 | continue; |
| 145 | } |
| 146 | |
| 147 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 148 | |
| 149 | for(Literal l : fc.getRegLiterals()){ |
| 150 | |
| 151 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 152 | |
| 153 | if(processedPred.contains(p)){ |
| 154 | continue; |
| 155 | } |
| 156 | |
| 157 | processedPred.add(p); |
| 158 | |
| 159 | if(p.isClosedWorld()){ |
| 160 | continue; |
| 161 | } |
| 162 | |
| 163 | Literal l1 = fc.getRegLiterals().get(0); |
| 164 | Literal l2 = fc.getRegLiterals().get(1); |
| 165 | |
| 166 | if(fc.getConstraints().size() != 1 || |
| 167 | l1.getPred().equals(l2.getPred()) == false){ |
| 168 | continue; |
| 169 | } |
| 170 | |
| 171 | Expression e = fc.getConstraints().get(0); |
| 172 | String var1 = "", var2 = ""; |
| 173 | |
| 174 | boolean eqNeqFlag = false; |
| 175 | if(e.getFunction() == Function.NOT){ |
| 176 | e = e.getArgs().get(0); |
| 177 | eqNeqFlag = true; |
| 178 | } |
| 179 | |
| 180 | if ( ( eqNeqFlag == false && e.getFunction() == Function.Neq ) || |
| 181 | ( eqNeqFlag == true && e.getFunction() == Function.Eq ) ){ |
| 182 | |
| 183 | if(l1.getSense() == true || l2.getSense() == true){ |
| 184 | continue; |
| 185 | } |
| 186 | |
| 187 | if(e.getArgs().size() != 2){ |
| 188 | continue; |
| 189 | } |
| 190 | |
| 191 | Expression e1 = e.getArgs().get(0); |
| 192 | Expression e2 = e.getArgs().get(1); |
| 193 | |
| 194 | if(e1.getFunction() != Function.VariableBinding |
| 195 | || e2.getFunction() != Function.VariableBinding){ |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | var1 = e1.toString(); |
| 200 | var2 = e2.toString(); |
| 201 | }else{ |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | //check |
| 206 | ArrayList<Term> ta = l1.getTerms(); |
| 207 | ArrayList<Term> tb = l2.getTerms(); |
| 208 | |
| 209 | if(ta.size() != tb.size()) continue; |
| 210 | |
| 211 | boolean isLR = true; |
| 212 | boolean isFirst = false; |
| 213 | int firstI = -1; |
| 214 | ArrayList<Integer> __labelpos = new ArrayList<Integer>(); |
| 215 | for(int i=0;i<ta.size();i++){ |
| 216 | if(ta.get(i).toString().equals(tb.get(i).toString()) == false){ |
| 217 | |
| 218 | if( (ta.get(i).toString().equals(var1) && tb.get(i).toString().equals(var2) && isFirst ==false) || |
| 219 | (tb.get(i).toString().equals(var1) && ta.get(i).toString().equals(var2) && isFirst ==false) ){ |
| 220 | firstI = i; |
| 221 | isFirst = true; |
| 222 | }else{ |
| 223 | isLR = false; |
| 224 | } |
| 225 | |
| 226 | __labelpos.add(i); |
| 227 | |
| 228 | }else{ |
| 229 | //__keypos.add(i); |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | if(firstI == -1 || isLR == false){ |
| 234 | continue; |
| 235 | } |
| 236 | |
| 237 | Object[] _labelpos = __labelpos.toArray(); |
| 238 | int[] labelpos = new int[_labelpos.length]; |
| 239 | |
| 240 | for(int i=0;i<_labelpos.length;i++){ |
| 241 | labelpos[i] = (Integer) _labelpos[i]; |
| 242 | } |
| 243 | |
| 244 | p.registerProperty( |
| 245 | FelixPredicate.FPProperty.KEY_CONSTRAINT, |
| 246 | fc, |
| 247 | labelpos); |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | } |
| 252 | |
| 253 | /** |
| 254 | * Generates all permutations of the given terms. |
| 255 | * @param terms |
| 256 | * @return |
| 257 | */ |
| 258 | public HashSet<ArrayList<String>> generateAllPermutations(HashSet<String> terms){ |
| 259 | HashSet<ArrayList<String>> ret = new HashSet<ArrayList<String>>(); |
| 260 | |
| 261 | if(terms.size() == 1){ |
| 262 | ArrayList<String> tmp = new ArrayList<String>(); |
| 263 | tmp.add(terms.iterator().next()); |
| 264 | ret.add(tmp); |
| 265 | return ret; |
| 266 | } |
| 267 | |
| 268 | for(String first : terms){ |
| 269 | |
| 270 | HashSet<String> newTerms = (HashSet<String>) terms.clone(); |
| 271 | newTerms.remove(first); |
| 272 | |
| 273 | HashSet<ArrayList<String>> others = this.generateAllPermutations(newTerms); |
| 274 | for(ArrayList<String> a : others){ |
| 275 | a.add(first); |
| 276 | ret.add(a); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | return ret; |
| 281 | } |
| 282 | |
| 283 | |
| 284 | /** |
| 285 | * Parse predicate which is symmetric. |
| 286 | */ |
| 287 | public void parseSymmetricRelation(){ |
| 288 | |
| 289 | for(FelixClause fc : fq.getAllClause()){ |
| 290 | |
| 291 | if(fc.getRegLiterals().size() != 2 || |
| 292 | fc.isHardClause() == false){ |
| 293 | continue; |
| 294 | } |
| 295 | |
| 296 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 297 | |
| 298 | for(Literal l : fc.getRegLiterals()){ |
| 299 | |
| 300 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 301 | |
| 302 | if(processedPred.contains(p)){ |
| 303 | continue; |
| 304 | } |
| 305 | |
| 306 | processedPred.add(p); |
| 307 | |
| 308 | if(p.isClosedWorld()){ |
| 309 | continue; |
| 310 | } |
| 311 | |
| 312 | Literal l1 = fc.getRegLiterals().get(0); |
| 313 | Literal l2 = fc.getRegLiterals().get(1); |
| 314 | |
| 315 | if(!l1.getPred().equals(l2.getPred())){ |
| 316 | continue; |
| 317 | } |
| 318 | |
| 319 | if(p.arity() != 2){ |
| 320 | continue; |
| 321 | } |
| 322 | |
| 323 | if(l1.getSense() != l2.getSense()){ |
| 324 | if(l1.getTerms().get(0).toString().equals(l2.getTerms().get(1).toString()) && |
| 325 | l1.getTerms().get(1).toString().equals(l2.getTerms().get(0).toString()) && |
| 326 | !l1.getTerms().get(1).toString().equals(l1.getTerms().get(0).toString())){ |
| 327 | p.registerProperty( |
| 328 | FPProperty.SYMM, |
| 329 | fc); |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | } |
| 337 | |
| 338 | /** |
| 339 | * Parse predicate which is reflexive. |
| 340 | */ |
| 341 | public void parseReflexiveRelation(){ |
| 342 | |
| 343 | for(FelixClause fc : fq.getAllClause()){ |
| 344 | |
| 345 | if(fc.getRegLiterals().size() != 1 || |
| 346 | fc.isHardClause() == false){ |
| 347 | continue; |
| 348 | } |
| 349 | |
| 350 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 351 | |
| 352 | for(Literal l : fc.getRegLiterals()){ |
| 353 | |
| 354 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 355 | |
| 356 | if(processedPred.contains(p)){ |
| 357 | continue; |
| 358 | } |
| 359 | |
| 360 | processedPred.add(p); |
| 361 | |
| 362 | if(p.isClosedWorld()){ |
| 363 | continue; |
| 364 | } |
| 365 | |
| 366 | if(l.getTerms().size() == 2 && |
| 367 | (l.getSense() == true)){ |
| 368 | if(l.getTerms().get(0).var() != null && |
| 369 | l.getTerms().get(0).var().equals(l.getTerms().get(1).var())){ |
| 370 | p.registerProperty( |
| 371 | FPProperty.REFLEX, |
| 372 | fc); |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | /** |
| 381 | * Parse predicate which is transitive. |
| 382 | */ |
| 383 | public void parseTransitiveRelation(){ |
| 384 | |
| 385 | for(FelixClause fc : fq.getAllClause()){ |
| 386 | |
| 387 | if(fc.getRegLiterals().size() != 3 || |
| 388 | fc.isHardClause() == false){ |
| 389 | continue; |
| 390 | } |
| 391 | |
| 392 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 393 | |
| 394 | for(Literal l : fc.getRegLiterals()){ |
| 395 | |
| 396 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 397 | |
| 398 | if(processedPred.contains(p)){ |
| 399 | continue; |
| 400 | } |
| 401 | |
| 402 | processedPred.add(p); |
| 403 | |
| 404 | if(p.arity() != 2){ |
| 405 | continue; |
| 406 | } |
| 407 | |
| 408 | if(p.isClosedWorld()){ |
| 409 | continue; |
| 410 | } |
| 411 | |
| 412 | if(fc.getRegLiterals().size() == 3){ |
| 413 | |
| 414 | ArrayList<Literal> ls = new ArrayList<Literal>(); |
| 415 | ls.add(fc.getRegLiterals().get(0)); |
| 416 | ls.add(fc.getRegLiterals().get(1)); |
| 417 | ls.add(fc.getRegLiterals().get(2)); |
| 418 | |
| 419 | if(!ls.get(0).getPred().equals(ls.get(1).getPred()) || |
| 420 | !ls.get(2).getPred().equals(ls.get(1).getPred()) || |
| 421 | !ls.get(0).getPred().equals(ls.get(2).getPred())){ |
| 422 | continue; |
| 423 | } |
| 424 | |
| 425 | int head = -1; |
| 426 | int[] aa = new int[2]; |
| 427 | int ct = 0; |
| 428 | for(int i=0;i<3;i++){ |
| 429 | if(ls.get(i).getSense() == true){ |
| 430 | if(head != -1){ |
| 431 | head = -1; |
| 432 | break; |
| 433 | } |
| 434 | head = i; |
| 435 | }else{ |
| 436 | if(ct < 2){ |
| 437 | aa[ct++] = i; |
| 438 | } |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | if(head == -1){ |
| 443 | continue; |
| 444 | } |
| 445 | |
| 446 | Literal l1 = ls.get(aa[0]); |
| 447 | Literal l2 = ls.get(aa[1]); |
| 448 | Literal h = ls.get(head); |
| 449 | |
| 450 | String common = ""; |
| 451 | String o1 = ""; |
| 452 | String o2 = ""; |
| 453 | for(int i=0;i<2;i++){ |
| 454 | for(int j=0;j<2;j++){ |
| 455 | if(l1.getTerms().get(i).toString().equals(l2.getTerms().get(j).toString())){ |
| 456 | common = l1.getTerms().get(i).toString(); |
| 457 | o1 = l1.getTerms().get((i+1)%2).toString(); |
| 458 | o2 = l2.getTerms().get((j+1)%2).toString(); |
| 459 | break; |
| 460 | } |
| 461 | } |
| 462 | if(common.equals("") == false){ |
| 463 | break; |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | if(common.equals("")){ |
| 468 | continue; |
| 469 | } |
| 470 | |
| 471 | if( h.getTerms().get(0).toString().equals(o1) && h.getTerms().get(1).toString().equals(o2) ){ |
| 472 | p.registerProperty( |
| 473 | FPProperty.TRANS, |
| 474 | fc); |
| 475 | } |
| 476 | |
| 477 | if( h.getTerms().get(1).toString().equals(o1) && h.getTerms().get(0).toString().equals(o2) ){ |
| 478 | p.registerProperty( |
| 479 | FPProperty.TRANS, |
| 480 | fc); |
| 481 | } |
| 482 | } |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | } |
| 487 | |
| 488 | /** |
| 489 | * Parse clause which specifies a CRF chain rule. |
| 490 | */ |
| 491 | public void parseChainRecursiveRelation(){ |
| 492 | |
| 493 | for(FelixClause fc : fq.getAllClause()){ |
| 494 | |
| 495 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 496 | |
| 497 | for(Literal l : fc.getRegLiterals()){ |
| 498 | |
| 499 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 500 | |
| 501 | if(processedPred.contains(p)){ |
| 502 | continue; |
| 503 | } |
| 504 | |
| 505 | processedPred.add(p); |
| 506 | |
| 507 | if(p.isClosedWorld()){ |
| 508 | continue; |
| 509 | } |
| 510 | |
| 511 | if(fc.getLiteralsOfPredicate(l.getPred()).size() != 2){ |
| 512 | continue; |
| 513 | } |
| 514 | |
| 515 | Literal l1 = fc.getLiteralsOfPredicate(l.getPred()).get(0); |
| 516 | Literal l2 = fc.getLiteralsOfPredicate(l.getPred()).get(1); |
| 517 | |
| 518 | boolean isCRFRule = true; |
| 519 | |
| 520 | int numberOfDifference = 0; |
| 521 | for(int i=0;i<l1.getTerms().size();i++){ |
| 522 | Term t1 = l1.getTerms().get(i); |
| 523 | Term t2 = l2.getTerms().get(i); |
| 524 | |
| 525 | if(t1.toString().equals(t2.toString())){ |
| 526 | // if these two terms are the same, good! |
| 527 | continue; |
| 528 | }else{ |
| 529 | // if not, we need to see whether in this rule, |
| 530 | // t1 and t2 is representing a chain. Here we know |
| 531 | // there can be only one label-field, so, only one |
| 532 | // such t1-t2 pair can exist. |
| 533 | |
| 534 | if(!p.getKeyPositions().contains(i)){ |
| 535 | continue; |
| 536 | } |
| 537 | |
| 538 | numberOfDifference ++; |
| 539 | |
| 540 | boolean isChain = false; |
| 541 | |
| 542 | // find in condition [t1 = t2 + 1] |
| 543 | //TODO: We may want to change it smarter in the future |
| 544 | for(Expression e : fc.getConstraints()){ |
| 545 | if(e.toString().equals(t1+" = (" + t2 + " + 1)") || |
| 546 | e.toString().equals(t2+" = (" + t1 + " + 1)") || |
| 547 | e.toString().equals("(" + t1 + " + 1) = " + t2) || |
| 548 | e.toString().equals("(" + t2 + " + 1) = " + t1) || |
| 549 | e.toString().equals(t1+" = (" + t2 + " - 1)") || |
| 550 | e.toString().equals(t2+" = (" + t1 + " - 1)") || |
| 551 | //TODO |
| 552 | e.toString().equals("(" + t1 + " - 1) = (" + t2 + " + 0)") || |
| 553 | e.toString().equals("(" + t2 + " - 1) = (" + t1 + " + 0)") || |
| 554 | e.toString().equals("(" + t1 + " - " + t2 + ") = " + 1) || |
| 555 | e.toString().equals(1 + " = (" + t1 + " - " + t2 + ")") || |
| 556 | e.toString().equals("(" + t2 + " - " + t1 + ") = " + 1) || |
| 557 | e.toString().equals(1 + " = (" + t2 + " - " + t1 + ")")){ |
| 558 | isChain = true; |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | if(!isChain){ |
| 563 | isCRFRule = false; |
| 564 | } |
| 565 | |
| 566 | if(numberOfDifference != 1){ |
| 567 | isCRFRule = false; |
| 568 | } |
| 569 | } |
| 570 | } |
| 571 | |
| 572 | if(isCRFRule == true && numberOfDifference > 0){ |
| 573 | if(p.getKeyPositions().size() != 0){ |
| 574 | p.registerProperty( |
| 575 | FPProperty.CHAIN_RECUR, |
| 576 | fc); |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | } |
| 581 | } |
| 582 | |
| 583 | } |
| 584 | |
| 585 | // rules other than special rules |
| 586 | /** |
| 587 | * Parse clause which does NOT specify 1) NON-RECURSIVE rule and |
| 588 | * 2) Chain rule. |
| 589 | * |
| 590 | */ |
| 591 | public void parseOtherRecursiveRelation(){ |
| 592 | for(FelixClause fc : fq.getAllClause()){ |
| 593 | |
| 594 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 595 | |
| 596 | HashSet<FelixPredicate> appeared = new HashSet<FelixPredicate>(); |
| 597 | |
| 598 | for(Literal l : fc.getRegLiterals()){ |
| 599 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 600 | |
| 601 | if(p.isClosedWorld()){ |
| 602 | continue; |
| 603 | } |
| 604 | |
| 605 | appeared.add(p); |
| 606 | } |
| 607 | |
| 608 | |
| 609 | |
| 610 | |
| 611 | for(Literal l : fc.getRegLiterals()){ |
| 612 | |
| 613 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 614 | |
| 615 | if(p.isClosedWorld()){ |
| 616 | continue; |
| 617 | } |
| 618 | |
| 619 | if(processedPred.contains(p)){ |
| 620 | continue; |
| 621 | } |
| 622 | |
| 623 | processedPred.add(p); |
| 624 | |
| 625 | if(appeared.size() == 1){ |
| 626 | if(fc.getLiteralsOfPredicate(l.getPred()).size() > 1){ |
| 627 | p.registerProperty( |
| 628 | FPProperty.OTHER_RECUR, |
| 629 | fc); |
| 630 | } |
| 631 | }else{ |
| 632 | if(fc.getLiteralsOfPredicate(l.getPred()).size() > 1){ |
| 633 | p.registerProperty( |
| 634 | FPProperty.OTHER_RECUR_WITHOTHER_OPENPRED, |
| 635 | fc); |
| 636 | } |
| 637 | } |
| 638 | |
| 639 | } |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | |
| 644 | /** |
| 645 | * Parse clause which specifies non-recursive rules. |
| 646 | */ |
| 647 | public void parseNonRecursiveRelation(){ |
| 648 | |
| 649 | for(FelixClause fc : fq.getAllClause()){ |
| 650 | |
| 651 | HashSet<FelixPredicate> processedPred = new HashSet<FelixPredicate>(); |
| 652 | |
| 653 | for(Literal l : fc.getRegLiterals()){ |
| 654 | |
| 655 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 656 | |
| 657 | if(p.isClosedWorld()){ |
| 658 | continue; |
| 659 | } |
| 660 | |
| 661 | if(processedPred.contains(p)){ |
| 662 | continue; |
| 663 | } |
| 664 | |
| 665 | processedPred.add(p); |
| 666 | |
| 667 | if(fc.getLiteralsOfPredicate(l.getPred()).size() == 1){ |
| 668 | p.registerProperty( |
| 669 | FPProperty.NON_RECUR, |
| 670 | fc); |
| 671 | } |
| 672 | |
| 673 | } |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | /** |
| 678 | * Parse clause whose weights are specified by embedded weight. |
| 679 | */ |
| 680 | public void parseEmbededWeightRule(){ |
| 681 | |
| 682 | for(FelixClause fc : fq.getAllClause()){ |
| 683 | |
| 684 | for(Literal l : fc.getRegLiterals()){ |
| 685 | |
| 686 | FelixPredicate p = fq.getPredByName(l.getPred().getName()); |
| 687 | |
| 688 | if(p.isClosedWorld()){ |
| 689 | continue; |
| 690 | } |
| 691 | |
| 692 | if(fc.hasEmbeddedWeight()){ |
| 693 | p.registerProperty(FPProperty.EMBED_WEIGHT_RULE, fc); |
| 694 | } |
| 695 | |
| 696 | } |
| 697 | |
| 698 | } |
| 699 | } |
| 700 | |
| 701 | } |