You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

287 lines
8.6 KiB

//==============================================================================
//
// Copyright (c) 2002-
// Authors:
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford)
//
//------------------------------------------------------------------------------
//
// This file is part of PRISM.
//
// PRISM 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; either version 2 of the License, or
// (at your option) any later version.
//
// PRISM 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 PRISM; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//==============================================================================
package pta;
import java.util.*;
import prism.PrismException;
import explicit.IndexedSet;
import explicit.StateStorage;
/**
* Class to perform the parallel composition of PTAs.
*/
public class PTAParallel
{
// All states
private StateStorage<IndexPair> states;
// States to be explored
private LinkedList<IndexPair> explore;
// Component PTAs
private PTA pta1;
private PTA pta2;
// Resulting PTA (parallel composition)
private PTA par;
/**
* Construct the parallel composition of two PTAs.
*/
public PTA compose(PTA pta1, PTA pta2)
{
Set<String> alpha1, alpha2, alpha1only, alpha2only, sync;
Transition transition;
Edge edge;
double prob;
IndexPair state;
int src, dest;
// Store PTAs locally and create new one to store parallel composition
this.pta1 = pta1;
this.pta2 = pta2;
par = new PTA();
// New set of clocks is union of sets for two PTAs
for (String s : pta1.clockNames) {
par.getOrAddClock(s);
}
for (String s : pta2.clockNames) {
par.getOrAddClock(s);
}
// Get alphabets, compute intersection etc.
alpha1 = pta1.getAlphabet();
alpha2 = pta2.getAlphabet();
//System.out.println("alpha1: " + alpha1);
//System.out.println("alpha2: " + alpha2);
sync = new LinkedHashSet<String>();
alpha1only = new LinkedHashSet<String>();
alpha2only = new LinkedHashSet<String>();
for (String a : alpha1) {
if (!("".equals(a)) && alpha2.contains(a)) {
sync.add(a);
} else {
alpha1only.add(a);
}
}
for (String a : alpha2) {
if (!alpha1.contains(a)) {
alpha2only.add(a);
}
}
// Explicitly add tau to action lists
alpha1only.add("");
alpha2only.add("");
//System.out.println("alpha1only: " + alpha1only);
//System.out.println("alpha2only: " + alpha2only);
//System.out.println("sync: " + sync);
// Initialise states storage
states = new IndexedSet<IndexPair>();
explore = new LinkedList<IndexPair>();
// Add initial location
addState(0, 0);
src = -1;
while (!explore.isEmpty()) {
// Pick next state to explore
// (they are stored in order found so know index is src+1)
state = explore.removeFirst();
src++;
// Go through asynchronous transitions of PTA 1
for (String a : alpha1only) {
for (Transition transition1 : pta1.getTransitionsByAction(state.i1, a)) {
// Create new transition
transition = par.addTransition(src, a);
// Copy guard
for (Constraint c : transition1.getGuardConstraints())
transition.addGuardConstraint(c.deepCopy().renameClocks(pta1, par));
// Combine edges
for (Edge edge1 : transition1.getEdges()) {
prob = edge1.getProbability();
dest = addState(edge1.getDestination(), state.i2);
edge = transition.addEdge(prob, dest);
// Copy resets
for (Map.Entry<Integer, Integer> e : edge1.getResets()) {
edge.addReset(PTA.renameClock(pta1, par, e.getKey()), e.getValue());
}
}
}
}
// Go through asynchronous transitions of PTA 2
for (String a : alpha2only) {
for (Transition transition2 : pta2.getTransitionsByAction(state.i2, a)) {
// Create new transition
transition = par.addTransition(src, a);
// Copy guard
for (Constraint c : transition2.getGuardConstraints())
transition.addGuardConstraint(c.deepCopy().renameClocks(pta2, par));
// Combine edges
for (Edge edge2 : transition2.getEdges()) {
prob = edge2.getProbability();
dest = addState(state.i1, edge2.getDestination());
edge = transition.addEdge(prob, dest);
// Copy resets
for (Map.Entry<Integer, Integer> e : edge2.getResets()) {
edge.addReset(PTA.renameClock(pta2, par, e.getKey()), e.getValue());
}
}
}
}
// Go through synchronous transitions
for (String a : sync) {
for (Transition transition1 : pta1.getTransitionsByAction(state.i1, a)) {
for (Transition transition2 : pta2.getTransitionsByAction(state.i2, a)) {
// Create new transition
transition = par.addTransition(src, a);
// Guard is conjunction of guards
for (Constraint c : transition1.getGuardConstraints())
transition.addGuardConstraint(c.deepCopy().renameClocks(pta1, par));
for (Constraint c : transition2.getGuardConstraints())
transition.addGuardConstraint(c.deepCopy().renameClocks(pta2, par));
// Combine edges
for (Edge edge1 : transition1.getEdges()) {
for (Edge edge2 : transition2.getEdges()) {
prob = edge1.getProbability() * edge2.getProbability();
dest = addState(edge1.getDestination(), edge2.getDestination());
edge = transition.addEdge(prob, dest);
// Reset set is union of reset sets
for (Map.Entry<Integer, Integer> e : edge1.getResets()) {
edge.addReset(PTA.renameClock(pta1, par, e.getKey()), e.getValue());
}
for (Map.Entry<Integer, Integer> e : edge2.getResets()) {
edge.addReset(PTA.renameClock(pta2, par, e.getKey()), e.getValue());
}
}
}
}
}
}
}
return par;
}
/**
* Helper function. Add a new state, if it does not already exist, and returns its index.
* @param loc1: Index of location of PTA 1
* @param loc2: Index of location of PTA 2
*/
private int addState(int loc1, int loc2)
{
// See if this is a new state
IndexPair stateNew = new IndexPair(loc1, loc2);
if (states.add(stateNew)) {
// If so, add to the explore list
explore.add(stateNew);
// Get index of state in state set
int locNew = states.getIndexOfLastAdd();
// And add a location to the PTA
par.addLocation(PTA.combineLocationNames(pta1.getLocationName(loc1), pta2.getLocationName(loc2)));
// Invariant is conjunction of two invariants
for (Constraint c : pta1.getInvariantConstraints(loc1))
par.addInvariantCondition(locNew, c.deepCopy().renameClocks(pta1, par));
for (Constraint c : pta2.getInvariantConstraints(loc2))
par.addInvariantCondition(locNew, c.deepCopy().renameClocks(pta2, par));
}
// Return index of state in state set
return states.getIndexOfLastAdd();
}
/**
* Class to store a pair of indices.
*/
class IndexPair
{
int i1;
int i2;
public IndexPair(int i1, int i2)
{
this.i1 = i1;
this.i2 = i2;
}
public int hashCode()
{
// Simple hash code
return i1;
}
public boolean equals(Object o)
{
IndexPair ip;
if (o == null) return false;
try {
ip = (IndexPair) o;
} catch (ClassCastException e) {
return false;
}
return i1 == ip.i1 && i2 == ip.i2;
}
public String toString()
{
return i1 +"," + i2;
}
}
/**
* Main method to test
* (read from multiple des files, output result to a des file)
*/
public static void main(String args[])
{
PTA pta, pta2;
int i;
if (args.length < 1) {
System.err.println("Usage: java ... <des files>");
System.exit(1);
}
try {
// Build PTA
System.out.println("Building PTA from \"" + args[0] + "\"");
pta = PTA.buildPTAFromDesFile(args[0]);
System.out.println(pta.infoString());
//System.out.println(pta);
for (i = 1; i < args.length; i++) {
System.out.println("Building PTA from \"" + args[i] + "\"");
pta2 = PTA.buildPTAFromDesFile(args[i]);
System.out.println(pta2.infoString());
//System.out.println(pta2);
pta = new PTAParallel().compose(pta, pta2);
//System.out.println(pta);
}
System.out.println("Final PTA: " + pta.infoString());
System.out.println(pta);
pta.check();
pta.writeToDesFile("par.des");
// Parse target location
} catch (PrismException e) {
System.err.println("Error: " + e.getMessage());
}
}
}