Package ru.bmstu.datalog.algo

Source Code of ru.bmstu.datalog.algo.DatalogAlgo

package ru.bmstu.datalog.algo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;

import ru.bmstu.datalog.data.Argument;

import ru.bmstu.datalog.data.Predicate;
import ru.bmstu.datalog.data.Request;
import ru.bmstu.datalog.data.Rule;

import ru.bmstu.datalog.data.DatalogData;
import ru.bmstu.datalog.storage.DatalogStorage;

/**
* Implementation of an algorithm to compute the expression on Datalog.
* @author art-vybor
*/
public class DatalogAlgo {
  private static HashSet<Rule>       rules;      //Set of rules.
  private static HashSet<Request>     requests;    //Set of request.
  private static HashSet<Predicate>     requestCash;    //Request cache.
  private static HashSet<PredicateIdentifier>   ruleNames;    //A set of rules.
  private static DatalogStorage      storage;    //Storage of facts. 
  private static DatalogStorage       answerSet;    //Storage of intermediate answers.
 
  private static int        currentVariable;  //Variable required for the designation of variables.
 
  /**
   * Returns a response.
   * Used program for rules and requests, storagePath for storage(it must be existing database).
   * @param program
   * @param storagePath
   * @return
   */
  public static HashSet<Predicate> getAnswer(DatalogData program, String storagePath) {
    storage = new DatalogStorage(storagePath, false);
       
    return initAndStartAlgo(program);
  }
 
  /**
   * Returns a response.
   * Used data for facts,rules and requests. After, facts are placed in tempStorage.
   * @param data
   * @return
   */
  public static HashSet<Predicate> getAnswer(DatalogData data) {
    storage = new DatalogStorage("tempStorage", false);
    storage.clear();
    storage.insertFacts(data.getFacts());
   
    return initAndStartAlgo(data);   
  }
 
  /**
   * Returns a response.
   * Used program for rules and requests, data for facts. After, facts are placed in tempStorage.
   * @param program
   * @param data
   * @return
   */
  public static HashSet<Predicate> getAnswer(DatalogData program, DatalogData data) {
    storage = new DatalogStorage("tempStorage", false);
    storage.clear();
    storage.insertFacts(data.getFacts());
   
    return initAndStartAlgo(program);
  }

 
  /**
   * Initializes the necessary variables, prepare data, and runs the algorithm.
   * @param data
   * @return
   */
  private static HashSet<Predicate> initAndStartAlgo(DatalogData data) {
    //TODO пофиксить случай запуска QSQ для предиката от констант
    //initialization
    rules = data.getRules();
    requests = data.getRequests();
    currentVariable = 0;
   
    requestCash = new HashSet<Predicate>();
    answerSet = new DatalogStorage("answerStorage", true);
   
    //preprocessoring
    sortPredicateInRule();
    evaluateVariables();
    initRuleNames();
 
    //the algorithm
    HashSet<Predicate> answer = executeAlgo();

    //correct shutdown
    storage.close();
    answerSet.close();
   
    return answer;
  }
 
  //---------------------------------------------------------------------------------------
  //--------------Algorithm----------------------------------------------------------------
  //---------------------------------------------------------------------------------------
 
  /**
   * Returns a response to a pre-set program.
   * @return {@link HashSet<Predicate>}
   */
  private static HashSet<Predicate> executeAlgo() {
    HashSet<Predicate> answer = new HashSet<Predicate>();
   
    for (Request request : requests) {
      answerSet.clear();
      executeRequest(request.getPredicate());
      answer.addAll(answerSet.select(request.getPredicate()));
    }
   
    return answer;
  }
 
  /**
   * Function performs a request to update the answerSet.
   * @param request
   */
  private static void executeRequest(Predicate request) {
    if (requestCash.contains(request)) return;      //Do we already made ​​the same request? If yes is interrupted.   
    requestCash.add(request);
   
    answerSet.insert(storage.select(request));            //Add to answer all the possible answers of the zero level.
   
    int size = -1;
    int answerSize = answerSet.size();
   
    while (size != answerSize) {
      size = answerSize;
      for (Rule rule : getRulesForRequest(request)) {       //For all transformed rules with a suitable head.
       
        ArrayList<Unifier> unifierList = new ArrayList<Unifier>();     //Start with a list of substitutions, which consists of a single empty substitution.
        unifierList.add(new Unifier());
       
        for (int i = 0; i < rule.getBody().size(); ++i) {
          Predicate predicate = rule.getBody().get(i);        //Iterate through all the predicates of the body using select Function
          ArrayList<Unifier> localUnifierList = new ArrayList<Unifier>();
         
          for (Unifier unifier : unifierList) {        //For each permutation of the list.
            Predicate localPredicate = unifier.unifyPredicate(predicate)//Apply it to the predicate.       
           
            HashSet<Predicate> tempAnswers;
           
            if (ruleNames.contains(new PredicateIdentifier(predicate))) {  //If the predicate occurs in the program as the head rules: //TODO вынести проверку на уровень выше
              executeRequest(getRequest(localPredicate));      //Recursively run executeRequest of this predicate.
              tempAnswers = answerSet.select(localPredicate);    //Select an answer from the set answerSet.
             
            } else {              //Else
              tempAnswers = storage.select(localPredicate);    //Select an answer from BD.
            }
           
            for (Predicate tempAnswer : tempAnswers) {      //For each answer we get a new permutation.       
              Unifier localUnifier = unifier.getNewUnifier(localPredicate, tempAnswer);
             
              localUnifierList.add(localUnifier);
            }
          }
          unifierList = localUnifierList;          
        }
        for (Unifier unifier : unifierList) {            //From the list of substitutions get the right answer.
          answerSet.insert(unifier.unifyPredicate(rule.getHead()));
        }
      }
      answerSize = answerSet.size();
    }
  }


  /**
   * Provides a new query based on predicate.
   * @param predicate
   * @return {@link Predicate}
   */
  private static Predicate getRequest(Predicate predicate) {
    ArrayList<Argument> args = new ArrayList<Argument>();
    HashMap<String, Integer> hash = new HashMap<String, Integer>();
   
    for (Argument arg : predicate.getArgs()) {
      arg = new Argument(arg);

      if (arg.isVariable())  
        evaluateVariable(hash, arg);
      args.add(arg);
    }
   
    return new Predicate(predicate.getName(),args);
  }

  /**
   * Return all rules with a suitable head which transformed to the form required for the current request.
   * @param request
   * @return
   */
  private static ArrayList<Rule> getRulesForRequest(Predicate request) {
    ArrayList<Rule> answer = new ArrayList<Rule>();
   
    for (Rule rule : rules) {
      Unifier unifier = Unifier.produceMostGeneralUnifier(rule.getHead(), request);
     
      if (unifier != null) {
        Predicate answerHead =  unifier.unifyPredicate(rule.getHead());
       
        ArrayList<Predicate> answerBody = new ArrayList<Predicate>();
        for (Predicate predicate : rule.getBody())
          answerBody.add(unifier.unifyPredicate(predicate));
       
        answer.add(new Rule(answerHead, answerBody));
      }
    }
    return answer;
  }
 
  /**
   * Evalute variables for rules and requests. 
   */
  private static void evaluateVariables() {
    for (Rule rule : rules) {
      HashMap<String, Integer> hash = new HashMap<String, Integer>();
     
      for (Argument arg : rule.getHead().getArgs())
        evaluateVariable(hash, arg);
     
      for (Predicate predicate : rule.getBody())
        for (Argument arg : predicate.getArgs())
          evaluateVariable(hash, arg);
    }
   
    for (Request request : requests) {
      HashMap<String, Integer> hash = new HashMap<String, Integer>();
     
      for (Argument arg : request.getPredicate().getArgs())
        evaluateVariable(hash, arg)
     
    }
  }
 
//---------------------------------------------------------------------------------------
//--------------Functions for preprocessoring--------------------------------------------
//---------------------------------------------------------------------------------------
 
  /**
   * Sorts the predicates in the body of the rule descending number of constants
   */
  private static void sortPredicateInRule() {
    for (Rule rule: rules) {
      Collections.sort(rule.getBody(),new Comparator<Predicate>() {
        @Override
        public int compare(Predicate p1, Predicate p2) {
          int c1 = 0;
          int c2 = 0;
          for (Argument arg : p1.getArgs()) {
            if (arg.isConstant()) c1++;
          }
         
          for (Argument arg : p2.getArgs()) {
            if (arg.isConstant()) c2++;
          }
          return c2-c1;
        }
      });
    }
  }
 
  /**
   * Evalute variable for arg.
   * @param hash
   * @param arg
   */
  private static void evaluateVariable(HashMap<String, Integer> hash, Argument arg) {
    if (arg.isVariable()) {
      if (arg.getConstant() == "_") {
        arg.setVariable(currentVariable++);
      } else {
        if (hash.containsKey(arg.getConstant()) == false) {
          arg.setVariable(currentVariable);
          hash.put(arg.getConstant(), currentVariable++);
        } else {
          arg.setVariable(hash.get(arg.getConstant()));
        }
      }
    }
  }
 
  /**
   * Add all the rules in the ruleNames.
   */
  private static void initRuleNames() {
    ruleNames = new HashSet<PredicateIdentifier>();
    for (Rule rule : rules) {
      ruleNames.add(new PredicateIdentifier(rule.getHead()));
    }
  }

}

TOP

Related Classes of ru.bmstu.datalog.algo.DatalogAlgo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.