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.
 
 
 
 
 
 

206 lines
5.8 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.Comparator;
import java.util.HashSet;
import java.util.PriorityQueue;
/**
* Stores a given partitioning of the states of a Markov model.
* This class is intended to be used in combination with signature-based
* partitioning refinement. In addition to storing the states, it can also
* compute which blocks become subject to change due to changes in other
* blocks.
*
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
*/
final class Partition {
/**
* Comparator class comparing integer hash sets according to their size.
*
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
*/
final class HashSetSizeComparator implements Comparator<HashSet<Integer>> {
@Override
public int compare(HashSet<Integer> o1, HashSet<Integer> o2) {
int size1 = o1.size();
int size2 = o2.size();
// TODO should actually be other way round, but slower then... ??
if (size1 < size2) {
return 1;
} else if (size1 == size2) {
return 0;
} else {
return -1;
}
}
@Override
public boolean equals(Object obj) {
return obj instanceof HashSetSizeComparator;
}
@Override
public int hashCode() {
return 0;
}
}
/** parametric Markov chain this partition is for */
private MutablePMC pmc;
/** all blocks of this partitioning */
private HashSet<HashSet<Integer>> blocks;
/** maps states to the block they are contained in */
private ArrayList<HashSet<Integer>> stateToBlock;
/** list of blocks which might need to be refined */
private PriorityQueue<HashSet<Integer>> mayChange;
/** hash set of blocks which might need to be refined */
private HashSet<HashSet<Integer>> mayChangeHash;
/** next block to refine */
private HashSet<Integer> nextBlock;
/**
* Creates new partitioning for given parametric Markov chain.
* Initially, all states will be in the same block.
*
* @param pmc parametric Markov chain to create partitioning of
*/
Partition(MutablePMC pmc)
{
this.pmc = pmc;
blocks = new HashSet<HashSet<Integer>>();
stateToBlock = new ArrayList<HashSet<Integer>>(pmc.getNumStates());
HashSet<Integer> initialBlock = new HashSet<Integer>(1);
mayChange = new PriorityQueue<HashSet<Integer>>(11, new HashSetSizeComparator());
mayChangeHash = new HashSet<HashSet<Integer>>();
for (int state = 0; state < pmc.getNumStates(); state++) {
initialBlock.add(state);
stateToBlock.add(initialBlock);
}
blocks.add(initialBlock);
mayChange.add(initialBlock);
mayChangeHash.add(initialBlock);
}
/**
* Obtain the next changeable block, according to their priority (size).
*
* @return next changeable block
*/
HashSet<Integer> nextChangeableBlock()
{
nextBlock = mayChange.poll();
mayChangeHash.remove(nextBlock);
blocks.remove(nextBlock);
return nextBlock;
}
/**
* Add a list of new blocks to list of blocks.
* Also marks existing blocks as subject to change in case they have
* transitions into these new blocks, and thus might have to be split.
*
* @param newBlocks list of blocks to add
*/
void addBlocks(ArrayList<HashSet<Integer>> newBlocks)
{
blocks.addAll(newBlocks);
for (HashSet<Integer> block : newBlocks) {
for (int state : block) {
stateToBlock.set(state, block);
}
if (block.equals(nextBlock)) {
return;
}
mayChange.add(block);
mayChangeHash.add(block);
}
for (HashSet<Integer> block : newBlocks) {
for (int state : block) {
for (int predec : pmc.incoming.get(state)) {
HashSet<Integer> predecBlock = stateToBlock.get(predec);
if (!nextBlock.contains(predec) && !mayChangeHash.contains(predecBlock) && (predecBlock.size() > 1)) {
mayChange.add(predecBlock);
mayChangeHash.add(predecBlock);
}
}
}
}
}
/**
* Checks whether there are blocks remaining which might need refinement.
*
* @return true iff blocks are remaining which might need refinement
*/
boolean mayChange()
{
return !mayChange.isEmpty();
}
/**
* Obtain a list of all blocks of the partition.
*
* @return list of all blocks of the partition
*/
ArrayList<HashSet<Integer>> getAllBlocks()
{
ArrayList<HashSet<Integer>> allBlocks = new ArrayList<HashSet<Integer>>(blocks.size());
for (HashSet<Integer> block : blocks) {
allBlocks.add(block);
}
return allBlocks;
}
/**
* Get the block in which a given state is contained.
*
* @param state state to search containing block of
* @return block state is contained in
*/
HashSet<Integer> getStateBlock(int state)
{
return stateToBlock.get(state);
}
/**
* Marks all blocks as being new.
*/
void markAllBlocksAsNew()
{
mayChange.clear();
mayChangeHash.clear();
for (HashSet<Integer> block : blocks) {
mayChange.add(block);
mayChangeHash.add(block);
}
}
}