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.
 
 
 
 
 
 

200 lines
6.1 KiB

//==============================================================================
//
// Copyright (c) 2013-
// Authors:
// * Ernst Moritz Hahn <emhahn@cs.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 param;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Checks if functions are (strictly) larger than zero in whole region.
* This class implements only an approximate check. This means, that
* functions are only evaluated in a finite number of points, so that it
* is unlikely but not impossible that there are other points in the
* region which are below (or equal) to zero. Derived classes might
* use a constraint solver to guarantee validity of this check.
*
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
*/
class ConstraintChecker {
/**
* Class to store keys for the cache of the decision procedure.
*/
class DecisionEntryKey {
/** constraint to be stored (representing "constraint >=/> 0") */
Function constraint;
/** whether constraint should be strictly larger than zero */
boolean strict;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DecisionEntryKey)) {
return false;
}
DecisionEntryKey other = (DecisionEntryKey) obj;
return this.constraint.equals(other.constraint) && (this.strict == other.strict);
}
@Override
public int hashCode() {
int hash = 0;
hash = constraint.hashCode() + (hash << 6) + (hash << 16) - hash;
hash = (strict ? 13 : 17) + (hash << 6) + (hash << 16) - hash;
return hash;
}
}
/**
* Class to store keys for the cache of the decision procedure.
*/
class DecisionEntryValue {
/** region this result is valid for */
Region region;
/** result, that is whether corresponding constraint holds in region */
boolean result;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DecisionEntryValue)) {
return false;
}
DecisionEntryValue other = (DecisionEntryValue) obj;
return this.region.equals(other.region) && (this.result == other.result);
}
@Override
public int hashCode() {
int hash = 0;
hash = region.hashCode() + (hash << 6) + (hash << 16) - hash;
hash = (result ? 13 : 17) + (hash << 6) + (hash << 16) - hash;
return hash;
}
}
/** number of random points to evaluate in decision procedure */
private int numRandomPoints;
/** decision cache */
protected HashMap<DecisionEntryKey,ArrayList<DecisionEntryValue>> decisions;
/**
* Constructs a new constraint checker.
*
* @param numRandomPoints number of inner points to evaluate in addition to border points
*/
ConstraintChecker(int numRandomPoints) {
this.numRandomPoints = numRandomPoints;
decisions = new HashMap<DecisionEntryKey,ArrayList<DecisionEntryValue>>();
}
/**
* Main decision check.
* In this class, does nothing. Derived class could override this method
* for instance by calling an external decision procedure, use a library
* to decide validity in a given region, etc.
*
* @param region region for which to check validity of constraint
* @param constraint constraint to check (whether >=/> 0)
* @param strict true iff ">" shold be checked rathern than ">="
* @return true
*/
boolean mainCheck(Region region, Function constraint, boolean strict)
{
return true;
}
/**
* Does a quick pre-check by evaluating constraint at random points.
*
* @param region region for which to check validity of constraint
* @param constraint constraint to check (whether >=/> 0)
* @param strict true iff ">" shold be checked rathern than ">="
* @return true if no counterexamples to validity found
*/
boolean preCheck(Region region, Function constraint, boolean strict)
{
ArrayList<Point> points = region.specialPoints();
for (Point point : points) {
if (!constraint.check(point, strict)) {
return false;
}
}
for (int pointNr = 0; pointNr < numRandomPoints; pointNr++) {
if (!constraint.check(region.randomPoint(), strict)) {
return false;
}
}
return true;
}
/**
* Checks whether constraint holds in given region.
*
* @param region region for which to check validity of constraint
* @param constraint constraint to check (whether >=/> 0)
* @param strict true iff ">" shold be checked rathern than ">="
* @return true iff function values are (strictly) larger than zero in whole region
*/
boolean check(Region region, Function constraint, boolean strict)
{
Function constr = constraint.toConstraint();
DecisionEntryKey key = new DecisionEntryKey();
key.constraint = constr;
key.strict = strict;
ArrayList<DecisionEntryValue> entries = decisions.get(key);
if (entries != null) {
for (DecisionEntryValue entry : entries) {
if (entry.region.contains(region)) {
if (entry.result) {
return true;
} else if (entry.region.equals(region)) {
return false;
}
}
}
}
boolean result = preCheck(region, constr, strict);
if (result) {
result = mainCheck(region, constr, strict);
}
entries = decisions.get(key);
if (entries == null) {
entries = new ArrayList<DecisionEntryValue>();
decisions.put(key, entries);
}
DecisionEntryValue entry = new DecisionEntryValue();
entry.region = region;
entry.result = result;
entries.add(entry);
return result;
}
}