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.
539 lines
11 KiB
539 lines
11 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;
|
|
|
|
/**
|
|
* Implementation of the difference-bound matrix (DBM) data structure.
|
|
*
|
|
* Data structures and algorithms are mostly based on those from:
|
|
* Johan Bengtsson, Wang Yi: Timed Automata: Semantics, Algorithms and Tools.
|
|
* Lectures on Concurrency and Petri Nets 2003, LNCS volume 3098, pages 87-124, Springer, 2004
|
|
*/
|
|
public class DBM extends Zone
|
|
{
|
|
/* Parent PTA */
|
|
protected PTA pta;
|
|
/*
|
|
* Canonical zone representation: DBM
|
|
* (numClocks+1)^2 matrix d, indexed 1...numClocks for clocks in PTA and 0 for special zero clock.
|
|
* Each entry d[i][j] gives the bound for clock difference xi-xj.
|
|
* Difference bounds are encoded as a single integer; see help class DB for details.
|
|
*/
|
|
protected int d[][];
|
|
|
|
/**
|
|
* Construct an empty DBM (don't use this).
|
|
*/
|
|
public DBM(PTA pta)
|
|
{
|
|
this.pta = pta;
|
|
this.d = new int[pta.numClocks + 1][pta.numClocks + 1];
|
|
}
|
|
|
|
// Methods required for Zone interface
|
|
|
|
/**
|
|
* Get parent PTA
|
|
*/
|
|
public PTA getPTA()
|
|
{
|
|
return pta;
|
|
}
|
|
|
|
// Zone operations (modify the zone)
|
|
|
|
/**
|
|
* Conjunction: add constraint x-y db
|
|
*/
|
|
public void addConstraint(int x, int y, int db)
|
|
{
|
|
// Check if this causes inconsistency (i.e. zone emptiness)
|
|
// and, if so, flag this by setting d[0][0] to -1;
|
|
if (DB.add(d[y][x], db) < DB.LEQ_ZERO)
|
|
d[0][0] = DB.LEQ_MINUS_ONE;
|
|
// Now add the constraint (if it is tighter than existing one)
|
|
else if (db < d[x][y]) {
|
|
int i, j, n, dTmp;
|
|
// Store new constraint
|
|
d[x][y] = db;
|
|
// Partial re-canonicalisation
|
|
// Note we do 2 (separate) outer iterations of Floyd-Warshall,
|
|
// unlike the incorrect formulation in the DBM algorithm notes.
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
dTmp = DB.add(d[i][x], d[x][j]);
|
|
if (dTmp < d[i][j])
|
|
d[i][j] = dTmp;
|
|
}
|
|
}
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
dTmp = DB.add(d[i][y], d[y][j]);
|
|
if (dTmp < d[i][j])
|
|
d[i][j] = dTmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Conjunction: add constraint c
|
|
*/
|
|
public void addConstraint(Constraint c)
|
|
{
|
|
addConstraint(c.x, c.y, c.db);
|
|
}
|
|
|
|
/**
|
|
* Conjunction: add multiple constraints
|
|
*/
|
|
public void addConstraints(Iterable<Constraint> constraints)
|
|
{
|
|
for (Constraint c : constraints)
|
|
addConstraint(c);
|
|
}
|
|
|
|
/**
|
|
* Conjunction: with another zone
|
|
*/
|
|
public void intersect(Zone z)
|
|
{
|
|
int i, j, n;
|
|
DBM dbm = (DBM) z;
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (i != j && !DB.isInfty(dbm.d[i][j]))
|
|
addConstraint(i, j, dbm.d[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Up, i.e. let time elapse, subject to some constraints
|
|
*/
|
|
public void up(Iterable<Constraint> constraints)
|
|
{
|
|
int i, n;
|
|
n = pta.numClocks;
|
|
for (i = 1; i < n + 1; i++) {
|
|
d[i][0] = DB.INFTY;
|
|
}
|
|
if (constraints != null) {
|
|
for (Constraint c : constraints) {
|
|
addConstraint(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Down, i.e. zone which can reach this one, subject to some constraints
|
|
*/
|
|
public void down(Iterable<Constraint> constraints)
|
|
{
|
|
int i, j, n;
|
|
n = pta.numClocks;
|
|
for (i = 1; i < n + 1; i++) {
|
|
d[0][i] = DB.LEQ_ZERO;
|
|
for (j = 1; j < n + 1; j++) {
|
|
if (d[j][i] < d[0][i])
|
|
d[0][i] = d[j][i];
|
|
}
|
|
}
|
|
if (constraints != null) {
|
|
for (Constraint c : constraints) {
|
|
addConstraint(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Free, i.e. remove constraints on a clock
|
|
*/
|
|
public void free(int x)
|
|
{
|
|
int i, n;
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
if (i != x) {
|
|
d[x][i] = DB.INFTY;
|
|
d[i][x] = d[i][0];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset clock x
|
|
*/
|
|
public void reset(int x, int v)
|
|
{
|
|
int i, n;
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
d[x][i] = DB.add(DB.createLeq(v), d[0][i]);
|
|
d[i][x] = DB.add(d[i][0], DB.createLeq(-v));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Backward reset of clock x
|
|
*/
|
|
public void backReset(int x, int v)
|
|
{
|
|
// Conjunction with constraint x=v
|
|
// (i.e. x-0 <= v && 0-x <= -v)
|
|
addConstraint(x, 0, DB.createLeq(v));
|
|
addConstraint(0, x, DB.createLeq(-v));
|
|
// Then "free" clock x
|
|
free(x);
|
|
}
|
|
|
|
/**
|
|
* c-Closure
|
|
*/
|
|
public void cClosure(int c)
|
|
{
|
|
int i, j, n;
|
|
if (isEmpty())
|
|
return;
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (!DB.isInfty(d[i][j]) && DB.createLeq(c) < d[i][j]) {
|
|
d[i][j] = DB.INFTY;
|
|
} else if (!DB.isInfty(d[i][j]) && d[i][j] < DB.createLt(-c)) {
|
|
d[i][j] = DB.createLt(-c);
|
|
}
|
|
}
|
|
}
|
|
canonicalise();
|
|
}
|
|
|
|
// Zone operations (create new zone)
|
|
|
|
/**
|
|
* Complement this DBM; creates a new DBM list as result.
|
|
*/
|
|
public DBMList createComplement()
|
|
{
|
|
DBMList list = new DBMList(pta);
|
|
DBM dbmNew;
|
|
int i, j, n;
|
|
// Special case: complement of empty DBM is True
|
|
if (isEmpty()) {
|
|
list.addDBM(createTrue(pta));
|
|
return list;
|
|
}
|
|
n = d.length - 1;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (i == j)
|
|
continue;
|
|
if (DB.isInfty(d[i][j]))
|
|
continue;
|
|
dbmNew = (DBM) new DBMFactory().createTrue(pta);
|
|
dbmNew.addConstraint(j, i, DB.dual(d[i][j]));
|
|
if (!dbmNew.isEmpty()) {
|
|
list.addDBM(dbmNew);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
// Zone queries (do not modify the zone)
|
|
|
|
/**
|
|
* Is this zone empty (i.e. inconsistent)?
|
|
*/
|
|
public boolean isEmpty()
|
|
{
|
|
// Internally, inconsistency is flagged by setting d[0][0] to -1.
|
|
// (Note: strictly speaking "<0" checks that the difference bound is less than "<0".)
|
|
return d[0][0] < 0;
|
|
}
|
|
|
|
/**
|
|
* Is constraint c satisfied by this zone (i.e does it overlap)?
|
|
*/
|
|
public boolean isSatisfied(Constraint c)
|
|
{
|
|
return DB.add(c.db, d[c.y][c.x]) > 0;
|
|
}
|
|
|
|
/**
|
|
* Is a DBM (fully) included in this zone?
|
|
*/
|
|
public boolean includes(DBM dbm)
|
|
{
|
|
int i, j, n;
|
|
int[][] d2 = dbm.d;
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (d[i][j] < d2[i][j])
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the minimum value of a clock.
|
|
*/
|
|
public int getClockMin(int x)
|
|
{
|
|
return -DB.getSignedDiff(d[0][x]);
|
|
}
|
|
|
|
/**
|
|
* Get the maximum value of a clock.
|
|
*/
|
|
public int getClockMax(int x)
|
|
{
|
|
return DB.getSignedDiff(d[x][0]);
|
|
}
|
|
|
|
/**
|
|
* Check if a clock is unbounded (can be infinite).
|
|
*/
|
|
public boolean clockIsUnbounded(int x)
|
|
{
|
|
return DB.isInfty(d[x][0]);
|
|
}
|
|
|
|
/**
|
|
* Check if all clocks are unbounded (can be infinite).
|
|
*/
|
|
public boolean allClocksAreUnbounded()
|
|
{
|
|
int i, n;
|
|
n = pta.numClocks;
|
|
for (i = 1; i < n + 1; i++) {
|
|
if (!DB.isInfty(d[i][0])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Misc
|
|
|
|
/**
|
|
* Clone this zone
|
|
*/
|
|
public DBM deepCopy()
|
|
{
|
|
int i, j, n;
|
|
DBM copy = new DBM(pta);
|
|
n = pta.numClocks;
|
|
copy.d = new int[n + 1][n + 1];
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
copy.d[i][j] = d[i][j];
|
|
}
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
/**
|
|
* Get storage info string
|
|
*/
|
|
public String storageInfo()
|
|
{
|
|
return "DBM with " + pta.numClocks + " clocks";
|
|
}
|
|
|
|
// Standard Java methods
|
|
|
|
public int hashCode()
|
|
{
|
|
// Simple hash code
|
|
return pta.numClocks;
|
|
}
|
|
|
|
public boolean equals(Object o)
|
|
{
|
|
DBM dbm;
|
|
int i, j, n;
|
|
if (o == null)
|
|
return false;
|
|
try {
|
|
dbm = (DBM) o;
|
|
} catch (ClassCastException e) {
|
|
return false;
|
|
}
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (d[i][j] != dbm.d[i][j])
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// To string methods
|
|
|
|
public String toString()
|
|
{
|
|
return toStringTextual();
|
|
}
|
|
|
|
/**
|
|
* Convert to string - textual representation
|
|
*/
|
|
public String toStringTextual()
|
|
{
|
|
int i, j, n;
|
|
boolean first = true;
|
|
String s = "", s2;
|
|
n = pta.numClocks;
|
|
// Trivial case - empty
|
|
if (isEmpty())
|
|
return "empty";
|
|
// Generate textual description for each difference (pair)
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = i + 1; j < n + 1; j++) {
|
|
s2 = null;
|
|
if (!DB.isInfty(d[i][j])) {
|
|
if (!DB.isInfty(d[j][i])) {
|
|
s2 = DB.constraintPairToString(i, j, d[i][j], d[j][i], pta);
|
|
} else {
|
|
s2 = DB.constraintToString(i, j, d[i][j], pta);
|
|
}
|
|
} else if (!DB.isInfty(d[j][i])) {
|
|
s2 = DB.constraintToString(j, i, d[j][i], pta);
|
|
}
|
|
if (s2 != null) {
|
|
if (!first)
|
|
s += ",";
|
|
else
|
|
first = false;
|
|
s += s2;
|
|
}
|
|
}
|
|
}
|
|
if ("".equals(s))
|
|
return "true";
|
|
else
|
|
return "{" + s + "}";
|
|
}
|
|
|
|
/**
|
|
* Convert to string - DBM representation
|
|
*/
|
|
public String toStringDBM()
|
|
{
|
|
int i, j, n;
|
|
String s = "[ ";
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (j > 0)
|
|
s += " ";
|
|
s += DB.toString(d[i][j]);
|
|
}
|
|
if (i < n)
|
|
s += ", ";
|
|
}
|
|
s += " ]";
|
|
return s;
|
|
}
|
|
|
|
/* Private utility methods */
|
|
|
|
/**
|
|
* Canonicalise, by applying Floyd-Warshall SPP algorithm
|
|
*/
|
|
private void canonicalise()
|
|
{
|
|
int k, i, j, db, n;
|
|
n = pta.numClocks;
|
|
for (k = 0; k < n + 1; k++) {
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
db = DB.add(d[i][k], d[k][j]);
|
|
if (db < d[i][j])
|
|
d[i][j] = db;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Static zone creation methods */
|
|
|
|
/**
|
|
* All clocks = 0
|
|
*/
|
|
public static DBM createZero(PTA pta)
|
|
{
|
|
int i, j, n;
|
|
DBM dbm = new DBM(pta);
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
dbm.d[i][j] = DB.LEQ_ZERO;
|
|
}
|
|
}
|
|
return dbm;
|
|
}
|
|
|
|
/**
|
|
* All clocks any (non-negative) value
|
|
*/
|
|
public static DBM createTrue(PTA pta)
|
|
{
|
|
int i, j, n;
|
|
DBM dbm = new DBM(pta);
|
|
n = pta.numClocks;
|
|
for (i = 0; i < n + 1; i++) {
|
|
for (j = 0; j < n + 1; j++) {
|
|
if (i == j)
|
|
dbm.d[i][j] = DB.LEQ_ZERO;
|
|
else if (i == 0)
|
|
dbm.d[i][j] = DB.LEQ_ZERO;
|
|
else
|
|
dbm.d[i][j] = DB.INFTY;
|
|
}
|
|
}
|
|
return dbm;
|
|
}
|
|
|
|
/**
|
|
* Zone defined by set of constraints
|
|
*/
|
|
public static DBM createFromConstraints(PTA pta, Iterable<Constraint> constrs)
|
|
{
|
|
DBM dbm = createTrue(pta);
|
|
for (Constraint c : constrs) {
|
|
dbm.addConstraint(c);
|
|
}
|
|
return dbm;
|
|
}
|
|
}
|