/*
* Copyright (C) 2016 Mostafa M.A. (mostafa.amin93@gmail.com)
* Copyright (C) 2014-2016 University of Freiburg
*
* This file is part of the ULTIMATE Automata Library.
*
* The ULTIMATE Automata Library 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 3 of the License, or
* (at your option) any later version.
*
* The ULTIMATE Automata Library 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 the ULTIMATE Automata Library. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE Automata Library, or any covered work, by linking
* or combining it with Eclipse RCP (or a modified version of Eclipse RCP),
* containing parts covered by the terms of the Eclipse Public License, the
* licensors of the ULTIMATE Automata Library grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.automata.tree.operations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.uni_freiburg.informatik.ultimate.automata.AutomataLibraryException;
import de.uni_freiburg.informatik.ultimate.automata.AutomataLibraryServices;
import de.uni_freiburg.informatik.ultimate.automata.GeneralOperation;
import de.uni_freiburg.informatik.ultimate.automata.IOperation;
import de.uni_freiburg.informatik.ultimate.automata.statefactory.IIntersectionStateFactory;
import de.uni_freiburg.informatik.ultimate.automata.statefactory.IStateFactory;
import de.uni_freiburg.informatik.ultimate.automata.tree.IRankedLetter;
import de.uni_freiburg.informatik.ultimate.automata.tree.ITreeAutomatonBU;
import de.uni_freiburg.informatik.ultimate.automata.tree.TreeAutomatonBU;
import de.uni_freiburg.informatik.ultimate.automata.tree.TreeAutomatonRule;
import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair;
/**
* Intersect 2 tree automatons.
*
* @author mostafa (mostafa.amin93@gmail.com)
*
* @param
* letter of the tree automatons.
* @param
* state of the tree automatons.
*/
public class Intersect
extends GeneralOperation>
implements IOperation> {
private final ITreeAutomatonBU mTreeA;
private final ITreeAutomatonBU mTreeB;
protected final ITreeAutomatonBU mResult;
private final IIntersectionStateFactory mStateFactory;
private final Map>> mPairsMap;
private final Map, STATE> mReducedStates;
/**
*
* NOTE: because of a convention in TestFileInterpreter, if an argument for
* the operation is a StateFactory, it must be the first argument same for
* Services, both: first services then StateFactory
*
* @param services
* @param factory
* @param t1
* @param t2
*/
public Intersect(final AutomataLibraryServices services, final IIntersectionStateFactory factory,
final ITreeAutomatonBU t1, final ITreeAutomatonBU t2) {
super(services);
mReducedStates = new HashMap<>();
mPairsMap = new HashMap<>();
mStateFactory = factory;
mTreeA = t1;
mTreeB = t2;
mResult = computeResult();
}
private STATE reduceState(final Pair key) {
if (!mReducedStates.containsKey(key)) {
mReducedStates.put(key, mStateFactory.intersection(key.getFirst(), key.getSecond()));
}
return mReducedStates.get(key);
}
private Pair getPair(final STATE q1, final STATE q2) {
if (!mPairsMap.containsKey(q1)) {
mPairsMap.put(q1, new HashMap<>());
}
if (!mPairsMap.get(q1).containsKey(q2)) {
mPairsMap.get(q1).put(q2, new Pair<>(q1, q2));
}
return mPairsMap.get(q1).get(q2);
}
@Override
public String startMessage() {
return "Start intersection tree automatons";
}
@Override
public String exitMessage() {
return "Exit intersection tree automatons";
}
private TreeAutomatonBU computeResult() {
// Minimal states intersection.
//final TreeAutomatonBU> res = new TreeAutomatonBU<>();
//res.extendAlphabet(mTreeA.getAlphabet());
//res.extendAlphabet(mTreeB.getAlphabet());
final Set alphabet = new HashSet<>();
final Set> finalStates = new HashSet<>();
final Set>> newRules = new HashSet<>();
alphabet.addAll(mTreeA.getAlphabet());
alphabet.addAll(mTreeB.getAlphabet());
final Map>> symbolToRuleA = new HashMap<>();
final Map>> symbolToRuleB = new HashMap<>();
for (final List src : mTreeA.getSourceCombinations()) {
for (final TreeAutomatonRule ruleA : mTreeA.getSuccessors(src)) {
Collection> rules;
if (symbolToRuleA.containsKey(ruleA.getLetter())) {
rules = symbolToRuleA.get(ruleA.getLetter());
} else {
rules = new LinkedList<>();
symbolToRuleA.put(ruleA.getLetter(), rules);
}
rules.add(ruleA);
}
}
for (final List src : mTreeB.getSourceCombinations()) {
for (final TreeAutomatonRule ruleB : mTreeB.getSuccessors(src)) {
Collection> rules;
if (symbolToRuleB.containsKey(ruleB.getLetter())) {
rules = symbolToRuleB.get(ruleB.getLetter());
} else {
rules = new LinkedList<>();
symbolToRuleB.put(ruleB.getLetter(), rules);
}
rules.add(ruleB);
}
}
for (final LETTER letter : symbolToRuleA.keySet()) {
if (symbolToRuleB.containsKey(letter)) {
for (final TreeAutomatonRule ruleA : symbolToRuleA.get(letter)) {
for (final TreeAutomatonRule ruleB : symbolToRuleB.get(letter)) {
if (ruleA.getArity() == ruleB.getArity()) {
final List> source = new ArrayList<>();
final int ar = ruleA.getArity();
for (int i = 0; i < ar; ++i) {
source.add(getPair(ruleA.getSource().get(i), ruleB.getSource().get(i)));
}
final Pair dest = getPair(ruleA.getDest(), ruleB.getDest());
newRules.add(new TreeAutomatonRule<>(letter, source, dest));
//res.addRule(new TreeAutomatonRule<>(letter, source, dest));
}
}
}
}
}
for (final STATE q1 : mPairsMap.keySet()) {
for (final STATE q2 : mPairsMap.get(q1).keySet()) {
final Pair st = getPair(q1, q2);
if (mTreeA.isFinalState(q1) && mTreeB.isFinalState(q2)) {
finalStates.add(st);
//res.addFinalState(st);
}
}
}
final TreeAutomatonBU reducedResult = new TreeAutomatonBU<>();
for (final TreeAutomatonRule> rule : newRules) {
final List src = new ArrayList<>();
for (final Pair pr : rule.getSource()) {
src.add(reduceState(pr));
}
reducedResult.addRule(new TreeAutomatonRule<>(rule.getLetter(), src, reduceState(rule.getDest())));
}
for (final Pair state : finalStates) {
reducedResult.addFinalState(reduceState(state));
}
/*
for (final Pair state : res.getStates()) {
reducedResult.addState(reduceState(state));
if (res.isFinalState(state)) {
reducedResult.addFinalState(reduceState(state));
}
}
*/
return reducedResult;
}
@Override
public ITreeAutomatonBU getResult() {
return mResult;
}
@Override
public boolean checkResult(final IStateFactory stateFactory) throws AutomataLibraryException {
return true;
}
}