/*
* Copyright (C) INRIA, 2012-2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package fr.inrialpes.tyrexmo.qcwrapper.afmu;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.rdf.model.Model;
import afreemu.formula.BDDManager;
import afreemu.formula.Formula;
import afreemu.formula.SatCheck;
import afreemu.formula.UniqManager;
import afreemu.parser.AFEParser;
import afreemu.parser.ASTroot;
import afreemu.parser.ParseException;
import afreemu.util.TimeHistory;
import fr.inrialpes.tyrexmo.queryanalysis.CycleAnalysis;
import fr.inrialpes.tyrexmo.queryanalysis.TransformAlgebra;
import fr.inrialpes.tyrexmo.testqc.ContainmentTestException;
import fr.inrialpes.tyrexmo.testqc.LegacyContainmentSolver;
import fr.inrialpes.tyrexmo.testqc.simple.SimpleContainmentSolver;
import net.sf.javabdd.BDDFactory;
import net.sf.javabdd.BuDDyFactory;
public class AFMUContainmentWrapper
implements LegacyContainmentSolver, SimpleContainmentSolver
{
final static Logger logger = LoggerFactory.getLogger( AFMUContainmentWrapper.class );
/* This is to turn around the ugly implementation of reentrance */
protected static boolean firstTime = true;
protected static AFEParser parser;
/*kripke restriction \varphi_r */
private String theta = "<-s>spr & <p>spr & <o>spr & !<s>true & !<-p>true & !<-o>true";
private String eta = "!<-s>true & !<o>true & !<p>true & !<d>true & !<-d>true & !<s>spr & !<-p>spr & !<-o>spr";
private String kappa = "[-s]("+eta+") & [p]("+eta+") & [o]("+eta+")";
// This is necessary for reentrance of the program
//private final String phiR = "(let x1 = nu "+theta+" & "+kappa+" & (!<d>true | <d>x1) in x1 end)";
private static int recVarRank = 0;
protected String getPhiR() {
recVarRank++;
return "(let xp"+recVarRank+" = nu "+theta+" & "+kappa+" & (!<d>true | <d>xp"+recVarRank+") in xp"+recVarRank+" end)";
}
private String WarmupFormula = "((let v1 = mu ((<-s>varx & <p>takescourse & <o>course10)) | <d>v1 in v1 end) & (let v0 = mu ((<-s>varx & <p>takescourse & <o>course20)) | <d>v0 in v0 end)) & !((let v2 = mu ((<-s>varx & <p>takescourse & <o>course10)) | <d>v2 in v2 end))";
public void warmup() {
try {
checkSAT( WarmupFormula );
} catch ( Exception ex ) {
logger.warn( "Warm-up problem", ex );
};
};
public boolean entailed( Query q1, Query q2 ) throws ContainmentTestException {
return entailedUnderSchema( (String)null, q1, q2 );
}
public boolean entailedUnderSchema( Model schema, Query q1, Query q2 ) throws ContainmentTestException {
throw new ContainmentTestException( "Cannot deal with schema" );
};
public boolean entailedUnderSchema( String schema, Query q1, Query q2 ) throws ContainmentTestException {
// Encode formula
String formulaLeft, formulaRight;
if ( supportedTest( q1, q2 ) ) {
if ( useSameEncoding( q1, q2 ) ){
logger.warn("BOTH QUERYS ARE EQUAL - THE IMPLEMENTATION MIGHT BE BUGGED");
formulaLeft = new EncodeLHSQuery( q1 ).getFormula();
// JE : ??????? Fortunately, given the coding of useSameEncoding we barely go here!
formulaRight = new EncodeLHSQuery( q2 ).getFormula();
} else {
formulaLeft = new EncodeLHSQuery( q1 ).getFormula();
formulaRight = new EncodeRHSQuery( q2 ).getFormula();
}
} else {
throw new ContainmentTestException( "Cannot deal with such a test" );
}
//System.out.println(formulaLeft);
//System.out.println(formulaRight);
String formula = getPhiR() + " & (" + formulaLeft + ") & !("+ formulaRight + ")";
//String formula = "(" + formulaLeft + ") & !("+ formulaRight + ")";
if ( schema != null ) {
formula = new AxiomEncoder().encodeSchema( schema )+" & ("+formula+")";
}
//System.err.println(formula);
// Create checker
// Test it
try {
return checkSAT( formula );
} catch ( Exception ex ) {
throw new ContainmentTestException( "Error during Parsing formula", ex );
}
};
public void cleanup() {
//reset();
};
public static void reset() {
try {
Field field = Formula.class.getDeclaredField("instances");
field.setAccessible(true);
field.set(null, new UniqManager());
} catch(Exception e) {
throw new RuntimeException(e);
}
try {
Field field = BDDManager.class.getDeclaredField("factory");
field.setAccessible(true);
BDDFactory f = (BDDFactory)field.get(null);
//f.reset();
f.clearAllDomains();
f.clearVarBlocks();
f.clearError();
//field.set(null, null);
} catch(Exception e) {
throw new RuntimeException(e);
}
// try {
// Field field = BuDDyFactory.class.getDeclaredField("INSTANCE");
// field.setAccessible(true);
// BuDDyFactory f = (BuDDyFactory)field.get(null);
// if(f != null) {
// f.done();
// }
//
// //field.set(null, null);
// } catch(Exception e) {
// throw new RuntimeException(e);
// }
}
/*
* JE: Here I comment many things because I think that they are useless
*/
public boolean checkSAT( String phi ) throws ParseException {
TimeHistory.start();
if ( firstTime ) {
parser = new AFEParser( new StringReader( phi ) );
firstTime = false;
} else {
AFEParser.ReInit( new StringReader( phi ) );
}
ASTroot n = (ASTroot)AFEParser.root();
// n.dump("" + recVarRank + ": ");
Formula f = n.toFormula();
//Closure c = new Closure( f );
/*
int leansize = 0;
ArrayList<Scc> scc = c.getSccs();
ArrayList<Object> lean = new ArrayList<Object>();
for (Scc sccd: scc) {
if(!sccd.getLean().isEmpty()) {
for (int i = 0; i < sccd.getLean().size(); i++)
lean.add(sccd.getLean().get(i));
}
//lean.add(sccd.getLean());
leansize += sccd.getLean().size();
}
//System.out.println("L E A N");
//System.out.println(lean.toString());
//System.out.println("L E A N SIZE = ");
//System.out.println(leansize);
*/
SatCheck satcheck = new SatCheck( f );
boolean result = !satcheck.satisfiable();
reset();
return result;
}
protected boolean useSameEncoding( Query leftQuery, Query rightQuery ) {
return leftQuery.equals( rightQuery );
}
private boolean supportedTest( Query q1, Query q2 ) {
TransformAlgebra ta1 = new TransformAlgebra( q1 );
TransformAlgebra ta2 = new TransformAlgebra( q2 );
if ( containsOptional( ta1, ta2 ) || isValidQueryType( q1, q2 ) || isCyclic( ta1, ta2 ) || haveSameDistVar( q1, q2 ) )
return false;
else
return true;
}
private boolean containsOptional( TransformAlgebra left, TransformAlgebra right ) {
return ( left.containsOpt() || right.containsOpt() );
}
// This is the same...
private boolean isValidQueryType( Query leftQuery, Query rightQuery ) {
return (leftQuery.isConstructType() || rightQuery.isConstructType() ||
leftQuery.isDescribeType() || rightQuery.isDescribeType());
}
private boolean isCyclic( TransformAlgebra left, TransformAlgebra right ) {
CycleAnalysis l = new CycleAnalysis( left.getTriples() );
CycleAnalysis r = new CycleAnalysis( right.getTriples() );
return ( l.isCyclic() || r.isCyclic() );
}
// This is the same...
private boolean haveSameDistVar( Query leftQuery, Query rightQuery ) {
List<String> rightQueryDistVars = rightQuery.getResultVars();
Collections.sort(rightQueryDistVars);
List<String> leftQueryDistVars = leftQuery.getResultVars();
Collections.sort(leftQueryDistVars);
return !rightQueryDistVars.equals(leftQueryDistVars);
}
@Override
public boolean entailed(String queryStr1, String queryStr2) {
Query q1 = QueryFactory.create(queryStr1);
Query q2 = QueryFactory.create(queryStr2);
boolean result;
try {
result = entailed(q1, q2);
} catch (ContainmentTestException e) {
throw new RuntimeException(e);
}
return result;
}
}