@ -48,7 +48,7 @@ namespace storm { 
			
		
	
		
			
				
					                refinementQueue . pop_front ( ) ;  
			
		
	
		
			
				
					                blocksInRefinementQueue . set ( currentBlock ,  false ) ;  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                splitBlock ( dtmc ,  backwardTransitions ,  currentBlock ,  stateToBlockMapping ,  distributions ,  blocksInRefinementQueue ,  refinementQueue ) ;  
			
		
	
		
			
				
					                splitBlock ( dtmc ,  backwardTransitions ,  currentBlock ,  stateToBlockMapping ,  distributions ,  blocksInRefinementQueue ,  refinementQueue ,  weak ) ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : duration  totalTime  =  std : : chrono : : high_resolution_clock : : now ( )  -  totalStart ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -57,52 +57,96 @@ namespace storm { 
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        template < typename  ValueType >  
			
		
	
		
			
				
					        std : : size_t  BisimulationDecomposition < ValueType > : : splitPredecessorsGraphBased ( storm : : models : : Dtmc < ValueType >  const &  dtmc ,  storm : : storage : : SparseMatrix < ValueType >  const &  backwardTransitions ,  std : : size_t  const &  blockId ,  std : : vector < std : : size_t > &  stateToBlockMapping ,  std : : vector < storm : : storage : : Distribution < ValueType > > &  distributions ,  storm : : storage : : BitVector &  blocksInRefinementQueue ,  std : : deque < std : : size_t > &  graphRefinementQueue )  {  
			
		
	
		
			
				
					        std : : size_t  BisimulationDecomposition < ValueType > : : splitPredecessorsGraphBased ( storm : : models : : Dtmc < ValueType >  const &  dtmc ,  storm : : storage : : SparseMatrix < ValueType >  const &  backwardTransitions ,  std : : size_t  const &  blockId ,  std : : vector < std : : size_t > &  stateToBlockMapping ,  std : : vector < storm : : storage : : Distribution < ValueType > > &  distributions ,  storm : : storage : : BitVector &  blocksInRefinementQueue ,  std : : deque < std : : size_t > &  graphRefinementQueue ,  storm : : storage : : BitVector &  splitBlocks )  {  
			
		
	
		
			
				
					            std : : cout  < <  " entering  "  < <  std : : endl ;  
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : time_point  totalStart  =  std : : chrono : : high_resolution_clock : : now ( ) ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					//            std::cout << "refining predecessors of " << blockId << std::endl;
  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // This method tries to split the blocks of predecessors of the provided block by checking whether there is
  
			
		
	
		
			
				
					            // a transition into the current block or not.
  
			
		
	
		
			
				
					            std : : unordered_map < std : : size_t ,  typename  BisimulationDecomposition < ValueType > : : block_type >  predecessorBlockToNewBlock ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Now for each predecessor block which state could actually reach the current block.
  
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : time_point  predIterStart  =  std : : chrono : : high_resolution_clock : : now ( ) ;  
			
		
	
		
			
				
					            int  predCounter  =  0 ;  
			
		
	
		
			
				
					            storm : : storage : : BitVector  preds ( dtmc . getNumberOfStates ( ) ) ;  
			
		
	
		
			
				
					            for  ( auto  const &  state  :  this - > blocks [ blockId ] )  {  
			
		
	
		
			
				
					                for  ( auto  const &  predecessorEntry  :  backwardTransitions . getRow ( state ) )  {  
			
		
	
		
			
				
					                    + + predCounter ;  
			
		
	
		
			
				
					                    storm : : storage : : sparse : : state_type  predecessor  =  predecessorEntry . getColumn ( ) ;  
			
		
	
		
			
				
					                    predecessorBlockToNewBlock [ stateToBlockMapping [ predecessor ] ] . insert ( predecessor ) ;  
			
		
	
		
			
				
					                    if  ( ! preds . get ( predecessor ) )  {  
			
		
	
		
			
				
					//                        std::cout << "having pred " << predecessor << " with block " << stateToBlockMapping[predecessor] << std::endl;
  
			
		
	
		
			
				
					                        predecessorBlockToNewBlock [ stateToBlockMapping [ predecessor ] ] . insert ( predecessor ) ;  
			
		
	
		
			
				
					                        preds . set ( predecessor ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : duration  predIterTime  =  std : : chrono : : high_resolution_clock : : now ( )  -  predIterStart ;  
			
		
	
		
			
				
					            std : : cout  < <  " took  "  < <  std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( predIterTime ) . count ( )  < <  " ms. for  "  < <  predCounter  < <  "  predecessors "  < <  std : : endl ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            // Now, we can check for each predecessor block whether it needs to be split.
  
			
		
	
		
			
				
					            for  ( auto  const &  blockNewBlockPair  :  predecessorBlockToNewBlock )  {  
			
		
	
		
			
				
					                if  ( this - > blocks [ blockNewBlockPair . first ] . size ( )  >  blockNewBlockPair . second . size ( ) )  {  
			
		
	
		
			
				
					                    // Add the states which have a successor in the current block to a totally new block.
  
			
		
	
		
			
				
					                    this - > blocks . emplace_back ( std : : move ( blockNewBlockPair . second ) ) ;  
			
		
	
		
			
				
					                    std : : cout  < <  " splitting! "  < <  std : : endl ;  
			
		
	
		
			
				
					//                    std::cout << "found that not all " << this->blocks[blockNewBlockPair.first].size() << " states of block " << blockNewBlockPair.first << " have a successor in " << blockId << " but only " << blockNewBlockPair.second.size() << std::endl;
  
			
		
	
		
			
				
					//                    std::cout << "original: " << this->blocks[blockNewBlockPair.first] << std::endl;
  
			
		
	
		
			
				
					//                    std::cout << "states with pred: " << blockNewBlockPair.second << std::endl;
  
			
		
	
		
			
				
					                    // Now update the block mapping for the smaller of the two blocks.
  
			
		
	
		
			
				
					                    typename  BisimulationDecomposition < ValueType > : : block_type  smallerBlock ;  
			
		
	
		
			
				
					                    typename  BisimulationDecomposition < ValueType > : : block_type  largerBlock ;  
			
		
	
		
			
				
					                    if  ( blockNewBlockPair . second . size ( )  <  this - > blocks [ blockNewBlockPair . first ] . size ( ) / 2 )  {  
			
		
	
		
			
				
					                        smallerBlock  =  std : : move ( blockNewBlockPair . second ) ;  
			
		
	
		
			
				
					                        std : : set_difference ( this - > blocks [ blockNewBlockPair . first ] . begin ( ) ,  this - > blocks [ blockNewBlockPair . first ] . end ( ) ,  smallerBlock . begin ( ) ,  smallerBlock . end ( ) ,  std : : inserter ( largerBlock ,  largerBlock . begin ( ) ) ) ;  
			
		
	
		
			
				
					                    }  else  {  
			
		
	
		
			
				
					                        largerBlock  =  std : : move ( blockNewBlockPair . second ) ;  
			
		
	
		
			
				
					                        std : : set_difference ( this - > blocks [ blockNewBlockPair . first ] . begin ( ) ,  this - > blocks [ blockNewBlockPair . first ] . end ( ) ,  largerBlock . begin ( ) ,  largerBlock . end ( ) ,  std : : inserter ( smallerBlock ,  smallerBlock . begin ( ) ) ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    // Compute the set of states that remains in the old block;
  
			
		
	
		
			
				
					                    typename  BisimulationDecomposition < ValueType > : : block_type  newBlock ;  
			
		
	
		
			
				
					                    std : : set_difference ( this - > blocks [ blockId ] . begin ( ) ,  this - > blocks [ blockId ] . end ( ) ,  this - > blocks . back ( ) . begin ( ) ,  this - > blocks . back ( ) . end ( ) ,  std : : inserter ( newBlock ,  newBlock . begin ( ) ) ) ;  
			
		
	
		
			
				
					                    this - > blocks [ blockNewBlockPair . first ]  =  std : : move ( newBlock ) ;  
			
		
	
		
			
				
					//                    std::cout << "created a smaller block with " << smallerBlock.size() << " states and a larger one with " << largerBlock.size() << "states" << std::endl;
  
			
		
	
		
			
				
					//                    std::cout << "smaller: " << smallerBlock << std::endl;
  
			
		
	
		
			
				
					//                    std::cout << "larger: " << largerBlock << std::endl;
  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    this - > blocks . emplace_back ( std : : move ( smallerBlock ) ) ;  
			
		
	
		
			
				
					                    this - > blocks [ blockNewBlockPair . first ]  =  std : : move ( largerBlock ) ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    // Update the block mapping of all moved states.
  
			
		
	
		
			
				
					                    std : : size_t  newBlockId  =  this - > blocks . size ( )  -  1 ;  
			
		
	
		
			
				
					                    for  ( auto  const &  state  :  this - > blocks . back ( ) )  {  
			
		
	
		
			
				
					                        stateToBlockMapping [ state ]  =  newBlockId ;  
			
		
	
		
			
				
					//                        std::cout << "updating " << state << " to block " << newBlockId << std::endl;
  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    blocksInRefinementQueue . resize ( this - > blocks . size ( ) ) ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    // Add the smaller part of the old block to the queue.
  
			
		
	
		
			
				
					                    std : : size_t  blockToAddToQueue  =  this - > blocks . back ( ) . size ( )  <  this - > blocks [ blockNewBlockPair . first ] . size ( )  ?  this - > blocks . size ( )  -  1  :  blockNewBlockPair . first ;  
			
		
	
		
			
				
					                    if  ( ! blocksInRefinementQueue . get ( blockToAddToQueue ) )  {  
			
		
	
		
			
				
					                        graphRefinementQueue . push_back ( blockToAddToQueue ) ;  
			
		
	
		
			
				
					                        blocksInRefinementQueue . set ( blockToAddToQueue ,  true ) ;  
			
		
	
		
			
				
					                    // Add bo th parts  of the old block to the queue.
  
			
		
	
		
			
				
					                    if  ( ! blocksInRefinementQueue . get ( blockNewBlockPair . first ) )  {  
			
		
	
		
			
				
					                        graphRefinementQueue . push_back ( blockNewBlockPair . first ) ;   
			
		
	
		
			
				
					                        blocksInRefinementQueue . set ( blockNewBlockPair . first ,  tr ue) ;  
			
		
	
		
			
				
					//                        std::cout << "adding " << blockNewBlockPair.first << " to refine further using graph-based analysis " << std::endl;
  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    graphRefinementQueue . push_back ( this - > blocks . size ( )  -  1 ) ;  
			
		
	
		
			
				
					                    blocksInRefinementQueue . set ( this - > blocks . size ( )  -  1 ) ;  
			
		
	
		
			
				
					//                    std::cout << "adding " << this->blocks.size() - 1 << " to refine further using graph-based analysis " << std::endl;
  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : duration  totalTime  =  std : : chrono : : high_resolution_clock : : now ( )  -  totalStart ;  
			
		
	
		
			
				
					            std : : cout  < <  " refinement of predecessors of block  "  < <  blockId  < <  "  took  "  < <  std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( totalTime ) . count ( )  < <  " ms. "  < <  std : : endl ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					//            std::cout << "done. "<< std::endl;
  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // FIXME
  
			
		
	
		
			
				
					            return  0 ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        template < typename  ValueType >  
			
		
	
		
			
				
					        std : : size_t  BisimulationDecomposition < ValueType > : : splitBlock ( storm : : models : : Dtmc < ValueType >  const &  dtmc ,  storm : : storage : : SparseMatrix < ValueType >  const &  backwardTransitions ,  std : : size_t  const &  blockId ,  std : : vector < std : : size_t > &  stateToBlockMapping ,  std : : vector < storm : : storage : : Distribution < ValueType > > &  distributions ,  storm : : storage : : BitVector &  blocksInRefinementQueue ,  std : : deque < std : : size_t > &  refinementQueue )  {  
			
		
	
		
			
				
					        std : : size_t  BisimulationDecomposition < ValueType > : : splitBlock ( storm : : models : : Dtmc < ValueType >  const &  dtmc ,  storm : : storage : : SparseMatrix < ValueType >  const &  backwardTransitions ,  std : : size_t  const &  blockId ,  std : : vector < std : : size_t > &  stateToBlockMapping ,  std : : vector < storm : : storage : : Distribution < ValueType > > &  distributions ,  storm : : storage : : BitVector &  blocksInRefinementQueue ,  std : : deque < std : : size_t > &  refinementQueue ,  bool  weakBisimulation )  {  
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : time_point  totalStart  =  std : : chrono : : high_resolution_clock : : now ( ) ;  
			
		
	
		
			
				
					            std : : unordered_map < storm : : storage : : Distribution < ValueType > ,  typename  BisimulationDecomposition < ValueType > : : block_type >  distributionToNewBlocks ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Traverse all states of the block and check whether they have different distributions.
  
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : time_point  gatherStart  =  std : : chrono : : high_resolution_clock : : now ( ) ;  
			
		
	
		
			
				
					            for  ( auto  const &  state  :  this - > blocks [ blockId ] )  {  
			
		
	
		
			
				
					                // Now construct the distribution of this state wrt. to the current partitioning.
  
			
		
	
		
			
				
					                storm : : storage : : Distribution < ValueType >  distribution ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -110,6 +154,12 @@ namespace storm { 
			
		
	
		
			
				
					                    distribution . addProbability ( static_cast < storm : : storage : : sparse : : state_type > ( stateToBlockMapping [ successorEntry . getColumn ( ) ] ) ,  successorEntry . getValue ( ) ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                // If we are requested to compute a weak bisimulation, we need to scale the distribution with the
  
			
		
	
		
			
				
					                // self-loop probability.
  
			
		
	
		
			
				
					                if  ( weakBisimulation )  {  
			
		
	
		
			
				
					                    distribution . scale ( blockId ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                // If the distribution already exists, we simply add the state. Otherwise, we open a new block.
  
			
		
	
		
			
				
					                auto  distributionIterator  =  distributionToNewBlocks . find ( distribution ) ;  
			
		
	
		
			
				
					                if  ( distributionIterator  ! =  distributionToNewBlocks . end ( ) )  {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -119,10 +169,13 @@ namespace storm { 
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            std : : chrono : : high_resolution_clock : : duration  gatherTime  =  std : : chrono : : high_resolution_clock : : now ( )  -  gatherStart ;  
			
		
	
		
			
				
					            std : : cout  < <  " time to iterate over all states was  "  < <  std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( gatherTime ) . count ( )  < <  " ms. "  < <  std : : endl ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Now we are ready to split the block.
  
			
		
	
		
			
				
					            if  ( distributionToNewBlocks . size ( )  = =  1 )  {  
			
		
	
		
			
				
					                // If there is just one behavior, we just set the distribution as the new one for this block.
  
			
		
	
		
			
				
					                distributions [ blockId ]  =  std : : move ( distributionToNewBlocks . begin ( ) - > first ) ;  
			
		
	
		
			
				
					                // distributions[blockId] = std::move(distributionToNewBlocks.begin()->first);
  
			
		
	
		
			
				
					            }  else  {  
			
		
	
		
			
				
					                // In this case, we need to split the block.
  
			
		
	
		
			
				
					                typename  BisimulationDecomposition < ValueType > : : block_type  tmpBlock ;  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -154,21 +207,32 @@ namespace storm { 
			
		
	
		
			
				
					                std : : deque < std : : size_t >  localRefinementQueue ;  
			
		
	
		
			
				
					                storm : : storage : : BitVector  blocksInLocalRefinementQueue ( this - > size ( ) ) ;  
			
		
	
		
			
				
					                localRefinementQueue . push_back ( blockId ) ;  
			
		
	
		
			
				
					//                std::cout << "adding " << blockId << " to local ref queue " << std::endl;
  
			
		
	
		
			
				
					                blocksInLocalRefinementQueue . set ( blockId ) ;  
			
		
	
		
			
				
					                for  ( std : : size_t  i  =  beforeNumberOfBlocks ;  i  <  this - > blocks . size ( ) ;  + + i )  {  
			
		
	
		
			
				
					                    localRefinementQueue . push_back ( i ) ;  
			
		
	
		
			
				
					                    blocksInLocalRefinementQueue . set ( i ) ;  
			
		
	
		
			
				
					//                    std::cout << "adding " << i << " to local refinement queue " << std::endl;
  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                // We need to keep track of which blocks were split so we can later add all their predecessors as
  
			
		
	
		
			
				
					                // candidates for furter splitting.
  
			
		
	
		
			
				
					                storm : : storage : : BitVector  splitBlocks ( this - > size ( ) ) ;  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                while  ( ! localRefinementQueue . empty ( ) )  {  
			
		
	
		
			
				
					                    std : : size_t  currentBlock  =  localRefinementQueue . front ( ) ;  
			
		
	
		
			
				
					                    localRefinementQueue . pop_front ( ) ;  
			
		
	
		
			
				
					                    blocksInLocalRefinementQueue . set ( currentBlock ,  false ) ;  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    splitPredecessorsGraphBased ( dtmc ,  backwardTransitions ,  blockId ,  stateToBlockMapping ,  distributions ,  blocksInLocalRefinementQueue ,  localRefinementQueue ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					//                while (!localRefinementQueue.empty()) {
  
			
		
	
		
			
				
					//                    std::size_t currentBlock = localRefinementQueue.front();
  
			
		
	
		
			
				
					//                    localRefinementQueue.pop_front();
  
			
		
	
		
			
				
					//                    blocksInLocalRefinementQueue.set(currentBlock, false);
  
			
		
	
		
			
				
					//                    
  
			
		
	
		
			
				
					//                    splitPredecessorsGraphBased(dtmc, backwardTransitions, currentBlock, stateToBlockMapping, distributions, blocksInLocalRefinementQueue, localRefinementQueue, splitBlocks);
  
			
		
	
		
			
				
					//                }
  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					//                std::cout << "split blocks: " << std::endl;
  
			
		
	
		
			
				
					//                std::cout << splitBlocks << std::endl;
  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                // Since we created some new blocks, we need to extend the bit vector storing the blocks in the
  
			
		
	
		
			
				
					                // refinement queue.
  
			
		
	
		
			
				
					                blocksInRefinementQueue . resize ( blocksInRefinementQueue . size ( )  +  ( distributionToNewB locks. size ( )  -  1 ) ) ;  
			
		
	
		
			
				
					                blocksInRefinementQueue . resize ( this - > b locks. size ( ) ) ;  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                // Insert blocks that possibly need a refinement into the queue.
  
			
		
	
		
			
				
					                for  ( auto  const &  state  :  tmpBlock )  {