package uk.ac.manchester.cs.jfact.kernel;
/* This file is part of the JFact DL reasoner
Copyright 2011-2013 by Ignazio Palmisano, Dmitry Tsarkov, University of Manchester
This 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 2.1 of the License, or (at your option) any later version.
This 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 this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import uk.ac.manchester.cs.jfact.helpers.Helper;
import uk.ac.manchester.cs.jfact.helpers.LogAdapter;
import conformance.Original;
import conformance.PortedFrom;
/** role automaton */
@PortedFrom(file = "RAutomaton.h", name = "RoleAutomaton")
public class RoleAutomaton implements Serializable {
private static final long serialVersionUID = 11000L;
/** all transitions of the automaton, groupped by a starting state */
@PortedFrom(file = "RAutomaton.h", name = "Base")
private final List<RAStateTransitions> base = new ArrayList<RAStateTransitions>();
/** maps original automata state into the new ones (used in copyRA) */
@PortedFrom(file = "RAutomaton.h", name = "map")
private int[] map = new int[0];
/** initial state of the next automaton in chain */
@PortedFrom(file = "RAutomaton.h", name = "iRA")
private int initialRA;
/** flag whether automaton is input safe */
@PortedFrom(file = "RAutomaton.h", name = "ISafe")
private boolean inputSafe;
/** flag whether automaton is output safe */
@PortedFrom(file = "RAutomaton.h", name = "OSafe")
private boolean outputSafe;
/**
* make sure that STATE exists in the automaton (update ton's size)
*
* @param state
* state
*/
@PortedFrom(file = "RAutomaton.h", name = "ensureState")
private void ensureState(int state) {
if (state >= base.size()) {
Helper.resize(base, state + 1);
}
for (int i = 0; i < base.size(); i++) {
if (base.get(i) == null) {
base.set(i, new RAStateTransitions());
}
}
}
/** default constructor */
public RoleAutomaton() {
initialRA = 0;
inputSafe = true;
outputSafe = true;
ensureState(1);
}
/**
* make the beginning of the chain
*
* @param from
* from
*/
@PortedFrom(file = "RAutomaton.h", name = "initChain")
public void initChain(int from) {
initialRA = from;
}
/**
* add an Automaton to the chain with a default state
*
* @param RA
* RA
* @param oSafe
* oSafe
* @return is o safe
*/
@PortedFrom(file = "RAutomaton.h", name = "addToChain")
public boolean addToChain(RoleAutomaton RA, boolean oSafe) {
return addToChain(RA, oSafe, size() + 1);
}
// i/o safety
/** @return the i-safe value */
@PortedFrom(file = "RAutomaton.h", name = "isISafe")
public boolean isISafe() {
return inputSafe;
}
/** @return the o-safe value */
@PortedFrom(file = "RAutomaton.h", name = "isOSafe")
public boolean isOSafe() {
return outputSafe;
}
// add single RA
/**
* add RA from a subrole to given one
*
* @param RA
* RA
*/
@PortedFrom(file = "RAutomaton.h", name = "addRA")
public void addRA(RoleAutomaton RA) {
// XXX not sure about this
if (isCompleted()) {
return;
}
assert !isCompleted();
if (RA.isSimple()) {
boolean ok = base.get(initial).addToExisting(
RA.getBase().get(initial).begin().get(0));
assert ok;
} else {
initChain(initial);
addToChain(RA, /* oSafe= */false, final_state);
}
}
/**
* add TRANSition leading from a given STATE; check whether all states are
* correct
*
* @param state
* state
* @param trans
* trans
*/
@PortedFrom(file = "RAutomaton.h", name = "addTransitionSafe")
public void addTransitionSafe(int state, RATransition trans) {
ensureState(state);
ensureState(trans.final_state());
addTransition(state, trans);
}
/** state that the automaton is i-unsafe */
@PortedFrom(file = "RAutomaton.h", name = "setIUnsafe")
public void setIUnsafe() {
inputSafe = false;
}
/** state that the automaton is o-unsafe */
@PortedFrom(file = "RAutomaton.h", name = "setOUnsafe")
public void setOUnsafe() {
outputSafe = false;
}
/**
* check whether transition between FROM and TO breaks safety
*
* @param from
* from
* @param to
* to
*/
@PortedFrom(file = "RAutomaton.h", name = "checkTransition")
public void checkTransition(int from, int to) {
if (from == final_state) {
setOUnsafe();
}
if (to == initial) {
setIUnsafe();
}
}
/**
* add TRANSition leading from a state FROM; all states are known to fit the
* ton
*
* @param from
* from
* @param trans
* trans
*/
@PortedFrom(file = "RAutomaton.h", name = "addTransition")
public void addTransition(int from, RATransition trans) {
checkTransition(from, trans.final_state());
base.get(from).add(trans);
}
/**
* make the internal chain transition (between chainState and TO)
*
* @param to
* to
*/
@PortedFrom(file = "RAutomaton.h", name = "nextChainTransition")
public void nextChainTransition(int to) {
addTransition(initialRA, new RATransition(to));
initialRA = to;
}
/** get the initial state */
@Original
public static final int initial = 0;
/** get the state */
@PortedFrom(file = "RAutomaton.h", name = "final")
public static final int final_state = 1;
/** @return new state */
@PortedFrom(file = "RAutomaton.h", name = "newState")
public int newState() {
int ret = base.size();
ensureState(ret);
return ret;
}
/**
* @param state
* state
* @return the 1st (multi-)transition starting in STATE
*/
@PortedFrom(file = "RAutomaton.h", name = "begin")
public RAStateTransitions getRAStateTransitions(int state) {
return base.get(state);
}
/** @return number of distinct states */
@PortedFrom(file = "RAutomaton.h", name = "size")
public int size() {
return base.size();
}
/**
* set up all transitions passing number of roles
*
* @param nRoles
* nRoles
* @param data
* data
*/
@PortedFrom(file = "RAutomaton.h", name = "setup")
public void setup(int nRoles, boolean data) {
for (int i = 0; i < base.size(); ++i) {
base.get(i).setup(i, nRoles, data);
}
}
/**
* @param o
* o
*/
@PortedFrom(file = "RAutomaton.h", name = "print")
public void print(LogAdapter o) {
for (int state = 0; state < base.size(); ++state) {
base.get(state).print(o);
}
}
/**
* @param RA
* RA
*/
@PortedFrom(file = "RAutomaton.h", name = "addCopy")
public void addCopy(RoleAutomaton RA) {
for (int i = 0; i < RA.size(); ++i) {
int from = map[i];
RAStateTransitions RST = base.get(from);
RAStateTransitions RSTOrig = RA.base.get(i);
if (RSTOrig.isEmpty()) {
continue;
}
List<RATransition> begin = RSTOrig.begin();
for (int j = 0; j < begin.size(); j++) {
RATransition p = begin.get(j);
int to = p.final_state();
RATransition trans = new RATransition(map[to]);
checkTransition(from, trans.final_state());
trans.add(p);
// try to merge transitions going to the original state
if (to == 1 && RST.addToExisting(trans)) {} else {
RST.add(trans);
}
}
}
}
/**
* init internal map according to RA size, with new initial state from
* chainState and (FRA) states
*
* @param RASize
* RASize
* @param fRA
* fRA
*/
@PortedFrom(file = "RAutomaton.h", name = "initMap")
public void initMap(int RASize, int fRA) {
map = Arrays.copyOf(map, RASize);
// new state in the automaton
int newState = size() - 1;
// fill initial state; it is always known in the automata
map[0] = initialRA;
// fills the state; if it is not known -- adjust newState
if (fRA >= size()) {
// make sure we don't create an extra unused state
fRA = size();
++newState;
}
map[1] = fRA;
// check transitions as it may turns out to be a single transition
checkTransition(initialRA, fRA);
// set new initial state
initialRA = fRA;
// fills the rest of map
for (int i = 2; i < RASize; ++i) {
map[i] = ++newState;
}
// reserve enough space for the new automaton
ensureState(newState);
}
/**
* add an Automaton to the chain that would start from the iRA; OSAFE shows
* the safety of a previous automaton in a chain
*
* @param RA
* RA
* @param oSafe
* oSafe
* @param fRA
* fRA
* @return is o safe
*/
@PortedFrom(file = "RAutomaton.h", name = "addToChain")
public boolean addToChain(RoleAutomaton RA, boolean oSafe, int fRA) {
assert !isCompleted();
boolean needFinalTrans = fRA < size() && !RA.isOSafe();
// we can skip transition if chaining automata are i- and o-safe
if (!oSafe && !RA.isISafe()) {
nextChainTransition(newState());
}
// check whether we need an output transition
initMap(RA.size(), needFinalTrans ? size() : fRA);
addCopy(RA);
if (needFinalTrans) {
nextChainTransition(fRA);
}
return RA.isOSafe();
}
/** @return state transitions */
@PortedFrom(file = "RAutomaton.h", name = "begin")
public List<RAStateTransitions> getBase() {
return base;
}
// automaton completeness
@PortedFrom(file = "RAutomaton.h", name = "Complete")
private boolean Complete;
/** mark an automaton as completed */
@PortedFrom(file = "RAutomaton.h", name = "setCompleted")
public void setCompleted() {
Complete = true;
}
/**
* @param b
* b
*/
@PortedFrom(file = "RAutomaton.h", name = "setCompleted")
public void setCompleted(boolean b) {
Complete = b;
}
/** @return check whether automaton is completed */
@PortedFrom(file = "RAutomaton.h", name = "isCompleted")
public boolean isCompleted() {
return Complete;
}
/** @return true iff the automaton is simple */
@PortedFrom(file = "RAutomaton.h", name = "isSimple")
public boolean isSimple() {
// assert isCompleted();
return size() == 2 && inputSafe && outputSafe;
}
}