All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.rdf.rules.TestTruthMaintenance Maven / Gradle / Ivy

There is a newer version: 2.1.4
Show newest version
/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     [email protected]

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

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 General Public License for more details.

You should have received a copy of the GNU 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
*/
/*
 * Created on Nov 5, 2007
 */

package com.bigdata.rdf.rules;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.Set;

import org.apache.log4j.MDC;
import org.openrdf.model.URI;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.OWL;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.rio.RDFFormat;

import com.bigdata.rdf.inf.TruthMaintenance;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.model.BigdataStatement;
import com.bigdata.rdf.model.BigdataURI;
import com.bigdata.rdf.model.BigdataValue;
import com.bigdata.rdf.model.BigdataValueFactory;
import com.bigdata.rdf.model.StatementEnum;
import com.bigdata.rdf.rio.StatementBuffer;
import com.bigdata.rdf.spo.ExplicitSPOFilter;
import com.bigdata.rdf.spo.ISPO;
import com.bigdata.rdf.spo.SPO;
import com.bigdata.rdf.spo.SPOComparator;
import com.bigdata.rdf.spo.SPOKeyOrder;
import com.bigdata.rdf.store.AbstractTripleStore;
import com.bigdata.rdf.store.DataLoader;
import com.bigdata.rdf.store.TempTripleStore;
import com.bigdata.rdf.store.AbstractTripleStore.Options;
import com.bigdata.rdf.store.DataLoader.ClosureEnum;
import com.bigdata.relation.accesspath.IAccessPath;
import com.bigdata.striterator.ChunkedArrayIterator;
import com.bigdata.striterator.IChunkedIterator;
import com.bigdata.striterator.IChunkedOrderedIterator;

/**
 * Test suite for {@link TruthMaintenance}.
 * 
 * @todo add a stress test where we assert random statements and then back out
 *       those assertions verifying that we recover the original closure?
 * 
 * @todo run for both full and fast closure programs.
 * 
 * @author Bryan Thompson
 * @version $Id$
 */
public class TestTruthMaintenance extends AbstractInferenceEngineTestCase {

    /**
     * 
     */
    public TestTruthMaintenance() {
        super();
    }

    /**
     * @param name
     */
    public TestTruthMaintenance(String name) {
        super(name);
    }

    final private Random r = new Random();

    /**
     * Test for
     * {@link TruthMaintenance#applyExistingStatements(AbstractTripleStore, AbstractTripleStore, IElementFilter filter)}.
     */
    public void test_filter_01() {

        TempTripleStore focusStore = null;
        final AbstractTripleStore store = getStore();

        try {

            /*
             * Setup some terms.
             */

            final BigdataValueFactory f = store.getValueFactory();

            final BigdataURI x = f.createURI("http://www.foo.org/x1");
            final BigdataURI y = f.createURI("http://www.foo.org/y2");
            final BigdataURI z = f.createURI("http://www.foo.org/z3");
            
            store.addTerms(new BigdataValue[] { x, y, z });
            
            final IV x1 = x.getIV();
            final IV y2 = y.getIV();
            final IV z3 = z.getIV();
            
            /*
             * Setup the database.
             */
            {

                final SPO[] a = new SPO[] {
                
                        new SPO(x1, y2, z3, StatementEnum.Inferred),
                
                        new SPO(y2, y2, z3, StatementEnum.Explicit)
                        
                };
                
                store.addStatements(a, a.length);

                assertTrue(store.hasStatement(x1, y2, z3));
                assertTrue(store.getStatement(x1, y2, z3).isInferred());
                
                assertTrue(store.hasStatement(y2, y2, z3));
                assertTrue(store.getStatement(y2, y2, z3).isExplicit());

//                nbefore = store.getStatementCount();

            }
            
            /*
             * Setup a temporary store.
             */
            {

                final Properties properties = store.getProperties();
                
                properties.setProperty(Options.LEXICON, "false");
                
                focusStore = new TempTripleStore( properties );
                
//                SPOAssertionBuffer buf = new SPOAssertionBuffer(focusStore, store,
//                        null/* filter */, 100/* capacity */, false/* justified */);

                final SPO[] a = new SPO[] {
                
                // should be applied to the database since already there as inferred.
                new SPO(x1, y2, z3, StatementEnum.Explicit),
                
                // should be applied to the database since already there as explicit.
                new SPO(y2, y2, z3, StatementEnum.Explicit),

                // should not be applied to the database since not there at all.
                new SPO(z3, y2, z3, StatementEnum.Explicit),

                };
                
                /*
                 * add statement to the focusStore and do NOT use the focusStore
                 * lexicon (it does not exist) to assign sids to the statements.
                 */
                store.addStatements(focusStore, true/* copyOnly */,
                                new ChunkedArrayIterator(a.length, a, null/* keyOrder */),
                                null/* filter */);
                
                assertTrue(focusStore.hasStatement(x1, y2, z3));
                assertTrue(focusStore.getStatement(x1, y2, z3).isExplicit());
                
                assertTrue(focusStore.hasStatement(y2, y2, z3));
                assertTrue(focusStore.getStatement(y2, y2, z3).isExplicit());
                
                assertTrue(focusStore.hasStatement(z3, y2, z3));
                assertTrue(focusStore.getStatement(z3, y2, z3).isExplicit());

//                assertEquals(nbefore + 1, focusStore.getStatementCount());

            }

            /*
             * For each (explicit) statement in the focusStore that also exists
             * in the database: (a) if the statement is not explicit in the
             * database then mark it as explicit; and (b) remove the statement
             * from the focusStore.
             */
            
            final int nremoved = TruthMaintenance.applyExistingStatements(
                    focusStore, store, null/*filter*/);

            // statement was pre-existing and was converted from inferred to explicit.
            assertTrue(store.hasStatement(x1, y2, z3));
            assertTrue(store.getStatement(x1, y2, z3).isExplicit());
            
            // statement was pre-existing as "explicit" so no change.
            assertTrue(store.hasStatement(y2, y2, z3));
            assertTrue(store.getStatement(y2, y2, z3).isExplicit());

//            assertEquals(nbefore, focusStore.getExactStatementCount());
            
            assertEquals("#removed", 1, nremoved);
            
        } finally {

            if (focusStore != null)
                focusStore.__tearDownUnitTest();
            
            store.__tearDownUnitTest();
            
        }
        
    }
    
    /**
     * A simple test of {@link TruthMaintenance} in which some statements are
     * asserted and their closure is computed and aspects of that closure are
     * verified (this is based on rdfs11).
     */
    public void test_assertAll_01() {

        TempTripleStore tempStore = null;
        final AbstractTripleStore store = getStore();
        
        try {
            
            final TruthMaintenance tm = new TruthMaintenance(store.getInferenceEngine());
            
            final BigdataValueFactory f = store.getValueFactory();
            
            final BigdataURI U = f.createURI("http://www.bigdata.com/U");
            final BigdataURI V = f.createURI("http://www.bigdata.com/V");
            final BigdataURI X = f.createURI("http://www.bigdata.com/X");

            final BigdataURI rdfsSubClassOf = f.asValue(RDFS.SUBCLASSOF);

            tempStore = tm.newTempTripleStore();

            // buffer writes on the tempStore.
            {

                final StatementBuffer assertionBuffer = new StatementBuffer(
                        tempStore, store, 10/* capacity */, 10/*queueCapacity*/);

                assertTrue(tempStore == assertionBuffer.getStatementStore());
                
                assertionBuffer.add(U, rdfsSubClassOf, V);
                assertionBuffer.add(V, rdfsSubClassOf, X);

                // flush to the temp store.
                assertionBuffer.flush();
                
            }

            if (log.isInfoEnabled())
                log.info("\n\ntempStore:\n"
                        + tempStore.dumpStore(store,
                                true, true, false, true));

            // perform closure and write on the database.
            tm.assertAll(tempStore);

            if (log.isInfoEnabled())
                log.info("\n\ndatabase:\n"
                        + store.dumpStore(store, true, true, false, true));
            
            // explicit.
            assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
            assertTrue(store.hasStatement(V, rdfsSubClassOf, X));

            // inferred.
            assertTrue(store.hasStatement(U, rdfsSubClassOf, X));
            
        } finally {
        // Note: This will be torn down with the [store].
//            if (tempStore != null)
//                tempStore.__tearDownUnitTest();
            
            store.__tearDownUnitTest();
            
        }
        
    }

    /**
     * A simple test of {@link TruthMaintenance} in which some statements are
     * asserted, their closure is computed and aspects of that closure are
     * verified, and then an explicit statement is removed and the closure is
     * updated and we verify that an entailment known to depend on the remove
     * statement has also been removed (this is based on rdfs11).
     * 
     * @todo do a variant test where we remove more than one support at once in
     *       a case where the at least one of the statements entails the other
     *       and verify that both statements are removed (ie, verify that
     *       isGrounded is NOT accepting as grounds any support that is in the
     *       focusStore). This test could actually be done in
     *       {@link TestJustifications}.
     */
    public void test_retractAll_01() {
        
        final AbstractTripleStore store = getStore();
        
        try {

            final BigdataValueFactory f = store.getValueFactory();
            
            final BigdataURI U = f.createURI("http://www.bigdata.com/U");
            final BigdataURI V = f.createURI("http://www.bigdata.com/V");
            final BigdataURI X = f.createURI("http://www.bigdata.com/X");

            final BigdataURI rdfsSubClassOf = f.asValue(RDFS.SUBCLASSOF);

            final InferenceEngine inf = store.getInferenceEngine();

            final TruthMaintenance tm = new TruthMaintenance(inf);

            // add some assertions and verify aspects of their closure.
            {
            
                final StatementBuffer assertionBuffer = new StatementBuffer(tm
                        .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/);

                assertionBuffer.add(U, rdfsSubClassOf, V);
                assertionBuffer.add(V, rdfsSubClassOf, X);

                // flush statements to the temp store.
                assertionBuffer.flush();
                
                // perform closure and write on the database.
                tm.assertAll((TempTripleStore) assertionBuffer
                        .getStatementStore());

                // explicit.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
                assertTrue(store.hasStatement(V, rdfsSubClassOf, X));

                // inferred.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, X));

            }
            
            /*
             * retract one of the explicit statements and update the closure.
             * 
             * then verify that it is retracted statement is gone, that the
             * entailed statement is gone, and that the other explicit statement
             * was not touched.
             */
            {
                
                final StatementBuffer retractionBuffer = new StatementBuffer(tm
                        .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/);

                retractionBuffer.add(V, rdfsSubClassOf, X);

                // flush buffer to temp store.
                retractionBuffer.flush();
                
                // update the closure.
                tm.retractAll((TempTripleStore) retractionBuffer
                        .getStatementStore());
                
                // explicit.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
                assertFalse(store.hasStatement(V, rdfsSubClassOf, X));

                // inferred.
                assertFalse(store.hasStatement(U, rdfsSubClassOf, X));
                
            }

            /*
             * Add the retracted statement back in and verify that we get the
             * entailment back.
             */
            {
                
                final StatementBuffer assertionBuffer = new StatementBuffer(tm
                        .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/);
                
                assertionBuffer.add(V, rdfsSubClassOf, X);
                
                // flush to the temp store.
                assertionBuffer.flush();

                // update the closure.
                tm.assertAll((TempTripleStore)assertionBuffer.getStatementStore());

                // explicit.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
                assertTrue(store.hasStatement(V, rdfsSubClassOf, X));

                // inferred.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, X));

            }

            /*
             * Retract the entailment and verify that it is NOT removed from the
             * database (removing an inference has no effect).
             */
            {
                
                final StatementBuffer retractionBuffer = new StatementBuffer(tm
                        .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/);

                retractionBuffer.add(U, rdfsSubClassOf, X);

                // flush to the temp store.
                retractionBuffer.flush();
                
                // update the closure.
                tm.retractAll((TempTripleStore)retractionBuffer.getStatementStore());

                // explicit.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
                assertTrue(store.hasStatement(V, rdfsSubClassOf, X));

                // inferred.
                assertTrue(store.hasStatement(U, rdfsSubClassOf, X));

            }
            
        } finally {
            
            store.__tearDownUnitTest();
            
        }
        
    }

    /**
     * A simple test of {@link TruthMaintenance} in which some statements are
     * asserted, including one statement which is also produced as an inference,
     * and their closure is computed and aspects of that closure are verified
     * (this is based on rdfs11). After we verify the closure, we retract the
     * explicit statement and then verify that the closure was updated such that
     * the statement was downgraded to an inference.
     */
    public void test_downgradeExplicitToInference() {
        
        final AbstractTripleStore store = getStore();
        
        try {
            
            final TruthMaintenance tm = new TruthMaintenance(store.getInferenceEngine());

            final BigdataValueFactory f = store.getValueFactory();

            final BigdataURI U = f.createURI("http://www.bigdata.com/U");
            final BigdataURI V = f.createURI("http://www.bigdata.com/V");
            final BigdataURI X = f.createURI("http://www.bigdata.com/X");

            final BigdataURI rdfsSubClassOf = f.asValue(RDFS.SUBCLASSOF);

            {

                // Note: new triple store on shared temporary store!
                final TempTripleStore tempStore = tm.newTempTripleStore();
                // buffer writes on the tempStore.
                {

                    final StatementBuffer assertionBuffer = new StatementBuffer(
                            tempStore, store, 10/* capacity */, 10/*queueCapacity*/);

                    assertTrue(tempStore == assertionBuffer.getStatementStore());

                    assertionBuffer.add(U, rdfsSubClassOf, V);
                    assertionBuffer.add(V, rdfsSubClassOf, X);

                    /*
                     * Note: this statement is entailed by the other two, but we
                     * represent it explicitly as well in order to test the
                     * downgrade mechanism.
                     */
                    assertionBuffer.add(U, rdfsSubClassOf, X);

                    // flush to the temp store.
                    assertionBuffer.flush();

                }

                if (log.isInfoEnabled())
                    log.info("\n\ntempStore:\n"
                            + tempStore.dumpStore(store, true, true, false,
                                    true));

                if (log.isInfoEnabled())
                    log.info("Doing asserts.");

                // perform closure and write on the database.
                tm.assertAll(tempStore);

            }

            if (log.isInfoEnabled())
                log.info("\n\ndatabase:\n"
                        + store.dumpStore(store, true, true, false, true));
            
            // verify statements exist.
            assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
            assertTrue(store.hasStatement(V, rdfsSubClassOf, X));
            assertTrue(store.hasStatement(U, rdfsSubClassOf, X));

            // and verify their statement type.
            assertEquals(StatementEnum.Explicit, store.getStatement(U,
                    rdfsSubClassOf, V).getStatementType());
            assertEquals(StatementEnum.Explicit, store.getStatement(V,
                    rdfsSubClassOf, X).getStatementType());
            assertEquals(StatementEnum.Explicit, store.getStatement(U,
                    rdfsSubClassOf, X).getStatementType());

            // now retract
            {

                // Note: new triple store on shared temporary store!
                final TempTripleStore tempStore = tm.newTempTripleStore();
                // buffer writes on the tempStore.
                {

                    final StatementBuffer retractionBuffer = new StatementBuffer(
                            tempStore, store, 10/* capacity */, 10/*queueCapacity*/);

                    assertTrue(tempStore == retractionBuffer
                            .getStatementStore());

                    /*
                     * Retract this statement. It is explicitly present in the
                     * DB. However, note that it is also inferred. Therefore, it
                     * MUST be downgraded to an inference.
                     */
                    retractionBuffer.add(U, rdfsSubClassOf, X);

                    // flush to the temp store.
                    retractionBuffer.flush();

                }

                if (log.isInfoEnabled())
                    log.info("\n\ntempStore:\n"
                            + tempStore.dumpStore(store, true, true, false,
                                    true));

                if (log.isInfoEnabled())
                    log.info("Doing retraction.");

                // perform closure and write on the database.
                tm.retractAll(tempStore);

            }

            if (log.isInfoEnabled())
                log.info("\n\ndatabase:\n"
                        + store.dumpStore(store, true, true, false, true));
            
            // verify statements exist.
            assertTrue(store.hasStatement(U, rdfsSubClassOf, V));
            assertTrue(store.hasStatement(V, rdfsSubClassOf, X));
            assertTrue(store.hasStatement(U, rdfsSubClassOf, X));

            // and verify their statement type. 
            assertEquals(StatementEnum.Explicit, store.getStatement(U,
                    rdfsSubClassOf, V).getStatementType());
            assertEquals(StatementEnum.Explicit, store.getStatement(V,
                    rdfsSubClassOf, X).getStatementType());
            assertEquals(StatementEnum.Inferred, store.getStatement(U,
                    rdfsSubClassOf, X).getStatementType());

        } finally {
            
            store.__tearDownUnitTest();
            
        }
        
    }

    /**
     * Given three explicit statements:
     * 
     * 
     *  stmt a:  #user #currentGraph #foo
     *  
     *  stmt b: #currentGraph rdfs:range #Graph
     *  
     *  stmt c: #foo rdf:type #Graph
     * 
* * a+b implies c *

* Delete a and verify that c is NOT gone since it is an explicit statement. */ public void test_retractWhenStatementSupportsExplicitStatement() { URI user = new URIImpl("http://www.bigdata.com/user"); URI currentGraph = new URIImpl("http://www.bigdata.com/currentGraph"); URI foo = new URIImpl("http://www.bigdata.com/foo"); URI graph = new URIImpl("http://www.bigdata.com/Graph"); URI rdftype = RDF.TYPE; URI rdfsRange = RDFS.RANGE; AbstractTripleStore store = getStore(); try { final InferenceEngine inf = store.getInferenceEngine(); final TruthMaintenance tm = new TruthMaintenance(inf); // add some assertions and verify aspects of their closure. { final StatementBuffer assertionBuffer = new StatementBuffer(tm .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/); // stmt a assertionBuffer.add(user, currentGraph, foo ); // stmt b assertionBuffer.add(currentGraph, rdfsRange, graph ); // stmt c assertionBuffer.add(foo, rdftype, graph ); // flush to the temp store. assertionBuffer.flush(); // perform closure and write on the database. tm.assertAll((TempTripleStore)assertionBuffer.getStatementStore()); // dump after closure. if (log.isInfoEnabled()) log.info("\n" + store.dumpStore(true, true, false)); // explicit. assertTrue(store.hasStatement(user, currentGraph, foo )); assertTrue(store.hasStatement(currentGraph, rdfsRange, graph )); assertTrue(store.hasStatement(foo, rdftype, graph)); // verify that stmt c is marked as explicit in the kb. final BigdataStatement stmtC = (BigdataStatement) store .getStatement(foo, rdftype, graph); assertNotNull(stmtC); assertEquals(StatementEnum.Explicit, stmtC.getStatementType()); } /* * retract stmt A and update the closure. * * then verify that it is retracted statement is gone and that the * other explicit statements were not touched. */ { final StatementBuffer retractionBuffer = new StatementBuffer(tm .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/); retractionBuffer.add(user, currentGraph, foo); // flush to the temp store. retractionBuffer.flush(); // update the closure. tm.retractAll( (TempTripleStore)retractionBuffer.getStatementStore()); // dump after re-closure. if (log.isInfoEnabled()) log.info("\n" + store.dumpStore(true, true, false)); // test the kb. assertFalse(store.hasStatement(user, currentGraph, foo)); assertTrue(store.hasStatement(currentGraph, rdfsRange, graph)); assertTrue(store.hasStatement(foo, rdftype, graph)); // verify that stmt c is marked as explicit in the kb. final BigdataStatement stmtC = (BigdataStatement) store .getStatement(foo, rdftype, graph); assertNotNull(stmtC); assertEquals(StatementEnum.Explicit, stmtC.getStatementType()); } } finally { store.__tearDownUnitTest(); } } /** * This test demonstrates TM incorrectness (since fixed of course). I add * two statements into store A, then remove one of them. Then I add the the * statement that remain in store A into store B and compare the closure of * the stores. They should be the same, right? Well, unfortunately they are * not the same. Too many inferences were deleted from the first store * during TM. */ public void test_closurecorrectness() { final URI a = new URIImpl("http://www.bigdata.com/a"); final URI b = new URIImpl("http://www.bigdata.com/b"); final URI c = new URIImpl("http://www.bigdata.com/c"); // final URI d = new URIImpl("http://www.bigdata.com/d"); final URI sco = RDFS.SUBCLASSOF; final AbstractTripleStore store = getStore(); try { final TruthMaintenance tm = new TruthMaintenance(store .getInferenceEngine()); // add two { final StatementBuffer assertionBuffer = new StatementBuffer(tm .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/); assertionBuffer.add(a, sco, b ); assertionBuffer.add(b, sco, c ); // assertionBuffer.add(c, sco, d ); // write statements on the temp store. assertionBuffer.flush(); // perform closure and write on the database. tm.assertAll((TempTripleStore) assertionBuffer .getStatementStore()); if (log.isInfoEnabled()) log.info("\ndump after closure:\n" + store.dumpStore(store, true, true, false, true)); } // retract one { final StatementBuffer retractionBuffer = new StatementBuffer(tm .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/); retractionBuffer.add(b, sco, c); // write statements on the temp store. retractionBuffer.flush(); // update the closure. tm.retractAll((TempTripleStore)retractionBuffer.getStatementStore()); if (log.isInfoEnabled()) log.info("\ndump after retraction and re-closure:\n" + store.dumpStore(true, true, false)); } /* * Add statement(s) to the "control store" and compute its closure. * This provides the basis for checking the result that we obtained * above via retraction. */ { final TempTripleStore controlStore = new TempTripleStore(store .getProperties()); try { // Note: maintains closure on the controlStore. final TruthMaintenance tmControlStore = new TruthMaintenance( controlStore.getInferenceEngine()); final StatementBuffer assertionBuffer = new StatementBuffer( tmControlStore.newTempTripleStore(), controlStore, 100/* capacity */, 10/*queueCapacity*/); assertionBuffer.add(a, sco, b); // assertionBuffer.add(c, sco, d ); // write statements on the controlStore. assertionBuffer.flush(); // perform closure and write on the database. tmControlStore.assertAll((TempTripleStore) assertionBuffer .getStatementStore()); if (log.isInfoEnabled()) log.info("\ndump controlStore after closure:\n" + controlStore.dumpStore(true, true, false)); assertSameGraphs(controlStore, store); } finally { controlStore.__tearDownUnitTest(); } } } finally { store.__tearDownUnitTest(); } } /** * This test demonstrates an infinite loop in TM arising from owl:sameAs. */ public void test_infiniteloop() { // if(true) fail("re-enable this test"); final URI a = new URIImpl("http://www.bigdata.com/a"); final URI b = new URIImpl("http://www.bigdata.com/b"); final URI entity = new URIImpl("http://www.bigdata.com/Entity"); final URI sameAs = OWL.SAMEAS; // /* // * Note: not using rdf:type to avoid entailments about (x rdf:type // * Class) and (x rdfs:subClassOf y) that are not required by this test. // */ // URI rdfType = new URIImpl("http://www.bigdata.com/type"); final URI rdfType = RDF.TYPE; final AbstractTripleStore store = getStore(); try { final InferenceEngine inf = store.getInferenceEngine(); final TruthMaintenance tm = new TruthMaintenance(inf); // add some assertions and verify aspects of their closure. { final StatementBuffer assertionBuffer = new StatementBuffer(tm .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/); // stmt a assertionBuffer.add(a, rdfType, entity ); // assertionBuffer.add(a, x, y ); // stmt b assertionBuffer.add(b, rdfType, entity ); // assert the sameas assertionBuffer.add(a, sameAs, b ); // flush statements to the tempStore. assertionBuffer.flush(); // perform closure and write on the database. tm.assertAll((TempTripleStore) assertionBuffer .getStatementStore()); // dump after closure. if (log.isInfoEnabled()) log.info("\ndump after closure:\n" + store.dumpStore(store, true, true, false, true)); } /* * retract stmt A and update the closure. * * then verify that the retracted statement is gone and that the * other explicit statements were not touched. */ { final StatementBuffer retractionBuffer = new StatementBuffer(tm .newTempTripleStore(), store, 100/* capacity */, 10/*queueCapacity*/); // retract the sameas retractionBuffer.add(a, sameAs, b); // flush statements to the tempStore. retractionBuffer.flush(); // update the closure. tm.retractAll((TempTripleStore) retractionBuffer .getStatementStore()); // dump after re-closure. if (log.isInfoEnabled()) log.info("\ndump after re-closure:\n" + store.dumpStore(store, true, true, false, true)); } } finally { store.__tearDownUnitTest(); } } /** * This is a stress test for truth maintenance. It verifies that retraction * and assertion are symmetric by randomly retracting and then asserting * statements while using truth maintenance and verifying that the initial * conditions are always recovered. It does NOT prove the correctness of the * entailments, merely that retraction and assertion are symmetric. * * @todo use data files that we can bundle with the distribution. */ public void test_stress() { // fail("enable test"); final String ontology = "src/test/resources/data/lehigh/univ-bench.owl"; final String resource = "src/test/resources/data/lehigh/U1"; // "../rdf-data/alibaba_data.rdf", // "../rdf-data/alibaba_schema.rdf" // }; // final String[] baseURL = new String[] { "", "" // }; // // final RDFFormat[] format = new RDFFormat[] { // RDFFormat.RDFXML, // RDFFormat.RDFXML // }; // // for(String r : resource) { // // if(!new File(r).exists()) { // // System.err.println("Resource not found: "+r+", test="+getName()+" skipped."); // // return; // // } // // } final Properties properties = getProperties(); /* * Note: overrides properties to make sure that entailments are * not computed on load. */ properties.setProperty(DataLoader.Options.CLOSURE, ClosureEnum.None.toString()); TempTripleStore tmp = null; final AbstractTripleStore store = getStore(properties); try { final DataLoader dataLoader = store.getDataLoader(); final String baseURI = new File(resource).toURI().toString(); dataLoader.loadData(ontology, baseURI, RDFFormat.RDFXML); dataLoader.loadData(resource, baseURI, RDFFormat.RDFXML); /* * Compute the closure of the database. */ final InferenceEngine inf = store.getInferenceEngine(); inf.computeClosure(null/* focusStore */); /* * Make a copy of the graph (statements only) that will serve as * ground truth. */ { final Properties p = new Properties(properties); // no lexicon. p.setProperty(Options.LEXICON, "false"); tmp = new TempTripleStore(p); store.copyStatements(tmp, null/* filter */, false/* copyJustifications */); } /* * Start the stress tests. */ doStressTest(tmp, inf, 10/*ntrials*/, 1/*depth*/, 1/*nstmts*/); doStressTest(tmp, inf, 7/*ntrials*/, 1/*depth*/, 5/*nstmts*/); doStressTest(tmp, inf, 5/*ntrials*/, 5/*depth*/, 1/*nstmts*/); doStressTest(tmp, inf, 3/*ntrials*/, 5/*depth*/, 5/*nstmts*/); // // very stressful. // doStressTest(tmp, inf, 100/*ntrials*/, 10/*depth*/, 20/*nstmts*/); } catch(Exception ex) { fail("Not expecting: "+ex, ex); } finally { if(tmp != null) tmp.__tearDownUnitTest(); store.__tearDownUnitTest(); } } /** * A stress test for truth maintenance using an arbitrary data set. The test * scans the statement indices in some order, selecting N explicit statement * to retract. It then retracts them, updates the closure, and then * re-asserts them and verifies that original closure was restored. *

* Note: this test by itself does not guarentee that any entailments of * those explicit statements were removed - we need to write other tests for * that. repeat several times on the dataset, potentially doing multiple * retractions before we back out of them. * * @param tmp * Ground truth (the state that must be recovered in order for * truth maintenance to be symmetric). * @param inf * The {@link InferenceEngine} to use in the test. This reads and * writes on the database whose closure is being maintained. * @param ntrials * The #of times that we will run the test. * @param D * The recursive depth of the retractions. A depth of ONE (1) * means that one set of N statements will be retracted, closure * updated, and the re-asserted and closure updated and compared * against ground truth (the initial conditions). When the depth * is greater than ONE (1) we will recursively retract a set of N * statements D times. The statements will be reasserted as we * back out of the recursion and the graph compared with ground * truth when we return from the top level of the recursion. * @param N * The #of explicit statements to be randomly selected and * retracted on each recursive pass. */ public void doStressTest(TempTripleStore tmp, InferenceEngine inf, int ntrials, int D, int N) { AbstractTripleStore store = inf.database; /* * Verify our initial conditions agree. */ assertSameGraphs( tmp, store ); for (int trial = 0; trial < ntrials; trial++) { /* * Do recursion. */ MDC.put("trial", "trial="+trial); retractAndAssert(inf,store,0/*depth*/,D,N); /* * Verify that the closure is correct after all that recursive * mutation and restoration. */ assertSameGraphs(tmp, store); MDC.remove("trial"); } } /** * At each level of recursion up to N explicit statements are selected * randomly from the database, retracted, and closure is updated. The method * then calls itself recursively, thereby building up a series of updates to * the graph. When the recursion bottoms out, the retracted statements are * asserted and closure is updated. This continues as we back out of the * recursion until the graph SHOULD contain the identical RDF model. * * @param inf * Used to update the closure. * @param db * The database. * @param depth * The current depth of recursion (ZERO on the first call). * @param D * The maximum depth of recursion (depth will always be strictly * less than D). * @param N * The #of explicit statements to randomly select at each level * of recursion for retraction from the database. */ private void retractAndAssert(InferenceEngine inf, AbstractTripleStore db, int depth, final int D, final int N) { assert depth >= 0; assert depth < D; /* * Select N explicit statements at random. */ SPO[] stmts = selectRandomExplicitStatements(db, N); log.info("Selected "+stmts.length+" statements at random: depth="+depth); final TruthMaintenance tm = new TruthMaintenance(inf); /* * Retract those statements and update the closure of the database. */ { for(SPO tmp : stmts) { log.info("Retracting: "+tmp.toString(db)); } final TempTripleStore tempStore = tm.newTempTripleStore(); db.addStatements(tempStore, true/* copyOnly */, new ChunkedArrayIterator(stmts.length, stmts, null/* keyOrder */), null/* filter */); log.info("Retracting: n="+stmts.length+", depth="+depth); // note: an upper bound when using isolated indices. final long before = db.getStatementCount(); tm.retractAll(tempStore); final long after = db.getStatementCount(); final long delta = after - before; log.info("Retraction: before="+before+", after="+after+", delta="+delta); } if (depth + 1 < D) { retractAndAssert(inf, db, depth+1, D, N); } /* * Assert those statements and update the closure of the database. */ { for(SPO tmp : stmts) { log.info("Asserting: "+tmp.toString(db)); } final TempTripleStore tempStore = tm.newTempTripleStore(); db.addStatements(tempStore, true/* copyOnly */, new ChunkedArrayIterator(stmts.length, stmts, null/*keyOrder*/), null/*filter*/); log.info("Asserting: n=" + stmts.length + ", depth=" + depth); // note: an upper bound when using isolated indices. final long before = db.getStatementCount(); tm.assertAll(tempStore); final long after = db.getStatementCount(); final long delta = after - before; log.info("Assertion: before="+before+", after="+after+", delta="+delta); } } /** * Select N explicit statements from the graph at random. * * @param db * The graph. * @param N * The #of statements to select. * * @return Up to N distinct explicit statements selected from the graph. */ public SPO[] selectRandomExplicitStatements(AbstractTripleStore db, int N) { /* * Count the #of distinct subjects in the graph. */ final int nsubjects; { final IChunkedIterator termIds = db.getSPORelation() .distinctTermScan(SPOKeyOrder.SPO); try { int n = 0; while (termIds.hasNext()) { termIds.next(); n++; } nsubjects = n; } finally { termIds.close(); } } if (log.isInfoEnabled()) log.info("There are " + nsubjects + " distinct subjects"); /* * Choose N distinct subjects from the graph at random. */ final Set subjects = new HashSet(N); for (int i = 0; i < nsubjects && subjects.size() < N; i++) { final IChunkedIterator termIds = db.getSPORelation() .distinctTermScan(SPOKeyOrder.SPO); try { // choose subject at random. int index = r.nextInt(nsubjects); IV s = NULL; for (int j = 0; termIds.hasNext() && j < index; j++) { s = termIds.next(); } subjects.add(s); } finally { termIds.close(); } } if (log.isInfoEnabled()) log.info("Selected " + subjects.size() + " distinct subjects: " + subjects); /* * Choose one explicit statement at random for each distinct subject. * * Note: It is possible that some subjects will not have any explicit * statements, in which case we will select fewer than N statements. */ List stmts = new ArrayList(N); for( IV s : subjects ) { final IAccessPath accessPath = db.getAccessPath(s, NULL, NULL, ExplicitSPOFilter.INSTANCE); final IChunkedOrderedIterator itr = accessPath.iterator(); try { if (!itr.hasNext()) continue; // a chunk of explicit statements for that subject. final ISPO[] chunk = itr.nextChunk(); // statement randomly choosen from that chunk. final ISPO tmp = chunk[r.nextInt(chunk.length)]; if (log.isInfoEnabled()) log.info("Selected at random: " + tmp.toString(db)); stmts.add(tmp); } finally { itr.close(); } } if (log.isInfoEnabled()) log.info("Selected " + stmts.size() + " distinct statements: " + stmts); return stmts.toArray(new SPO[stmts.size()]); } /** * This is a specialized test for equality in the graphs that simply compare * scans on the SPO index. *

* Pre-condition: The term identifiers for the graphs MUST be consistently * assigned since the statements are not being materialized as RDF * {@link org.openrdf.model.Value} objects. * * @param expected * A copy of the statements made after the data set was loaded * and its closure computed and before we began to retract and * assert stuff. * * @param actual * Note that this is used by both graphs to resolve the term * identifiers. */ protected void assertSameGraphs(TempTripleStore expected, AbstractTripleStore actual) { // For the truly paranoid. // assertStatementIndicesConsistent(expected); // // assertStatementIndicesConsistent(actual); /* * Note: You can not directly compare statement counts when using * isolatable indices since they are upper bounds - not exact counts. */ // if (expected.getStatementCount() != actual.getStatementCount()) { // // log.warn("statementCount: expected=" + expected.getStatementCount() // + ", but actual=" + actual.getStatementCount()); // // } final IChunkedOrderedIterator itre = expected.getAccessPath( SPOKeyOrder.SPO).iterator(); final IChunkedOrderedIterator itra = actual.getAccessPath( SPOKeyOrder.SPO).iterator(); // int i = 0; int nerrs = 0; int maxerrs = 10; int nexpected = 0; int nactual = 0; try { while (itre.hasNext()) { if(!itra.hasNext()) { fail("Actual iterator exhausted before expected: nexpected=" + nexpected + ", nactual=" + nactual + ", remaining=" + toString(itre, 10, expected)); } SPO expectedSPO = (SPO)itre.next(); nexpected++; SPO actualSPO = (SPO)itra.next(); nactual++; if (!expectedSPO.equals(actualSPO)) { while (SPOComparator.INSTANCE.compare(actualSPO, expectedSPO) < 0) { log.warn("Not expecting: " + actualSPO.toString(actual)); if(!itra.hasNext()) break; actualSPO = (SPO)itra.next(); nactual++; if(nerrs++==maxerrs) fail("Too many errors"); } while (SPOComparator.INSTANCE.compare(expectedSPO, actualSPO) < 0) { log.warn("Expecting: " + expectedSPO.toString(actual)); if(!itre.hasNext()) break; expectedSPO = (SPO)itre.next(); nexpected++; if(nerrs++==maxerrs) fail("Too many errors"); } } // i++; } assertFalse("Actual iterator will visit more than expected", itra.hasNext()); } finally { itre.close(); itra.close(); } /* * Note: This compares the #of statements actually visited by the two * iterators rather than comparing getStatementCount(), which is an * upper bound based on rangeCount(). */ assertEquals("statementCount", nexpected, nactual ); } /** * Consumes up to max elements from the iterator and returns a * {@link String} representation of those elements. This is used to show the * additional elements that would be visited by an iterator when the other * iterator is exhausted. * * @param itr * The iterator. * @param max * The maximum #of elements to visit. * @param db * Used to resolve term identifiers to RDF values. * * @return The string representation of the visited elements. */ private String toString(IChunkedOrderedIterator itr, int max, AbstractTripleStore db) { StringBuilder sb = new StringBuilder(); int n = 0; while (itr.hasNext() && n < max) { if (n > 0) sb.append(", "); sb.append(itr.next().toString(db)); } return "{" + sb.toString() + "}"; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy