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.
579 lines
11 KiB
579 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;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* List of DBMs representing a non-convex zone.
|
|
*
|
|
* See this reference for some useful algorithms:
|
|
* S. Tripakis. The formal analysis of timed systems in practice. Joseph Fourier University, 1998.
|
|
*/
|
|
public class DBMList extends NCZone
|
|
{
|
|
/* Parent PTA */
|
|
protected PTA pta;
|
|
/* List of DBMs */
|
|
protected ArrayList<DBM> list;
|
|
|
|
/* Should we check for inclusion of DBMs as we go? */
|
|
public static boolean checkInclusion = true;
|
|
|
|
/**
|
|
* Default constructor
|
|
*/
|
|
public DBMList(PTA pta)
|
|
{
|
|
this.pta = pta;
|
|
list = new ArrayList<DBM>();
|
|
}
|
|
|
|
/**
|
|
* Copy constructor: create single list from existing DBM(List)
|
|
*/
|
|
public DBMList(Zone z)
|
|
{
|
|
// From DBM
|
|
if (z instanceof DBM) {
|
|
DBM dbm = (DBM)z;
|
|
this.pta = dbm.pta;
|
|
list = new ArrayList<DBM>();
|
|
addDBM(dbm);
|
|
}
|
|
// From DBM
|
|
else {
|
|
DBMList dbml = (DBMList)z;
|
|
this.pta = dbml.pta;
|
|
list = new ArrayList<DBM>();
|
|
for (DBM dbm : dbml.list) {
|
|
list.add((DBM) dbm.deepCopy());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a DBM to the list
|
|
*/
|
|
public void addDBM(DBM dbm)
|
|
{
|
|
int i, n;
|
|
BitSet toRemove;
|
|
// If we don't want to check inclusions, just add
|
|
if (!checkInclusion) {
|
|
list.add(dbm);
|
|
}
|
|
// Otherwise look at existing DBMs
|
|
else {
|
|
n = list.size();
|
|
toRemove = new BitSet(n);
|
|
i = 0;
|
|
for (DBM dbm2 : list) {
|
|
if (dbm2.includes(dbm)) {
|
|
// New DBM already included inside something - don't add
|
|
return;
|
|
} else if (dbm.includes(dbm2)) {
|
|
// This DBM is will be redundant when new DBM is added
|
|
toRemove.set(i);
|
|
}
|
|
i++;
|
|
}
|
|
// Remove (now) redundant ones
|
|
for (i = n - 1; i >= 0; i--) {
|
|
if (toRemove.get(i))
|
|
list.remove(i);
|
|
}
|
|
// Add DBM
|
|
list.add(dbm);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a list of DBMs to the list
|
|
*/
|
|
public void addDBMs(DBMList dbml)
|
|
{
|
|
for (DBM dbm : dbml.list)
|
|
addDBM(dbm);
|
|
}
|
|
|
|
// Methods required for Zone interface
|
|
|
|
/**
|
|
* Get parent PTA
|
|
*/
|
|
public PTA getPTA()
|
|
{
|
|
return pta;
|
|
}
|
|
|
|
/**
|
|
* Get DBM
|
|
*/
|
|
public DBM getDBM(int i)
|
|
{
|
|
return list.get(i);
|
|
}
|
|
|
|
// Zone operations (modify the zone)
|
|
|
|
/**
|
|
* Conjunction: add constraint x-y db
|
|
*/
|
|
public void addConstraint(int x, int y, int db)
|
|
{
|
|
for (DBM dbm : list) {
|
|
dbm.addConstraint(x, y, db);
|
|
}
|
|
if (checkInclusion)
|
|
removeInclusions();
|
|
}
|
|
|
|
/**
|
|
* 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, n1, n2;
|
|
if (z instanceof DBM)
|
|
z = new DBMList((DBM) z);
|
|
DBMList dbml = (DBMList) z;
|
|
DBMList listNew;
|
|
DBM dbmNew;
|
|
listNew = new DBMList(pta);
|
|
n1 = list.size();
|
|
n2 = dbml.list.size();
|
|
for (i = 0; i < n1; i++) {
|
|
for (j = 0; j < n2; j++) {
|
|
dbmNew = list.get(i).deepCopy();
|
|
dbmNew.intersect(dbml.list.get(j));
|
|
if (!dbmNew.isEmpty())
|
|
listNew.addDBM(dbmNew);
|
|
}
|
|
}
|
|
list = listNew.list;
|
|
}
|
|
|
|
/**
|
|
* Up, i.e. let time elapse, subject to some constraints
|
|
*/
|
|
public void up(Iterable<Constraint> constraints)
|
|
{
|
|
for (DBM dbm : list) {
|
|
dbm.up(constraints);
|
|
}
|
|
if (checkInclusion)
|
|
removeInclusions();
|
|
}
|
|
|
|
/**
|
|
* Down, i.e. zone which can reach this one, subject to some constraints
|
|
*/
|
|
public void down(Iterable<Constraint> constraints)
|
|
{
|
|
for (DBM dbm : list) {
|
|
dbm.down(constraints);
|
|
}
|
|
if (checkInclusion)
|
|
removeInclusions();
|
|
}
|
|
|
|
/**
|
|
* Free, i.e. remove constraints on a clock
|
|
*/
|
|
public void free(int x)
|
|
{
|
|
// Existential quantification distributes over union
|
|
for (DBM dbm : list) {
|
|
dbm.free(x);
|
|
}
|
|
if (checkInclusion)
|
|
removeInclusions();
|
|
}
|
|
|
|
/**
|
|
* Reset clock x
|
|
*/
|
|
public void reset(int x, int v)
|
|
{
|
|
// NOT IMPLEMENTED
|
|
throw new RuntimeException("Not implemented yet");
|
|
}
|
|
|
|
/**
|
|
* Backward reset of clock x
|
|
*/
|
|
public void backReset(int x, int v)
|
|
{
|
|
// Implemented as conjunction, then "free"
|
|
// (see method in DBM class),
|
|
// both of which distribute over union
|
|
for (DBM dbm : list) {
|
|
dbm.addConstraint(x, 0, DB.createLeq(v));
|
|
dbm.addConstraint(0, x, DB.createLeq(-v));
|
|
}
|
|
for (DBM dbm : list) {
|
|
dbm.free(x);
|
|
}
|
|
if (checkInclusion)
|
|
removeInclusions();
|
|
}
|
|
|
|
/**
|
|
* c-Closure
|
|
*/
|
|
public void cClosure(int c)
|
|
{
|
|
// NOT IMPLEMENTED
|
|
throw new RuntimeException("Not implemented yet");
|
|
}
|
|
|
|
// Zone operations (create new zone)
|
|
|
|
/**
|
|
* Complement
|
|
* Creates non-convex zone so creates new one,
|
|
* and leaves this one unmodified
|
|
*/
|
|
public DBMList createComplement()
|
|
{
|
|
DBMList dbml = deepCopy();
|
|
dbml.complement();
|
|
return dbml;
|
|
}
|
|
|
|
// Zone queries (do not modify the zone)
|
|
|
|
/**
|
|
* Is this zone empty (i.e. inconsistent)?
|
|
*/
|
|
public boolean isEmpty()
|
|
{
|
|
for (DBM dbm : list) {
|
|
if (!dbm.isEmpty())
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Is constraint c satisfied by this zone (i.e does it overlap)?
|
|
*/
|
|
public boolean isSatisfied(Constraint c)
|
|
{
|
|
for (DBM dbm : list) {
|
|
if (!dbm.isSatisfied(c))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Is a DBM (fully) included in this zone?
|
|
*/
|
|
public boolean includes(DBM dbm)
|
|
{
|
|
for (DBM dbm2 : list) {
|
|
if (dbm2.includes(dbm))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the minimum value of a clock.
|
|
*/
|
|
public int getClockMin(int x)
|
|
{
|
|
// Take min across all DBMs
|
|
int min = Integer.MAX_VALUE;
|
|
for (DBM dbm : list) {
|
|
min = Math.min(min, dbm.getClockMin(x));
|
|
}
|
|
return min;
|
|
}
|
|
|
|
/**
|
|
* Get the maximum value of a clock.
|
|
*/
|
|
public int getClockMax(int x)
|
|
{
|
|
// Take max across all DBMs
|
|
int max = Integer.MIN_VALUE;
|
|
for (DBM dbm : list) {
|
|
max = Math.max(max, dbm.getClockMax(x));
|
|
}
|
|
return max;
|
|
}
|
|
|
|
/**
|
|
* Check if a clock is unbounded (can be infinite).
|
|
*/
|
|
public boolean clockIsUnbounded(int x)
|
|
{
|
|
// Clock is unbounded if is in any DBM
|
|
for (DBM dbm : list) {
|
|
if (dbm.clockIsUnbounded(x))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 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 (!clockIsUnbounded(i)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Methods required for NCZone interface
|
|
|
|
/**
|
|
* Conjunction: with complement of another zone
|
|
*/
|
|
public void intersectComplement(Zone z)
|
|
{
|
|
if (z instanceof DBM)
|
|
z = new DBMList((DBM) z);
|
|
DBMList dbml = (DBMList) z;
|
|
for (DBM dbm : dbml.list) {
|
|
DBMList listTmp = dbm.createComplement();
|
|
intersect(listTmp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Complement
|
|
*/
|
|
public void complement()
|
|
{
|
|
DBMList listNew, res;
|
|
res = null;
|
|
// Special case: complement of empty DBM list is True
|
|
if (list.size() == 0)
|
|
addDBM(DBM.createTrue(pta));
|
|
// The complement of a list of DBMs is the intersection
|
|
// of the complement of each DBM (and the complement of
|
|
// of a DBM is a DBM list).
|
|
for (DBM dbm : list) {
|
|
listNew = dbm.createComplement();
|
|
if (res == null)
|
|
res = listNew;
|
|
else {
|
|
res.intersect(listNew);
|
|
}
|
|
// Stop early if res already empty
|
|
if (res.list.size() == 0)
|
|
break;
|
|
}
|
|
list = res.list;
|
|
}
|
|
|
|
/**
|
|
* Disjunction: with another zone
|
|
*/
|
|
public void union(Zone z)
|
|
{
|
|
if (z instanceof DBM) {
|
|
addDBM((DBM) z);
|
|
}
|
|
else {
|
|
addDBMs((DBMList) z);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get some (any) convex zone contained within this zone.
|
|
* Returns null if this zone is empty.
|
|
*/
|
|
public Zone getAZone()
|
|
{
|
|
if (list.size() > 0)
|
|
return list.get(0);
|
|
else return null;
|
|
}
|
|
|
|
/**
|
|
* Get the number of DBMs in this DBMList.
|
|
* @return
|
|
*/
|
|
public int size()
|
|
{
|
|
return list.size();
|
|
}
|
|
|
|
/**
|
|
* Clone this zone
|
|
*/
|
|
public DBMList deepCopy()
|
|
{
|
|
DBMList copy = new DBMList(pta);
|
|
for (DBM dbm : list) {
|
|
copy.list.add((DBM) dbm.deepCopy());
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
// Standard Java methods
|
|
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
// Simple hash code
|
|
return list.size();
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o)
|
|
{
|
|
DBMList dbml;
|
|
int i, n;
|
|
if (o == null)
|
|
return false;
|
|
try {
|
|
dbml = (DBMList) o;
|
|
} catch (ClassCastException e) {
|
|
return false;
|
|
}
|
|
n = list.size();
|
|
if (n != dbml.list.size())
|
|
return false;
|
|
for (i = 0; i < n; i++) {
|
|
if (!list.get(i).equals(dbml.list.get(i)))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// To string methods
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return "" + list;
|
|
}
|
|
|
|
/**
|
|
* Get storage info string
|
|
*/
|
|
public String storageInfo()
|
|
{
|
|
return "List of " + list.size() + " DBMs with " + pta.numClocks + " clocks";
|
|
}
|
|
|
|
// Static zone creation methods
|
|
|
|
/**
|
|
* Create empty DBM list (i.e. false)
|
|
*/
|
|
public static DBMList createFalse(PTA pta)
|
|
{
|
|
DBMList dbml = new DBMList(pta);
|
|
return dbml;
|
|
}
|
|
|
|
// Private utility methods
|
|
|
|
private void removeInclusions()
|
|
{
|
|
int i, j, n;
|
|
DBM dbm1, dbm2;
|
|
BitSet toRemove;
|
|
n = list.size();
|
|
toRemove = new BitSet(n);
|
|
for (i = 0; i < n; i++) {
|
|
if (toRemove.get(i))
|
|
continue;
|
|
dbm1 = list.get(i);
|
|
for (j = i + 1; j < n; j++) {
|
|
if (toRemove.get(i) || toRemove.get(j))
|
|
continue;
|
|
dbm2 = list.get(j);
|
|
if (dbm2.includes(dbm1))
|
|
toRemove.set(i);
|
|
else if (dbm1.includes(dbm2))
|
|
toRemove.set(j);
|
|
}
|
|
}
|
|
for (i = n - 1; i >= 0; i--) {
|
|
if (toRemove.get(i))
|
|
list.remove(i);
|
|
}
|
|
}
|
|
|
|
// Test program for complementing big DBM lists
|
|
|
|
public static void main(String args[])
|
|
{
|
|
int numClocks = 7;
|
|
int i, j, x, y, db;
|
|
Random generator = new Random();
|
|
PTA pta = new PTA();
|
|
for (i = 0; i < numClocks; i++) {
|
|
pta.addClock("" + i);
|
|
}
|
|
DBMList dbml = new DBMList(pta);
|
|
for (i = 0; i < 5; i++) {
|
|
DBM dbm = DBM.createTrue(pta);
|
|
for (j = 0; j < 10; j++) {
|
|
x = generator.nextInt(numClocks);
|
|
y = generator.nextInt(numClocks);
|
|
db = generator.nextInt();
|
|
dbm.addConstraint(x, y, db);
|
|
}
|
|
dbml.addDBM(dbm);
|
|
}
|
|
System.out.println(dbml.storageInfo());
|
|
dbml.complement();
|
|
System.out.println(dbml.storageInfo());
|
|
}
|
|
}
|