LCOV - code coverage report
Current view: top level - lps/source - linearise.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 4011 4860 82.5 %
Date: 2020-09-16 00:45:56 Functions: 242 258 93.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Jan Friso Groote
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file linearise.cpp
      10             : /// \brief This file contains code to transform an mCRL2 process
      11             : ///        into a linear process.
      12             : 
      13             : /* This file contains the implementation of an mCRL2 lineariser.
      14             : 
      15             :    It is based on the implementation of the mCRL lineariser, on which work
      16             :    started on 12 juli 1997.  This lineariser was based on the CWI technical
      17             :    report "The Syntax and Semantics of Timed mCRL", by J.F. Groote.
      18             : 
      19             :    Everybody is free to use this software, provided it is not changed.
      20             : 
      21             :    In case problems are encountered when using this software, please report
      22             :    them to J.F. Groote, TU/e, Eindhoven, J.F.Groote@tue.nl
      23             : 
      24             :    This software comes as it is. I.e. the author assumes no responsibility for
      25             :    the use of this software.
      26             : */
      27             : 
      28             : //mCRL2 data
      29             : #include "mcrl2/data/substitutions/maintain_variables_in_rhs.h"
      30             : #include "mcrl2/data/fourier_motzkin.h"
      31             : #include "mcrl2/data/enumerator.h" 
      32             : 
      33             : // linear process libraries.
      34             : #include "mcrl2/lps/detail/ultimate_delay.h"
      35             : #include "mcrl2/lps/linearise.h"
      36             : #include "mcrl2/lps/sumelm.h"
      37             : #include "mcrl2/lps/constelm.h"
      38             : #include "mcrl2/lps/replace_capture_avoiding_with_an_identifier_generator.h"
      39             : 
      40             : // Process libraries.
      41             : #include "mcrl2/process/alphabet_reduce.h"
      42             : #include "mcrl2/process/balance_nesting_depth.h"
      43             : 
      44             : 
      45             : // For Aterm library extension functions
      46             : using namespace atermpp;
      47             : using namespace mcrl2;
      48             : using namespace mcrl2::core;
      49             : using namespace mcrl2::core::detail;
      50             : using namespace mcrl2::data;
      51             : using namespace mcrl2::data::detail;
      52             : using namespace mcrl2::lps;
      53             : using namespace mcrl2::process;
      54             : 
      55             : /*  Preamble */
      56             : 
      57             : typedef enum { unknown,
      58             :                mCRL,
      59             :                mCRLdone,
      60             :                mCRLbusy,
      61             :                mCRLlin,
      62             :                pCRL,
      63             :                multiAction,
      64             :                GNF,
      65             :                GNFalpha,
      66             :                GNFbusy,
      67             :                error
      68             :              } processstatustype;
      69             : 
      70             : 
      71             : 
      72             : /**************** Definitions of object class  ***********************/
      73             : 
      74             : typedef enum { none,
      75             :                _map,
      76             :                func,
      77             :                act,
      78             :                proc,
      79             :                variable_,
      80             :                sorttype,
      81             :                multiact
      82             :              } objecttype;
      83             : 
      84             : class objectdatatype
      85             : {
      86             :   public:
      87             :     identifier_string objectname;
      88             :     process::action_label_list multi_action_names;
      89             :     bool constructor;
      90             :     process_expression representedprocess;
      91             :     process_identifier process_representing_action; /* for actions target sort is used to
      92             :                                                        indicate the process representing this action. */
      93             :     process_expression processbody;
      94             :     std::set <variable> free_variables;
      95             :     bool free_variables_defined;
      96             :     variable_list parameters;
      97             :     variable_list old_parameters;
      98             :     processstatustype processstatus;
      99             :     objecttype object;
     100             :     bool canterminate;
     101             :     bool containstime;
     102             : 
     103       36827 :     objectdatatype()
     104       36827 :     {
     105       36827 :       constructor=false;
     106       36827 :       processstatus=unknown;
     107       36827 :       object=none;
     108       36827 :       canterminate=0;
     109       36827 :       containstime=false;
     110       36827 :     }
     111             : 
     112             :     objectdatatype(const objectdatatype& o)
     113             :     {
     114             :       objectname=o.objectname;
     115             :       multi_action_names=o.multi_action_names;
     116             :       constructor=o.constructor;
     117             :       representedprocess=o.representedprocess;
     118             :       process_representing_action=o.process_representing_action;
     119             :       processbody=o.processbody;
     120             :       free_variables=o.free_variables;
     121             :       free_variables_defined=o.free_variables_defined;
     122             :       parameters=o.parameters;
     123             :       processstatus=o.processstatus;
     124             :       object=o.object;
     125             :       canterminate=o.canterminate;
     126             :       containstime=o.containstime;
     127             :     }
     128             : 
     129       20152 :     const objectdatatype& operator=(const objectdatatype& o)
     130             :     {
     131       20152 :       objectname=o.objectname;
     132       20152 :       multi_action_names=o.multi_action_names;
     133       20152 :       constructor=o.constructor;
     134       20152 :       representedprocess=o.representedprocess;
     135       20152 :       process_representing_action=o.process_representing_action;
     136       20152 :       processbody=o.processbody;
     137       20152 :       free_variables=o.free_variables;
     138       20152 :       free_variables_defined=o.free_variables_defined;
     139       20152 :       parameters=o.parameters;
     140       20152 :       processstatus=o.processstatus;
     141       20152 :       object=o.object;
     142       20152 :       canterminate=o.canterminate;
     143       20152 :       containstime=o.containstime;
     144       20152 :       return (*this);
     145             :     }
     146             : 
     147       36827 :     ~objectdatatype()
     148       36827 :     {
     149       36827 :     }
     150             : };
     151             : 
     152             : 
     153             : class specification_basic_type
     154             : {
     155             :   public:
     156             :     process::action_label_list acts;     /* storage place for actions */
     157             :     std::set < variable > global_variables; /* storage place for free variables occurring
     158             :                                    in processes ranging over data */
     159             :     variable_list initdatavars; /* storage place for free variables in
     160             :                                    init clause */
     161             :     data_specification data;    /* contains the data specification for the current process.  */
     162             : 
     163             :     specification_basic_type(const specification_basic_type& )=delete;
     164             :     specification_basic_type& operator=(const specification_basic_type&)=delete;
     165             : 
     166             :   private:
     167             :     class stackoperations;
     168             :     class stacklisttype;
     169             :     class enumtype;
     170             :     class enumeratedtype;
     171             : 
     172             :     std::vector < process_equation > procs;
     173             :     /* storage place for processes,
     174             :        uses alt, seq, par, lmer, cond,sum,
     175             :        com, bound, at, name, delta,
     176             :        tau, hide, rename, encap */
     177             :     mcrl2::data::rewriter rewr; /* The rewriter used while linearising */
     178             :     action terminationAction;   /* A list of length one with the action that denotes termination */
     179             :     process_identifier terminatedProcId; /* A process identifier of which the body consists of the termination
     180             :                                             action */
     181             :     process_identifier tau_process;
     182             :     process_identifier delta_process;
     183             :     std::vector < process_identifier > seq_varnames; /* Contains names of processes which represent a sequence
     184             :                                                             of process variables */
     185             :     std::vector < std::vector < process_instance_assignment > > representedprocesses; /* contains the sequences of process
     186             :                                                          instances that are represented by the variables in seq_varnames */
     187             :     t_lin_options options;
     188             :     bool timeIsBeingUsed;
     189             :     bool stochastic_operator_is_being_used;
     190             :     bool fresh_equation_added;
     191             :     std::map < aterm, objectdatatype > objectdata; // It is important to guarantee that the objects will not
     192             :                                                    // be moved to another place when the object data structure grows. This
     193             :                                                    // is because objects in this datatype  are passed around by reference.
     194             : 
     195             :     set_identifier_generator fresh_identifier_generator;
     196             :     std::vector < enumeratedtype > enumeratedtypes;
     197             :     stackoperations* stack_operations_list;
     198             : 
     199             :   public:
     200         692 :     specification_basic_type(const process::action_label_list& as,
     201             :                              const std::vector< process_equation >& ps,
     202             :                              const variable_list& idvs,
     203             :                              const data_specification& ds,
     204             :                              const std::set < data::variable >& glob_vars,
     205             :                              const t_lin_options& opt,
     206         692 :                              const process_specification& procspec):
     207             :       acts(),
     208             :       global_variables(glob_vars),
     209             :       data(ds),
     210         692 :       rewr(data,opt.rewrite_strategy),
     211             :       options(opt),
     212             :       timeIsBeingUsed(false),
     213             :       stochastic_operator_is_being_used(false),
     214        1384 :       fresh_equation_added(false)
     215             :     {
     216             :       // find_identifiers does not find the identifiers in the enclosed data specification.
     217         692 :       fresh_identifier_generator.add_identifiers(process::find_identifiers(procspec));
     218             :       // So, the identifiers in the data type must be added explicitly.
     219         692 :       fresh_identifier_generator.add_identifiers(data::find_identifiers(ds.equations()));
     220         692 :       fresh_identifier_generator.add_identifiers(data::find_identifiers(ds.user_defined_aliases()));
     221         692 :       fresh_identifier_generator.add_identifiers(data::find_identifiers(ds.sorts()));
     222         692 :       fresh_identifier_generator.add_identifiers(data::find_identifiers(ds.constructors()));
     223         692 :       fresh_identifier_generator.add_identifiers(data::find_identifiers(ds.mappings()));
     224             : 
     225         692 :       stack_operations_list=nullptr;
     226         692 :       acts=as;
     227         692 :       storeact(acts);
     228         692 :       procs=ps;
     229         692 :       storeprocs(procs);
     230         692 :       initdatavars=idvs;
     231             :       // The terminationAction and the terminatedProcId must be defined after initialisation of
     232             :       // data as otherwise fresh name does not work properly.
     233         692 :       terminationAction=action(action_label(fresh_identifier_generator("Terminate"),sort_expression_list()),data_expression_list());
     234         692 :       terminatedProcId=process_identifier(fresh_identifier_generator("Terminated**"), variable_list());
     235             : // /* Changed delta() to DeltaAtZero on 24/12/2006. Moved back in spring 2007, as this introduces unwanted time constraints. */
     236         692 :       insert_process_declaration(
     237             :         terminatedProcId,
     238        1384 :         variable_list(),
     239        1384 :         seq(terminationAction,delta()),
     240         692 :         pCRL,0,false);
     241         692 :       delta_process=newprocess(variable_list(),delta(),pCRL,false,false);
     242         692 :       tau_process=newprocess(variable_list(),tau(),pCRL,true,false);
     243         692 :     }
     244             : 
     245         924 :     ~specification_basic_type()
     246         692 :     {
     247        1156 :       for (; stack_operations_list!=nullptr;)
     248             :       {
     249         232 :         stackoperations* temp=stack_operations_list->next;
     250         232 :         delete stack_operations_list;
     251         232 :         stack_operations_list=temp;
     252             :       }
     253             : 
     254         692 :     }
     255             : 
     256             :   private:
     257       62905 :     data_expression real_zero()
     258             :     {
     259       62905 :       static data_expression zero=sort_real::creal(sort_int::cint(sort_nat::c0()),sort_pos::c1());
     260       62905 :       return zero;
     261             :     }
     262             : 
     263       39053 :     data_expression real_one()
     264             :     {
     265       39053 :       static data_expression one=sort_real::creal(sort_int::cint(sort_nat::cnat(sort_pos::c1())),sort_pos::c1());
     266       39053 :       return one;
     267             :     }
     268             : 
     269       31452 :     data_expression real_times_optimized(const data_expression& r1, const data_expression& r2)
     270             :     {
     271       31452 :       if (r1==real_zero() || r2==real_zero())
     272             :       {
     273           0 :         return real_zero();
     274             :       }
     275       31452 :       if (r1==real_one())
     276             :       {
     277       31402 :         return r2;
     278             :       }
     279          50 :       if (r2==real_one())
     280             :       {
     281           0 :         return r1;
     282             :       }
     283          50 :       return sort_real::times(r1,r2);
     284             :     }
     285             : 
     286          31 :     process_expression delta_at_zero(void)
     287             :     {
     288          31 :       return at(delta(), data::sort_real::real_(0));
     289             :     }
     290             : 
     291        4878 :     bool isDeltaAtZero(const process_expression& t)
     292             :     {
     293        4878 :       if (!is_at(t))
     294             :       {
     295        4750 :         return false;
     296             :       }
     297         128 :       if (!is_delta(at(t).operand()))
     298             :       {
     299           2 :         return false;
     300             :       }
     301         126 :       return RewriteTerm(at(t).time_stamp())==data::sort_real::real_(0);
     302             :     }
     303             : 
     304             :     /***************** temporary helper function to compare substitutions ******************/
     305             : 
     306             :     template <class Expression, class Substitution>
     307       59677 :     Expression replace_variables_capture_avoiding_alt(const Expression& e, Substitution& sigma)
     308             :     {
     309       59677 :       return data::replace_variables_capture_avoiding_with_an_identifier_generator(e, sigma, fresh_identifier_generator);
     310             :     }
     311             : 
     312             : 
     313             :     /*****************  retrieve basic objects  ******************/
     314             : 
     315       91652 :     void detail_check_objectdata(const aterm_appl& o) const
     316             :     {
     317       91652 :       if (objectdata.count(o)==0)
     318             :       {
     319           0 :         if (is_process_identifier(o))
     320             :         {
     321           0 :           throw mcrl2::runtime_error("Fail to recognize " + process::pp(process_identifier(o)) + ". Most likely due to unguarded recursion in a process equation. ");
     322             :         }
     323             :         else
     324             :         {
     325           0 :           throw mcrl2::runtime_error("Fail to recognize " + process::pp(o) + ". This is an internal error in the lineariser. ");
     326             :         }
     327             :       }
     328       91652 :     }
     329       85530 :     objectdatatype& objectIndex(const aterm_appl& o) 
     330             :     {
     331       85530 :       detail_check_objectdata(o);
     332       85530 :       return objectdata.find(o)->second;
     333             :     } 
     334             : 
     335        6122 :     const objectdatatype& objectIndex(const aterm_appl& o) const
     336             :     {
     337        6122 :       detail_check_objectdata(o);
     338        6122 :       return objectdata.find(o)->second;
     339             :     } 
     340             : 
     341       19766 :     void addString(const identifier_string& str)
     342             :     {
     343       19766 :       fresh_identifier_generator.add_identifier(str);
     344       19766 :     }
     345             : 
     346         896 :     process_expression action_list_to_process(const action_list& ma)
     347             :     {
     348         896 :       if (ma.size()==0)
     349             :       {
     350           0 :         return tau();
     351             :       }
     352         896 :       if (ma.size()==1)
     353             :       {
     354         581 :         return ma.front();
     355             :       }
     356         315 :       return process::sync(ma.front(),action_list_to_process(ma.tail()));
     357             :     }
     358             : 
     359        3524 :     action_list to_action_list(const process_expression& p)
     360             :     {
     361        3524 :       if (is_tau(p))
     362             :       {
     363          73 :         return action_list();
     364             :       }
     365             : 
     366        3451 :       if (is_action(p))
     367             :       {
     368        3160 :         return action_list({ action(p) });
     369             :       }
     370             : 
     371         291 :       if (is_sync(p))
     372             :       {
     373         291 :         return to_action_list(process::sync(p).left())+to_action_list(process::sync(p).right());
     374             :       }
     375           0 :       assert(0);
     376             :       return action_list();
     377             :     }
     378             : 
     379         515 :     process::action_label_list getnames(const process_expression& multiAction)
     380             :     {
     381         515 :       if (is_action(multiAction))
     382             :       {
     383         491 :         return action_label_list({ action(multiAction).label() });
     384             :       }
     385          24 :       assert(is_sync(multiAction));
     386          24 :       return getnames(process::sync(multiAction).left())+getnames(process::sync(multiAction).right());
     387             :     }
     388             : 
     389             :     // Returns a list of variables with the same sort as the expressions in the list.
     390             :     // If the expression is a variable not occurring in the occurs_set that variable
     391             :     // is used.
     392         410 :     variable_list make_parameters_rec(const data_expression_list& l,
     393             :                                       std::set < variable>& occurs_set)
     394             :     {
     395         820 :       variable_list result;
     396         822 :       for (data_expression_list::const_iterator l1=l.begin();
     397         822 :            l1!=l.end() ; ++l1)
     398             :       {
     399             :         /* if the current argument of the multi-action is a variable that does
     400             :          not occur in result, use this variable. This is advantageous, when joining
     401             :          processes to one linear process where variable names are joined. If this
     402             :          is not being done (as happened before 4/1/2008) very long lists of parameters
     403             :          can occur when linearising using regular2 */
     404         412 :         if (is_variable(*l1) && std::find(occurs_set.begin(),occurs_set.end(),*l1)==occurs_set.end())
     405             :         {
     406         280 :           const variable& v = atermpp::down_cast<variable>(*l1);
     407         280 :           result.push_front(v);
     408         280 :           occurs_set.insert(v);
     409             :         }
     410             :         else
     411             :         {
     412         132 :           result.push_front(variable(get_fresh_variable("a",l1->sort())));
     413             :         }
     414             :       }
     415         820 :       return reverse(result);
     416             :     }
     417             : 
     418         434 :     variable_list getparameters_rec(const process_expression& multiAction,
     419             :                                     std::set < variable>& occurs_set)
     420             :     {
     421         434 :       if (is_action(multiAction))
     422             :       {
     423         410 :         return make_parameters_rec(action(multiAction).arguments(),occurs_set);
     424             :       }
     425          24 :       assert(is_sync(multiAction));
     426          48 :       return getparameters_rec(process::sync(multiAction).left(),occurs_set)+
     427          72 :              getparameters_rec(process::sync(multiAction).right(),occurs_set);
     428             :     }
     429             : 
     430         386 :     variable_list getparameters(const process_expression& multiAction)
     431             :     {
     432         772 :       std::set < variable > occurs_set;
     433         772 :       return getparameters_rec(multiAction,occurs_set);
     434             :     }
     435             : 
     436          18 :     data_expression_list getarguments(const action_list& multiAction)
     437             :     {
     438          36 :       data_expression_list result;
     439          60 :       for (const action& a: multiAction)
     440             :       {
     441          42 :         result=reverse(a.arguments()) + result;
     442             :       }
     443          36 :       return reverse(result);
     444             :     }
     445             : 
     446         386 :     action_list makemultiaction(const process::action_label_list& actionIds, const data_expression_list& args)
     447             :     {
     448         772 :       action_list result;
     449         386 :       data_expression_list::const_iterator e_walker=args.begin();
     450         796 :       for (const process::action_label& l: actionIds)
     451             :       {
     452         410 :         std::size_t arity=l.sorts().size();
     453         820 :         data_expression_list temp_args;
     454         822 :         for (std::size_t i=0 ; i< arity; ++i,++e_walker)
     455             :         {
     456         412 :           assert(e_walker!=args.end());
     457         412 :           temp_args.push_front(*e_walker);
     458             :         }
     459         410 :         temp_args=reverse(temp_args);
     460         410 :         result.push_front(action(l,temp_args));
     461             :       }
     462         386 :       assert(e_walker==args.end());
     463         772 :       return reverse(result);
     464             :     }
     465             : 
     466         467 :     objectdatatype& addMultiAction(const process_expression& multiAction, bool& isnew)
     467             :     {
     468         934 :       const process::action_label_list actionnames=getnames(multiAction);
     469             : 
     470         467 :       isnew=(objectdata.count(actionnames)==0);
     471             : 
     472         467 :       if (isnew)
     473             :       {
     474         772 :         objectdatatype object;
     475             :               
     476             :         // tempvar is needed as objectdata can change during a call
     477             :         // of getparameters.
     478         772 :         const variable_list templist=getparameters(multiAction);
     479         386 :         object.parameters=templist;
     480         386 :         object.object=multiact;
     481             :         // must separate assignment below as
     482             :         // objectdata may change as a side effect of make
     483             :         // multiaction.
     484         772 :         const action_list tempvar=makemultiaction(actionnames, variable_list_to_data_expression_list(object.parameters));
     485         386 :         object.processbody=action_list_to_process(tempvar);
     486         386 :         object.free_variables=std::set<variable>(object.parameters.begin(), object.parameters.end());
     487         386 :         object.free_variables_defined=true;
     488             :         
     489         386 :         objectdata[actionnames]=object;
     490             :       }
     491         934 :       return objectdata.find(actionnames)->second;
     492             :     }
     493             : 
     494        2603 :     const std::set<variable>& get_free_variables(objectdatatype& object)
     495             :     {
     496        2603 :       if (!object.free_variables_defined)
     497             :       {
     498        1738 :         object.free_variables=find_free_variables_process(object.processbody);
     499        1738 :         object.free_variables_defined=true;
     500             :       }
     501        2603 :       return object.free_variables;
     502             :     }
     503             : 
     504       12024 :     void insertvariable(const variable& var, const bool mustbenew)
     505             :     {
     506       12024 :       addString(var.name());
     507             : 
     508       12024 :       if (objectdata.count(var.name())>0  && mustbenew)
     509             :       {
     510           0 :         throw mcrl2::runtime_error("Variable " + data::pp(var) + " already exists. ");
     511             :       }
     512             : 
     513       24048 :       objectdatatype object;
     514       12024 :       object.objectname=var.name();
     515       12024 :       object.object=variable_;
     516       12024 :       objectdata[var.name()]=object;
     517       12024 :     }
     518             : 
     519        7240 :     void insertvariables(const variable_list& vars, const bool mustbenew)
     520             :     {
     521       11456 :       for (variable_list::const_iterator l=vars.begin(); l!=vars.end(); ++l)
     522             :       {
     523        4216 :         insertvariable(*l,mustbenew);
     524             :       }
     525        7240 :     }
     526             : 
     527             :     template <class SUBSTITUTION>
     528             :     std::set<data::variable> sigma_variables(const SUBSTITUTION& sigma)
     529             :     {
     530             :       std::set<data::variable> result;
     531             :       for (typename SUBSTITUTION::const_iterator i = sigma.begin(); i != sigma.end(); ++i)
     532             :       {
     533             :         std::set<data::variable> V = data::find_free_variables(i->second);
     534             :         V.erase(i->first);
     535             :         result.insert(V.begin(), V.end());
     536             :       }
     537             :       return result;
     538             :     }
     539             : 
     540             : 
     541             :     /************ upperpowerof2 *********************************************/
     542             : 
     543           0 :     std::size_t upperpowerof2(std::size_t i)
     544             :     /* function yields n for the smallest value n such that
     545             :        2^n>=i. This constitutes the number of bits necessary
     546             :        to represent a number smaller than i. i is assumed to
     547             :        be at least 1. */
     548             :     {
     549           0 :       std::size_t n=0;
     550           0 :       std::size_t powerof2=1;
     551           0 :       for (; powerof2< i ; n++)
     552             :       {
     553           0 :         powerof2=2*powerof2;
     554             :       }
     555           0 :       return n;
     556             :     }
     557             : 
     558      159744 :     data_expression RewriteTerm(const data_expression& t)
     559             :     {
     560      159744 :       if (!options.norewrite)
     561             :       {
     562      159744 :         if (fresh_equation_added)
     563             :         {
     564          13 :           rewr=rewriter(data,options.rewrite_strategy);
     565          13 :           fresh_equation_added=false;
     566             :         }
     567      159744 :         return rewr(t);
     568             :       }
     569           0 :       return t;
     570             :     }
     571             : 
     572           0 :     data_expression_list RewriteTermList(const data_expression_list& t)
     573             :     {
     574           0 :       data_expression_vector v;
     575           0 :       for(const data_expression& d: t)
     576             :       {
     577           0 :         v.push_back(RewriteTerm(d));
     578             :       }
     579           0 :       return data_expression_list(v.begin(),v.end());
     580             :     }
     581             : 
     582        4171 :     assignment_list rewrite_assignments(const assignment_list& t)
     583             :     {
     584        8342 :       assignment_vector v;
     585        6746 :       for(const assignment& a: t)
     586             :       {
     587        2575 :         v.push_back(assignment(a.lhs(), RewriteTerm(a.rhs())));
     588             :       }
     589        8342 :       return assignment_list(v.begin(),v.end());
     590             :     }
     591             : 
     592           0 :     action RewriteAction(const action& t)
     593             :     {
     594           0 :       return action(t.label(),RewriteTermList(t.arguments()));
     595             :     }
     596             : 
     597        4171 :     process_instance_assignment RewriteProcess(const process_instance_assignment& t)
     598             :     {
     599        4171 :       return process_instance_assignment(t.identifier(),rewrite_assignments(t.assignments()));
     600             :     }
     601             : 
     602           0 :     process_expression RewriteMultAct(const process_expression& t)
     603             :     {
     604           0 :       if (is_tau(t))
     605             :       {
     606           0 :         return t;
     607             :       }
     608             : 
     609           0 :       if (is_action(t))
     610             :       {
     611           0 :         return RewriteAction(action(t));
     612             :       }
     613             : 
     614           0 :       assert(is_sync(t));  // A multi action is a sequence of actions with a sync operator in between.
     615           0 :       return process::sync(RewriteMultAct(process::sync(t).left()),RewriteMultAct(process::sync(t).right()));
     616             :     }
     617             : 
     618             : 
     619        4882 :     process_expression pCRLrewrite(const process_expression& t)
     620             :     {
     621        4882 :       if (options.norewrite)
     622             :       {
     623           0 :         return t;
     624             :       }
     625             : 
     626        4882 :       if (is_if_then(t))
     627             :       {
     628           0 :         const data_expression new_cond=RewriteTerm(if_then(t).condition());
     629           0 :         const process_expression new_then_case=pCRLrewrite(if_then(t).then_case());
     630           0 :         if (new_cond==sort_bool::true_())
     631             :         {
     632           0 :           return new_then_case;
     633             :         }
     634           0 :         return if_then(new_cond,new_then_case);
     635             :       }
     636             : 
     637        4882 :       if (is_seq(t))
     638             :       {
     639             :         /* only one summand is needed */
     640        1422 :         return seq(
     641        1422 :                  pCRLrewrite(seq(t).left()),
     642        2133 :                  pCRLrewrite(seq(t).right()));
     643             :       }
     644             : 
     645        4171 :       if (is_at(t))
     646             :       {
     647           0 :         const data_expression atTime=RewriteTerm(at(t).time_stamp());
     648           0 :         const process_expression t1=pCRLrewrite(at(t).operand());
     649           0 :         return at(t1,atTime);
     650             :       }
     651             : 
     652        4171 :       if (is_stochastic_operator(t))
     653             :       {
     654           0 :         const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(t);
     655           0 :         return stochastic_operator(sto.variables(),RewriteTerm(sto.distribution()),pCRLrewrite(sto.operand()));
     656             :       }
     657             : 
     658        4171 :       if (is_delta(t) || is_tau(t))
     659             :       {
     660           0 :         return t;
     661             :       }
     662             : 
     663        4171 :       if (is_action(t))
     664             :       {
     665           0 :         return RewriteAction(atermpp::down_cast<process::action>(t));
     666             :       }
     667             : 
     668        4171 :       if (is_process_instance_assignment(t))
     669             :       {
     670        4171 :         return RewriteProcess(process_instance_assignment(t));
     671             :       }
     672             : 
     673           0 :       if (is_sync(t))
     674             :       {
     675           0 :         return RewriteMultAct(t);
     676             :       }
     677             : 
     678           0 :       assert(0); // Expected a term in pCRL format, using only basic process operators.
     679             :       return t;
     680             :     }
     681             : 
     682             :     /************ storeact ****************************************************/
     683             : 
     684        2230 :     objectdatatype& insertAction(const action_label& actionId)
     685             :     {
     686        2230 :       if (objectdata.count(actionId)>0)
     687             :       {
     688           0 :         throw mcrl2::runtime_error("Action " + process::pp(actionId) + " is added twice. This is an internal error in the lineariser. Please report. ");
     689             :       }
     690             : 
     691        2230 :       const identifier_string& str=actionId.name();
     692        2230 :       addString(str);
     693             : 
     694        4460 :       objectdatatype object;
     695        2230 :       object.objectname=str;
     696        2230 :       object.object=act;
     697        2230 :       object.process_representing_action=process_identifier();
     698             :       
     699        2230 :       objectdata[actionId]=object;
     700        4460 :       return objectdata.find(actionId)->second;
     701             :     }
     702             : 
     703         692 :     void storeact(const process::action_label_list& acts)
     704             :     {
     705        2922 :       for (process::action_label_list::const_iterator l=acts.begin(); l!=acts.end(); ++l)
     706             :       {
     707        2230 :         insertAction(*l);
     708             :       }
     709         692 :     }
     710             : 
     711             :     /************ storeprocs *************************************************/
     712             : 
     713        5512 :     objectdatatype& insert_process_declaration(
     714             :       const process_identifier& procId, 
     715             :       const variable_list& parameters,  
     716             :       const process_expression& body,
     717             :       processstatustype s,
     718             :       const bool canterminate,
     719             :       const bool containstime)
     720             :     {
     721        5512 :       assert(procId.variables().size()==parameters.size());
     722       11024 :       const std::string str=procId.name();
     723        5512 :       addString(str);
     724             : 
     725        5512 :       if (objectdata.count(procId)>0)
     726             :       {
     727           0 :         throw mcrl2::runtime_error("Process " + process::pp(procId) + " is added twice. This is an internal error in the lineariser. Please report. ");
     728             :       }
     729             : 
     730       11024 :       objectdatatype object;
     731        5512 :       object.objectname=procId.name();
     732        5512 :       object.object=proc;
     733        5512 :       object.processbody=body;
     734        5512 :       object.free_variables_defined=false;
     735        5512 :       object.canterminate=canterminate;
     736        5512 :       object.containstime=containstime;
     737        5512 :       object.processstatus=s;
     738        5512 :       object.parameters=parameters;
     739        5512 :       insertvariables(parameters,false);
     740        5512 :       objectdata[procId]=object;
     741       11024 :       return objectdata.find(procId)->second;
     742             :     }
     743             : 
     744         692 :     void storeprocs(const std::vector< process_equation >& procs)
     745             :     {
     746        1529 :       for (std::vector< process_equation >::const_iterator i=procs.begin();
     747        1529 :            i!=procs.end(); ++i)
     748             :       {
     749         837 :         insert_process_declaration(
     750             :           i->identifier(),
     751             :           i->formal_parameters(),
     752             :           i->expression(),
     753         837 :           unknown,0,false);
     754             :       }
     755         692 :     }
     756             : 
     757        3237 :     bool searchProcDeclaration(
     758             :       const variable_list& parameters,
     759             :       const process_expression& body,
     760             :       const processstatustype s,
     761             :       const bool canterminate,
     762             :       const bool containstime,
     763             :       process_identifier& p)
     764             :     {
     765       69903 :       for(const std::pair<const aterm,objectdatatype>& d: objectdata)
     766             :       {
     767      162006 :         if (d.second.object==proc &&
     768       39551 :             d.second.parameters==parameters &&
     769       11019 :             d.second.processbody==body &&
     770         104 :             d.second.canterminate==canterminate &&
     771       66814 :             d.second.containstime==containstime &&
     772          51 :             d.second.processstatus==s)
     773             :         {
     774          45 :           p=process_identifier(d.second.objectname,d.second.parameters);
     775          45 :           return true;
     776             :         }
     777             :       }
     778        3192 :       return false;
     779             :     }
     780             : 
     781             : 
     782             :     /************ storeinit *************************************************/
     783             : 
     784             :   public:
     785         692 :     process_identifier storeinit(const process_expression& init)
     786             :     {
     787             :       /* init is used as the name of the initial process,
     788             :          because it cannot occur as a string in the input */
     789             : 
     790         692 :       process_identifier initprocess(std::string("init"), variable_list());
     791         692 :       insert_process_declaration(initprocess,variable_list(),init,unknown,0,false);
     792         692 :       return initprocess;
     793             :     }
     794             : 
     795             :   private:
     796             : 
     797             :     /********** various functions on action and multi actions  ***************/
     798      142542 :     bool actioncompare(const action_label& a1, const action_label& a2)
     799             :     {
     800             :       /* first compare the strings in the actions */
     801      142542 :       if (std::string(a1.name())<std::string(a2.name()))
     802             :       {
     803      107808 :         return true;
     804             :       }
     805             : 
     806       34734 :       if (a1.name()==a2.name())
     807             :       {
     808             :         /* the strings are equal; the sorts are used to
     809             :            determine the ordering */
     810        1737 :         return a1.sorts()<a2.sorts();
     811             :       }
     812             : 
     813       32997 :       return false;
     814             :     }
     815             : 
     816      190034 :     action_list linInsertActionInMultiActionList(
     817             :       const action& act,
     818             :       action_list multiAction)
     819             :     {
     820             :       /* store the action in the multiAction, alphabetically
     821             :          sorted on the actionname in the actionId. Note that
     822             :          the empty multiAction represents tau. */
     823             : 
     824      190034 :       if (multiAction.empty())
     825             :       {
     826       47492 :         return action_list({ act });
     827             :       }
     828      285084 :       const action firstAction=multiAction.front();
     829             : 
     830             :       /* Actions are compared on the basis of their position
     831             :          in memory, to order them. As the aterm library maintains
     832             :          pointers to objects that are not garbage collected, this
     833             :          is a safe way to do this. */
     834      142542 :       if (actioncompare(act.label(),firstAction.label()))
     835             :       {
     836      107808 :         multiAction.push_front(act);
     837      107808 :         return multiAction;
     838             :       }
     839             :       action_list result= linInsertActionInMultiActionList(
     840             :                           act,
     841       69468 :                           multiAction.tail());
     842       34734 :       result.push_front(firstAction);
     843       34734 :       return result;
     844             :     }
     845             : 
     846       31561 :     action_list linMergeMultiActionList(const action_list& ma1, const action_list& ma2)
     847             :     {
     848       31561 :       action_list result=ma2;
     849       63295 :       for (action_list::const_iterator i=ma1.begin() ; i!=ma1.end() ; ++i)
     850             :       {
     851       31734 :         result=linInsertActionInMultiActionList(*i,result);
     852             :       }
     853       31561 :       return result;
     854             :     }
     855             : 
     856             : 
     857         195 :     action_list linMergeMultiActionListProcess(const process_expression& ma1, const process_expression& ma2)
     858             :     {
     859         195 :       return linMergeMultiActionList(to_action_list(ma1),to_action_list(ma2));
     860             :     }
     861             : 
     862             :     /************** determine_process_status ********************************/
     863             : 
     864       20531 :     processstatustype determine_process_statusterm(
     865             :       const process_expression& body,  // intentionally not a reference.
     866             :       const processstatustype status)
     867             :     {
     868             :       /* In this procedure it is determined whether a process
     869             :          is of type mCRL, pCRL or a multiAction. pCRL processes
     870             :          occur strictly within mCRL processes, and multiActions
     871             :          occur strictly within pCRL processes. Processes that pass
     872             :          this procedure can be linearised. Bounded initialisation,
     873             :          the leftmerge and synchronization merge on the highest
     874             :          level are filtered out. */
     875       20531 :       if (is_choice(body))
     876             :       {
     877        1500 :         if (status==multiAction)
     878             :         {
     879           0 :           throw mcrl2::runtime_error("Choice operator occurs in a multi-action in " + process::pp(body) + ". The lineariser cannot handle such a pattern. ");
     880             :         }
     881        1500 :         const processstatustype s1=determine_process_statusterm(choice(body).left(),pCRL);
     882        1500 :         const processstatustype s2=determine_process_statusterm(choice(body).right(),pCRL);
     883        1500 :         if ((s1==mCRL)||(s2==mCRL))
     884             :         {
     885           0 :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs within the scope of a choice operator in " + process::pp(body) +
     886           0 :                                       ". The lineariser cannot handle such processes. ");
     887             :         }
     888        1500 :         return pCRL;
     889             :       }
     890             : 
     891       19031 :       if (is_seq(body))
     892             :       {
     893        4808 :         if (status==multiAction)
     894             :         {
     895           0 :           throw mcrl2::runtime_error("Sequential operator occurs in a multi-action in " + process::pp(body) +". The lineariser cannot handle such a pattern. ");
     896             :         }
     897        4814 :         const processstatustype s1=determine_process_statusterm(seq(body).left(),pCRL);
     898        4802 :         const processstatustype s2=determine_process_statusterm(seq(body).right(),pCRL);
     899        4802 :         if ((s1==mCRL)||(s2==mCRL))
     900             :         {
     901           0 :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs in the scope of a sequential operator in " + process::pp(body) +". "
     902           0 :                                        + "The lineariser cannot handle such processes. ");
     903             :         }
     904        4802 :         return pCRL;
     905             :       }
     906             : 
     907       14223 :       if (is_merge(body))
     908             :       {
     909         354 :         if (status!=mCRL)
     910             :         {
     911          12 :           throw mcrl2::runtime_error("The parallel operator occurs in the scope of recursion, or the condition, sequential or choice operatar in " +
     912          18 :                                       process::pp(body) + ". The lineariser cannot handle such processes. ");
     913             :         }
     914         348 :         determine_process_statusterm(process::merge(body).left(),mCRL);
     915         348 :         determine_process_statusterm(process::merge(body).right(),mCRL);
     916         348 :         return mCRL;
     917             :       }
     918             : 
     919       13869 :       if (is_left_merge(body))
     920             :       {
     921           0 :         throw mcrl2::runtime_error("Cannot linearise because the specification contains a leftmerge. ");
     922             :       }
     923             : 
     924       13869 :       if (is_if_then(body))
     925             :       {
     926         685 :         if (status==multiAction)
     927             :         {
     928           0 :           throw mcrl2::runtime_error("If-then occurs in a multi-action in " + process::pp(body) + ". The lineariser cannot linearise this. ");
     929             :         }
     930         685 :         const processstatustype s1=determine_process_statusterm(if_then(body).then_case(),pCRL);
     931         685 :         if (s1==mCRL)
     932             :         {
     933           0 :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs in the scope of the if-then operator in " + process::pp(body) + ". "
     934           0 :                                      + "The lineariser cannot handle such processes. ");
     935             :         }
     936         685 :         return pCRL;
     937             :       }
     938             : 
     939       13184 :       if (is_if_then_else(body))
     940             :       {
     941         314 :         if (status==multiAction)
     942             :         {
     943           0 :           throw mcrl2::runtime_error("If-then-else occurs in a multi-action in " + process::pp(body) +".");
     944             :         }
     945         314 :         const processstatustype s1=determine_process_statusterm(if_then_else(body).then_case(),pCRL);
     946         314 :         const processstatustype s2=determine_process_statusterm(if_then_else(body).else_case(),pCRL);
     947         314 :         if ((s1==mCRL)||(s2==mCRL))
     948             :         {
     949           0 :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs in the scope of the if-then-else operator in " + process::pp(body) +
     950           0 :                                      ". " + "The lineariser cannot handle such processes. ");
     951             :         }
     952         314 :         return pCRL;
     953             :       }
     954             : 
     955       12870 :       if (is_sum(body))
     956             :       {
     957             :         /* insert the variable names of variables, to avoid
     958             :            that this variable name will be reused later on */
     959        1493 :         insertvariables(sum(body).variables(),false);
     960        1493 :         if (status==multiAction)
     961             :         {
     962           0 :           throw mcrl2::runtime_error("The sum operator occurs within a multi-action in " + process::pp(body) + ". "
     963           0 :                                       + "The lineariser cannot handle such processes. ");
     964             :         }
     965        1493 :         const processstatustype s1=determine_process_statusterm(sum(body).operand(),pCRL);
     966        1493 :         if (s1==mCRL)
     967             :         {
     968           0 :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs in the scope of the sum operator in " + process::pp(body) + ". "
     969           0 :                                      "The lineariser cannot handle such processes. ");
     970             :         }
     971        1493 :         return pCRL;
     972             :       }
     973             : 
     974       11377 :       if (is_stochastic_operator(body))
     975             :       {
     976         235 :         stochastic_operator_is_being_used=true;
     977             :         /* insert the variable names of variables, to avoid
     978             :            that this variable name will be reused later on */
     979         235 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(body);
     980         235 :         insertvariables(sto.variables(),false);
     981         235 :         if (status==multiAction)
     982             :         {
     983           0 :           throw mcrl2::runtime_error("Stochastic operator occurs within a multi-action in " + process::pp(body) +".");
     984             :         }
     985         235 :         const processstatustype s1=determine_process_statusterm(sto.operand(),mCRL);
     986             :         /*if (s1==mCRL)
     987             :         {
     988             :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs in the scope of the stochastic operator in " + process::pp(body) + ". "
     989             :                                      + "The lineariser cannot handle such processes. ");
     990             :         }*/
     991         235 :         return s1;
     992             :       }
     993             : 
     994       11142 :       if (is_comm(body))
     995             :       {
     996         112 :         if (status!=mCRL)
     997             :         {
     998             :           throw mcrl2::runtime_error("The communication operator occurs in the scope of recursion, the condition, the sequential operation or the choice in "
     999           0 :                                       + process::pp(body) + ". The lineariser cannot linearise such processes. ");
    1000             :         }
    1001         112 :         determine_process_statusterm(comm(body).operand(),mCRL);
    1002         112 :         return mCRL;
    1003             :       }
    1004             : 
    1005       11030 :       if (is_bounded_init(body))
    1006             :       {
    1007           0 :         throw mcrl2::runtime_error("Cannot linearise a specification with the bounded initialization operator.");
    1008             :       }
    1009             : 
    1010       11030 :       if (is_at(body))
    1011             :       {
    1012         410 :         timeIsBeingUsed = true;
    1013         410 :         if (status==multiAction)
    1014             :         {
    1015           0 :           throw mcrl2::runtime_error("Time operator occurs in a multi-action in " + process::pp(body) +".");
    1016             :         }
    1017         410 :         const processstatustype s1=determine_process_statusterm(at(body).operand(),pCRL);
    1018         410 :         if (s1==mCRL)
    1019             :         {
    1020           0 :           throw mcrl2::runtime_error("An operator ||, allow, hide, rename, or comm occurs in the scope of a time operator in " + process::pp(body) + "."
    1021           0 :                                      + "The lineariser cannot handle such processes. ");
    1022             :         }
    1023         410 :         return pCRL;
    1024             :       }
    1025             : 
    1026       10620 :       if (is_sync(body))
    1027             :       {
    1028         390 :         const processstatustype s1=determine_process_statusterm(process::sync(body).left(),pCRL);
    1029         390 :         const processstatustype s2=determine_process_statusterm(process::sync(body).right(),pCRL);
    1030         390 :         if ((s1!=multiAction)||(s2!=multiAction))
    1031             :         {
    1032           0 :           throw mcrl2::runtime_error("Other objects than multi-actions occur in the scope of a synch operator in " + process::pp(body) +".");
    1033             :         }
    1034         390 :         return multiAction;
    1035             :       }
    1036             : 
    1037       10230 :       if (is_action(body))
    1038             :       {
    1039        5965 :         return multiAction;
    1040             :       }
    1041             : 
    1042        4265 :       if (is_process_instance(body))
    1043             :       {
    1044           0 :         assert(0);
    1045             :         determine_process_status(process_instance(body).identifier(),status);
    1046             :         return status;
    1047             :       }
    1048             : 
    1049        4265 :       if (is_process_instance_assignment(body))
    1050             :       {
    1051        3530 :         determine_process_status(process_instance_assignment(body).identifier(),status);
    1052        3518 :         return status;
    1053             :       }
    1054             : 
    1055         741 :       if (is_delta(body))
    1056             :       {
    1057         441 :         return pCRL;
    1058             :       }
    1059             : 
    1060         300 :       if (is_tau(body))
    1061             :       {
    1062         193 :         return multiAction;
    1063             :       }
    1064             : 
    1065         107 :       if (is_hide(body))
    1066             :       {
    1067          18 :         if (status!=mCRL)
    1068             :         {
    1069           0 :           throw mcrl2::runtime_error("A hide operator occurs in the scope of recursion, or a condition, choice or sequential operator in " + process::pp(body) +".");
    1070             :         }
    1071          18 :         determine_process_statusterm(hide(body).operand(),mCRL);
    1072          18 :         return mCRL;
    1073             :       }
    1074             : 
    1075          89 :       if (is_rename(body))
    1076             :       {
    1077           0 :         if (status!=mCRL)
    1078             :         {
    1079           0 :           throw mcrl2::runtime_error("A rename operator occurs in the scope of recursion, or a condition, choice or sequential operator in " + process::pp(body) +".");
    1080             :         }
    1081           0 :         determine_process_statusterm(process::rename(body).operand(),mCRL);
    1082           0 :         return mCRL;
    1083             :       }
    1084             : 
    1085          89 :       if (is_allow(body))
    1086             :       {
    1087          89 :         if (status!=mCRL)
    1088             :         {
    1089           0 :           throw mcrl2::runtime_error("An allow operator occurs in the scope of recursion, or a condition, choice or sequential operator in " + process::pp(body) +".");
    1090             :         }
    1091          89 :         determine_process_statusterm(allow(body).operand(),mCRL);
    1092          89 :         return mCRL;
    1093             :       }
    1094             : 
    1095           0 :       if (is_block(body))
    1096             :       {
    1097           0 :         if (status!=mCRL)
    1098             :         {
    1099           0 :           throw mcrl2::runtime_error("A block operator occurs in the scope of recursion, or a condition, choice or sequential operator in " + process::pp(body) +".");
    1100             :         }
    1101           0 :         determine_process_statusterm(block(body).operand(),mCRL);
    1102           0 :         return mCRL;
    1103             :       }
    1104             : 
    1105           0 :       throw mcrl2::runtime_error("Process has unexpected format (2) " + process::pp(body) +".");
    1106             :       return error;
    1107             :     }
    1108             : 
    1109             : 
    1110        4216 :     void determine_process_status(
    1111             :       const process_identifier& procDecl,
    1112             :       const processstatustype status)
    1113             :     {
    1114             :       processstatustype s;
    1115        4216 :       objectdatatype& object=objectIndex(procDecl);
    1116        4216 :       s=object.processstatus;
    1117             : 
    1118        4216 :       if (s==unknown)
    1119             :       {
    1120        1465 :         object.processstatus=status;
    1121        1465 :         if (status==pCRL)
    1122             :         {
    1123         104 :           determine_process_statusterm(object.processbody,pCRL);
    1124         104 :           return;
    1125             :         }
    1126             :         /* status==mCRL */
    1127        1361 :         s=determine_process_statusterm(object.processbody,mCRL);
    1128        1349 :         if (s!=status)
    1129             :         {
    1130             :           /* s==pCRL and status==mCRL */
    1131         756 :           object.processstatus=s;
    1132         756 :           determine_process_statusterm(object.processbody,pCRL);
    1133             :         }
    1134             :       }
    1135        4100 :       if (s==mCRL)
    1136             :       {
    1137        1165 :         if (status==pCRL)
    1138             :         {
    1139         554 :           object.processstatus=pCRL;
    1140         554 :           determine_process_statusterm(object.processbody,pCRL);
    1141             :         }
    1142             :       }
    1143             :     }
    1144             : 
    1145             :     /***********  collect pcrlprocessen **********************************/
    1146             : 
    1147       10197 :     void collectPcrlProcesses_term(const process_expression& body,  // Intentionally not a reference.
    1148             :                                    std::vector <process_identifier>& pcrlprocesses,
    1149             :                                    std::set <process_identifier>& visited)
    1150             :     {
    1151       10197 :       if (is_if_then(body))
    1152             :       {
    1153         245 :         collectPcrlProcesses_term(if_then(body).then_case(),pcrlprocesses,visited);
    1154         245 :         return;
    1155             :       }
    1156             : 
    1157        9952 :       if (is_if_then_else(body))
    1158             :       {
    1159         122 :         collectPcrlProcesses_term(if_then_else(body).then_case(),pcrlprocesses,visited);
    1160         122 :         collectPcrlProcesses_term(if_then_else(body).else_case(),pcrlprocesses,visited);
    1161         122 :         return;
    1162             :       }
    1163             : 
    1164        9830 :       if (is_choice(body))
    1165             :       {
    1166         631 :         collectPcrlProcesses_term(choice(body).left(),pcrlprocesses,visited);
    1167         631 :         collectPcrlProcesses_term(choice(body).right(),pcrlprocesses,visited);
    1168         631 :         return ;
    1169             :       }
    1170             : 
    1171        9199 :       if (is_seq(body))
    1172             :       {
    1173        2199 :         collectPcrlProcesses_term(seq(body).left(),pcrlprocesses,visited);
    1174        2199 :         collectPcrlProcesses_term(seq(body).right(),pcrlprocesses,visited);
    1175        2199 :         return ;
    1176             :       }
    1177             : 
    1178        7000 :       if (is_merge(body))
    1179             :       {
    1180         348 :         collectPcrlProcesses_term(process::merge(body).left(),pcrlprocesses,visited);
    1181         348 :         collectPcrlProcesses_term(process::merge(body).right(),pcrlprocesses,visited);
    1182         348 :         return ;
    1183             :       }
    1184             : 
    1185        6652 :       if (is_sync(body))
    1186             :       {
    1187         195 :         collectPcrlProcesses_term(process::sync(body).left(),pcrlprocesses,visited);
    1188         195 :         collectPcrlProcesses_term(process::sync(body).right(),pcrlprocesses,visited);
    1189         195 :         return ;
    1190             :       }
    1191             : 
    1192        6457 :       if (is_sum(body))
    1193             :       {
    1194         550 :         collectPcrlProcesses_term(sum(body).operand(),pcrlprocesses,visited);
    1195         550 :         return;
    1196             :       }
    1197             : 
    1198        5907 :       if (is_stochastic_operator(body))
    1199             :       {
    1200          92 :         collectPcrlProcesses_term(stochastic_operator(body).operand(),pcrlprocesses,visited);
    1201          92 :         return;
    1202             :       }
    1203             : 
    1204        5815 :       if (is_at(body))
    1205             :       {
    1206         267 :         collectPcrlProcesses_term(at(body).operand(),pcrlprocesses,visited);
    1207         267 :         return;
    1208             :       }
    1209             : 
    1210        5548 :       if (is_process_instance(body))
    1211             :       {
    1212           0 :         assert(0);
    1213             :         collectPcrlProcesses(process_instance(body).identifier(),pcrlprocesses,visited);
    1214             :         return;
    1215             :       }
    1216             : 
    1217        5548 :       if (is_process_instance_assignment(body))
    1218             :       {
    1219        2179 :         collectPcrlProcesses(process_instance_assignment(body).identifier(),pcrlprocesses,visited);
    1220        2179 :         return;
    1221             :       }
    1222             : 
    1223        3369 :       if (is_hide(body))
    1224             :       {
    1225          18 :         collectPcrlProcesses_term(hide(body).operand(),pcrlprocesses,visited);
    1226          18 :         return;
    1227             :       }
    1228             : 
    1229        3351 :       if (is_rename(body))
    1230             :       {
    1231           0 :         collectPcrlProcesses_term(process::rename(body).operand(),pcrlprocesses,visited);
    1232           0 :         return;
    1233             :       }
    1234             : 
    1235        3351 :       if (is_allow(body))
    1236             :       {
    1237          89 :         collectPcrlProcesses_term(allow(body).operand(),pcrlprocesses,visited);
    1238          89 :         return;
    1239             :       }
    1240             : 
    1241        3262 :       if (is_block(body))
    1242             :       {
    1243           0 :         collectPcrlProcesses_term(block(body).operand(),pcrlprocesses,visited);
    1244           0 :         return;
    1245             :       }
    1246             : 
    1247        3262 :       if (is_comm(body))
    1248             :       {
    1249         112 :         collectPcrlProcesses_term(comm(body).operand(),pcrlprocesses,visited);
    1250         112 :         return;
    1251             :       }
    1252             : 
    1253        9014 :       if ((is_delta(body))||
    1254        5775 :           (is_tau(body))||
    1255        2625 :           (is_action(body)))
    1256             :       {
    1257        3150 :         return;
    1258             :       }
    1259             : 
    1260           0 :       throw mcrl2::runtime_error("process has unexpected format (1) " + process::pp(body) +".");
    1261             :     }
    1262             : 
    1263        2865 :     void collectPcrlProcesses(
    1264             :       const process_identifier& procDecl,
    1265             :       std::vector <process_identifier>& pcrlprocesses,
    1266             :       std::set <process_identifier>& visited)
    1267             :     {
    1268        2865 :       if (visited.count(procDecl)==0)
    1269             :       {
    1270        1834 :         visited.insert(procDecl);
    1271        1834 :         objectdatatype& object=objectIndex(procDecl);
    1272        1834 :         if (object.processstatus==pCRL)
    1273             :         {
    1274        1241 :           pcrlprocesses.push_back(procDecl);
    1275             :         }
    1276        1834 :         collectPcrlProcesses_term(object.processbody,pcrlprocesses,visited);
    1277             :       }
    1278        2865 :     }
    1279             : 
    1280         686 :     void collectPcrlProcesses(
    1281             :       const process_identifier& procDecl,
    1282             :       std::vector <process_identifier>& pcrlprocesses)
    1283             :     {
    1284        1372 :       std::set <process_identifier> visited;
    1285         686 :       collectPcrlProcesses(procDecl, pcrlprocesses, visited);
    1286         686 :     }
    1287             : 
    1288             :     /****************  occursinterm *** occursintermlist ***********/
    1289             : 
    1290       89632 :     bool occursinterm(const variable& var, const data_expression& t) const
    1291             :     {
    1292       89632 :       return data::search_free_variable(t, var);
    1293             :     }
    1294             : 
    1295       80299 :     void filter_vars_by_term(
    1296             :       const data_expression& t,
    1297             :       const std::set < variable >& vars_set,
    1298             :       std::set < variable >& vars_result_set)
    1299             :     {
    1300       80299 :       if (is_variable(t))
    1301             :       {
    1302       19715 :         const variable& v = atermpp::down_cast<variable>(t);
    1303       19715 :         if (vars_set.find(v)!=vars_set.end())
    1304             :         {
    1305        1367 :           vars_result_set.insert(v);
    1306             :         }
    1307       19715 :         return;
    1308             :       }
    1309             : 
    1310       60584 :       if (is_function_symbol(t))
    1311             :       {
    1312       39094 :         return;
    1313             :       }
    1314             : 
    1315       21490 :       if (is_abstraction(t))
    1316             :       {
    1317             :         // mCRL2log(mcrl2::log::warning) << "filtering of variables expression with binders" << std::endl;
    1318          10 :         return;
    1319             :       }
    1320             : 
    1321       21480 :       if (is_where_clause(t))
    1322             :       {
    1323             :         // mCRL2log(mcrl2::log::warning) << "filtering of variables expression with where clause" << std::endl;
    1324           0 :         return;
    1325             :       }
    1326             : 
    1327       21480 :       if (!is_application(t))
    1328             :       {
    1329           0 :         mCRL2log(mcrl2::log::error) << "term of unexpected type " << t << std::endl;
    1330             :       }
    1331             : 
    1332       21480 :       assert(is_application(t));
    1333             : 
    1334       21480 :       const application& a=atermpp::down_cast<const application>(t);
    1335       21480 :       filter_vars_by_term(a.head(),vars_set,vars_result_set);
    1336       21480 :       filter_vars_by_termlist(a.begin(),a.end(),vars_set,vars_result_set);
    1337             :     }
    1338             : 
    1339       13955 :     bool occursintermlist(const variable& var, const data_expression_list& r) const
    1340             :     {
    1341       21921 :       for (data_expression_list::const_iterator l=r.begin() ; l!=r.end() ; ++l)
    1342             :       {
    1343        9166 :         if (occursinterm(var,*l))
    1344             :         {
    1345        1200 :           return true;
    1346             :         }
    1347             :       }
    1348       12755 :       return false;
    1349             :     }
    1350             : 
    1351        6694 :     bool occursintermlist(const variable& var, const assignment_list& r, const process_identifier& proc_name) const
    1352             :     {
    1353       13388 :       std::set<variable> assigned_variables;
    1354       15862 :       for (const assignment& l: r)
    1355             :       {
    1356        9740 :         if (occursinterm(var,l.rhs()))
    1357             :         {
    1358         572 :           return true;
    1359             :         }
    1360        9168 :        assigned_variables.insert(l.lhs());
    1361             :       }
    1362             :       // Check whether x does not occur in the assignment list. Then variable x is assigned to
    1363             :       // itself, and it occurs in the process.
    1364       12244 :       variable_list parameters=objectIndex(proc_name).parameters;
    1365       15531 :       for (variable_list::const_iterator i=parameters.begin(); i!=parameters.end(); ++i)
    1366             :       {
    1367       10115 :         if (var==*i)
    1368             :         {
    1369         960 :           if (assigned_variables.count(var)==0) // This variable is not assigned, so it does occur!
    1370             :           {
    1371         706 :             return true;
    1372             :           }
    1373             :         }
    1374             :       }
    1375        5416 :       return false;
    1376             :     }
    1377             : 
    1378             :     template <typename Iterator>
    1379       78200 :     void filter_vars_by_termlist(
    1380             :       Iterator begin,
    1381             :       const Iterator& end,
    1382             :       const std::set < variable >& vars_set,
    1383             :       std::set < variable >& vars_result_set)
    1384             :     {
    1385      130235 :       for (; begin != end; ++begin)
    1386             :       {
    1387       52035 :         filter_vars_by_term(*begin,vars_set,vars_result_set);
    1388             :       }
    1389       26165 :     }
    1390             : 
    1391        1898 :     void filter_vars_by_multiaction(
    1392             :       const action_list& multiaction,
    1393             :       const std::set < variable >& vars_set,
    1394             :       std::set < variable >& vars_result_set)
    1395             :     {
    1396        4011 :       for (action_list::const_iterator ma=multiaction.begin() ; ma!=multiaction.end() ; ++ma)
    1397             :       {
    1398        2113 :         filter_vars_by_termlist(ma->arguments().begin(), ma->arguments().end(),vars_set,vars_result_set);
    1399             :       }
    1400        1898 :       return;
    1401             :     }
    1402             : 
    1403        1898 :     void filter_vars_by_assignmentlist(
    1404             :       const assignment_list& assignments,
    1405             :       const variable_list& parameters,
    1406             :       const std::set < variable >& vars_set,
    1407             :       std::set < variable >& vars_result_set)
    1408             :     {
    1409        1898 :       const data_expression_list& l=atermpp::container_cast<data_expression_list>(parameters);
    1410        1898 :       filter_vars_by_termlist(l.begin(),l.end(),vars_set,vars_result_set);
    1411        5721 :       for (assignment_list::const_iterator i=assignments.begin();
    1412        5721 :            i!=assignments.end(); ++i)
    1413             :       {
    1414        7646 :         const data_expression rhs=i->rhs();
    1415        3823 :         filter_vars_by_term(rhs,vars_set,vars_result_set);
    1416             :       }
    1417        1898 :     }
    1418             : 
    1419       29976 :     bool occursinpCRLterm(const variable& var,
    1420             :                           const process_expression& p,
    1421             :                           const bool strict)
    1422             :     {
    1423       29976 :       if (is_choice(p))
    1424             :       {
    1425       21312 :         return occursinpCRLterm(var,choice(p).left(),strict)||
    1426       15073 :                occursinpCRLterm(var,choice(p).right(),strict);
    1427             :       }
    1428       23737 :       if (is_seq(p))
    1429             :       {
    1430       22394 :         return occursinpCRLterm(var,seq(p).left(),strict)||
    1431       16228 :                occursinpCRLterm(var,seq(p).right(),strict);
    1432             :       }
    1433       17571 :       if (is_if_then(p))
    1434             :       {
    1435       19522 :         return occursinterm(var,if_then(p).condition())||
    1436       14238 :                occursinpCRLterm(var,if_then(p).then_case(),strict);
    1437             :       }
    1438             : 
    1439       12287 :       if (is_sum(p))
    1440             :       {
    1441          87 :         if (strict)
    1442           0 :           return occursintermlist(var,variable_list_to_data_expression_list(sum(p).variables())) ||
    1443           0 :                  occursinpCRLterm(var,sum(p).operand(),strict);
    1444             :         /* below appears better? , but leads
    1445             :            to errors. Should be investigated. */
    1446             :         else
    1447             :           return
    1448         348 :             (!occursintermlist(var,variable_list_to_data_expression_list(sum(p).variables()))) &&
    1449         261 :             occursinpCRLterm(var,sum(p).operand(),strict);
    1450             :       }
    1451       12200 :       if (is_stochastic_operator(p))
    1452             :       {
    1453          48 :         const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(p);
    1454          48 :         if (strict)
    1455             :         {
    1456           0 :           return occursintermlist(var,variable_list_to_data_expression_list(sto.variables())) ||
    1457           0 :                       occursinterm(var,sto.distribution()) ||
    1458           0 :                       occursinpCRLterm(var,sto.operand(),strict);
    1459             :         }
    1460             :         else
    1461             :         {
    1462         102 :           return (!occursintermlist(var,variable_list_to_data_expression_list(sto.variables()))) &&
    1463          90 :                       (occursinterm(var,sto.distribution()) ||
    1464          90 :                        occursinpCRLterm(var,sto.operand(),strict));
    1465             :         }
    1466             :       }
    1467       12152 :       if (is_process_instance(p))
    1468             :       {
    1469           0 :         assert(0);
    1470             :         return occursintermlist(var,process_instance(p).actual_parameters());
    1471             :       }
    1472       12152 :       if (is_process_instance_assignment(p))
    1473             :       {
    1474        6694 :         return occursintermlist(var,process_instance_assignment(p).assignments(),process_instance_assignment(p).identifier());
    1475             :       }
    1476        5458 :       if (is_action(p))
    1477             :       {
    1478        5416 :         return occursintermlist(var,action(p).arguments());
    1479             :       }
    1480          42 :       if (is_sync(p))
    1481             :       {
    1482          72 :         return occursinpCRLterm(var,process::sync(p).left(),strict)||
    1483          48 :                occursinpCRLterm(var,process::sync(p).right(),strict);
    1484             :       }
    1485          18 :       if (is_at(p))
    1486             :       {
    1487          12 :         return occursinterm(var,at(p).time_stamp()) ||
    1488           8 :                occursinpCRLterm(var,at(p).operand(),strict);
    1489             :       }
    1490          14 :       if (is_delta(p))
    1491             :       {
    1492          14 :         return false;
    1493             :       }
    1494           0 :       if (is_tau(p))
    1495             :       {
    1496           0 :         return false;
    1497             :       }
    1498           0 :       throw mcrl2::runtime_error("unexpected process format in occursinCRLterm " + process::pp(p));
    1499             :       return false;
    1500             :     }
    1501             : 
    1502             :     template <class MutableSubstitution>
    1503         168 :     void alphaconvertprocess(
    1504             :       variable_list& sumvars,
    1505             :       MutableSubstitution& sigma,
    1506             :       const process_expression& p)
    1507             :     {
    1508             :       /* This function replaces the variables in sumvars
    1509             :          by unique ones if these variables occur in occurvars
    1510             :          or occurterms. It extends rename_vars and rename
    1511             :          terms to rename the replaced variables to new ones. */
    1512         336 :       variable_list newsumvars;
    1513             : 
    1514         424 :       for (variable_list::const_iterator l=sumvars.begin() ;
    1515         424 :            l!=sumvars.end() ; ++l)
    1516             :       {
    1517         512 :         const variable var=*l;
    1518         256 :         if (occursinpCRLterm(var,p,true))
    1519             :         {
    1520           0 :           const variable newvar=get_fresh_variable(var.name(),var.sort());
    1521           0 :           newsumvars.push_front(newvar);
    1522           0 :           sigma[var]=newvar;
    1523             :         }
    1524             :         else
    1525             :         {
    1526         256 :           newsumvars.push_front(var);
    1527             :         }
    1528             :       }
    1529         168 :       sumvars=reverse(newsumvars);
    1530         168 :     }
    1531             : 
    1532             :     template <class MutableSubstitution>
    1533       15501 :     void alphaconvert(
    1534             :       variable_list& sumvars,
    1535             :       MutableSubstitution& sigma,
    1536             :       const variable_list& occurvars,
    1537             :       const data_expression_list& occurterms)
    1538             :     {
    1539             :       /* This function replaces the variables in sumvars
    1540             :          by unique ones if these variables occur in occurvars
    1541             :          or occurterms. It extends rename_vars and rename
    1542             :          terms to rename the replaced variables to new ones. */
    1543       31002 :       variable_list newsumvars;
    1544             : 
    1545       19970 :       for (const variable& var: sumvars)
    1546             :       {
    1547        8404 :         if (occursintermlist(var,variable_list_to_data_expression_list(occurvars)) ||
    1548        3935 :             occursintermlist(var,occurterms))
    1549             :         {
    1550        1076 :           const variable newvar=get_fresh_variable(var.name(),var.sort());
    1551         538 :           newsumvars.push_front(newvar);
    1552         538 :           sigma[var]=newvar;
    1553             :         }
    1554             :         else
    1555             :         {
    1556        3931 :           newsumvars.push_front(var);
    1557             :         }
    1558             :       }
    1559       15501 :       sumvars=reverse(newsumvars);
    1560       15501 :     }
    1561             : 
    1562             :     /******************* find_free_variables_process *****************************************/
    1563             : 
    1564             : 
    1565             :     /* We define our own variant of the standard function find_free_variables, because
    1566             :        find_free_variables is not correctly defined on processes, due to process_instance_assignments,
    1567             :        where variables can occur by not being mentioned. It is necessary to know the parameters of
    1568             :        a process to retrieve these. Concrete example in P() defined by P(x:Nat)= ..., the variable x
    1569             :        appears as a free variable, although it is not explicitly mentioned.
    1570             :        If the standard function find_free_variable on processes is repaired, this function can
    1571             :        be removed */
    1572        8444 :     void find_free_variables_process(const process_expression& p, std::set< variable >& free_variables_in_p)
    1573             :     {
    1574        8444 :       if (is_choice(p))
    1575             :       {
    1576         660 :          find_free_variables_process(choice(p).left(),free_variables_in_p);
    1577         660 :          find_free_variables_process(choice(p).right(),free_variables_in_p);
    1578         660 :          return;
    1579             :       }
    1580        7784 :       if (is_seq(p))
    1581             :       {
    1582        2067 :         find_free_variables_process(seq(p).left(),free_variables_in_p);
    1583        2067 :         find_free_variables_process(seq(p).right(),free_variables_in_p);
    1584        2067 :         return;
    1585             :       }
    1586        5717 :       if (is_sync(p))
    1587             :       {
    1588         108 :         find_free_variables_process(process::sync(p).left(),free_variables_in_p);
    1589         108 :         find_free_variables_process(process::sync(p).right(),free_variables_in_p);
    1590         108 :         return;
    1591             :       }
    1592        5609 :       if (is_if_then(p))
    1593             :       {
    1594         644 :         std::set<variable> s=find_free_variables(if_then(p).condition());
    1595         844 :         for(std::set<variable>::const_iterator i=s.begin(); i!=s.end(); ++i)
    1596             :         {
    1597         522 :           free_variables_in_p.insert(*i);
    1598             :         }
    1599         322 :         find_free_variables_process(if_then(p).then_case(),free_variables_in_p);
    1600         322 :         return;
    1601             :       }
    1602        5287 :       if (is_if_then_else(p))
    1603             :       {
    1604           0 :         std::set<variable> s=find_free_variables(if_then(p).condition());
    1605           0 :         for(std::set<variable>::const_iterator i=s.begin(); i!=s.end(); ++i)
    1606             :         {
    1607           0 :           free_variables_in_p.insert(*i);
    1608             :         }
    1609           0 :         find_free_variables_process(if_then_else(p).then_case(),free_variables_in_p);
    1610           0 :         find_free_variables_process(if_then_else(p).else_case(),free_variables_in_p);
    1611           0 :         return;
    1612             :       }
    1613             : 
    1614        5287 :       if (is_sum(p))
    1615             :       {
    1616         509 :         find_free_variables_process(sum(p).operand(),free_variables_in_p);
    1617         509 :         const variable_list& sumargs=sum(p).variables();
    1618             : 
    1619        1141 :         for(variable_list::const_iterator i=sumargs.begin(); i!=sumargs.end(); ++i)
    1620             :         {
    1621         632 :           free_variables_in_p.erase(*i);
    1622             :         }
    1623         509 :         return;
    1624             :       }
    1625             : 
    1626        4778 :       if (is_stochastic_operator(p))
    1627             :       {
    1628          95 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(p);
    1629          95 :         find_free_variables_process(sto.operand(),free_variables_in_p);
    1630         190 :         std::set<variable> s=find_free_variables(sto.distribution());
    1631          96 :         for(std::set<variable>::const_iterator i=s.begin(); i!=s.end(); ++i)
    1632             :         {
    1633           1 :           free_variables_in_p.insert(*i);
    1634             :         }
    1635             : 
    1636          95 :         const variable_list& sumargs=sto.variables();
    1637         733 :         for(variable_list::const_iterator i=sumargs.begin(); i!=sumargs.end(); ++i)
    1638             :         {
    1639         638 :           free_variables_in_p.erase(*i);
    1640             :         }
    1641          95 :         return;
    1642             :       }
    1643             : 
    1644        4683 :       if (is_process_instance(p))
    1645             :       {
    1646           0 :         const process_instance q(p);
    1647           0 :         std::set<variable> free_variables=find_free_variables(q.actual_parameters());
    1648           0 :         for(std::set<variable> ::const_iterator i=free_variables.begin(); i!=free_variables.end(); ++i)
    1649             :         {
    1650           0 :           free_variables_in_p.insert(*i);
    1651             :         }
    1652           0 :         return;
    1653             :       }
    1654        4683 :       if (is_process_instance_assignment(p))
    1655             :       {
    1656        4134 :         const process_instance_assignment q(p);
    1657        2067 :         objectdatatype& object=objectIndex(q.identifier());
    1658        4134 :         const variable_list parameters=object.parameters;
    1659        4134 :         std::set<variable> parameter_set(parameters.begin(),parameters.end());
    1660        2067 :         const assignment_list& assignments=q.assignments();
    1661        3701 :         for(assignment_list::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
    1662             :         {
    1663        3268 :           std::set<variable> s=find_free_variables(i->rhs());
    1664        2873 :           for(std::set<variable>::const_iterator j=s.begin(); j!=s.end(); ++j)
    1665             :           {
    1666        1239 :             free_variables_in_p.insert(*j);
    1667             :           }
    1668        1634 :           parameter_set.erase(i->lhs());
    1669             :         }
    1670             :         // Add all remaining variables in the parameter_set, as they have an identity assignment.
    1671        3235 :         for(std::set<variable>::const_iterator i=parameter_set.begin(); i!=parameter_set.end(); ++i)
    1672             :         {
    1673        1168 :           free_variables_in_p.insert(*i);
    1674             :         }
    1675        2067 :         return;
    1676             :       }
    1677             : 
    1678        2616 :       if (is_action(p))
    1679             :       {
    1680        4286 :         std::set<variable> s=process::find_free_variables(p);
    1681        3517 :         for(std::set<variable>::const_iterator i=s.begin(); i!=s.end(); ++i)
    1682             :         {
    1683        1374 :           free_variables_in_p.insert(*i);
    1684             :         }
    1685        2143 :         return;
    1686             :       }
    1687             : 
    1688         473 :       if (is_at(p))
    1689             :       {
    1690         220 :         std::set<variable> s=data::find_free_variables(at(p).time_stamp());
    1691         117 :         for(std::set<variable>::const_iterator i=s.begin(); i!=s.end(); ++i)
    1692             :         {
    1693           7 :           free_variables_in_p.insert(*i);
    1694             :         }
    1695         110 :         find_free_variables_process(at(p).operand(),free_variables_in_p);
    1696         110 :         return;
    1697             :       }
    1698             : 
    1699         363 :       if (is_delta(p))
    1700             :       {
    1701         312 :         return;
    1702             :       }
    1703             : 
    1704          51 :       if (is_tau(p))
    1705             :       {
    1706          51 :         return;
    1707             :       }
    1708             : 
    1709           0 :       if (is_sync(p))
    1710             :       {
    1711           0 :         find_free_variables_process(process::sync(p).left(),free_variables_in_p);
    1712           0 :         find_free_variables_process(process::sync(p).right(),free_variables_in_p);
    1713           0 :         return;
    1714             :       }
    1715             : 
    1716           0 :       if (is_left_merge(p))
    1717             :       {
    1718           0 :         find_free_variables_process(process::left_merge(p).left(),free_variables_in_p);
    1719           0 :         find_free_variables_process(process::left_merge(p).right(),free_variables_in_p);
    1720           0 :         return;
    1721             :       }
    1722             : 
    1723           0 :       if (is_merge(p))
    1724             :       {
    1725           0 :         find_free_variables_process(process::merge(p).left(),free_variables_in_p);
    1726           0 :         find_free_variables_process(process::merge(p).right(),free_variables_in_p);
    1727           0 :         return;
    1728             :       }
    1729             : 
    1730           0 :       if (is_allow(p))
    1731             :       {
    1732           0 :         find_free_variables_process(process::allow(p).operand(),free_variables_in_p);
    1733           0 :         return;
    1734             :       }
    1735             : 
    1736           0 :       if (is_comm(p))
    1737             :       {
    1738           0 :         find_free_variables_process(process::comm(p).operand(),free_variables_in_p);
    1739           0 :         return;
    1740             :       }
    1741             : 
    1742           0 :       if (is_block(p))
    1743             :       {
    1744           0 :         find_free_variables_process(process::block(p).operand(),free_variables_in_p);
    1745           0 :         return;
    1746             :       }
    1747             : 
    1748           0 :       if (is_hide(p))
    1749             :       {
    1750           0 :         find_free_variables_process(process::hide(p).operand(),free_variables_in_p);
    1751           0 :         return;
    1752             :       }
    1753             : 
    1754           0 :       if (is_rename(p))
    1755             :       {
    1756           0 :         find_free_variables_process(process::rename(p).operand(),free_variables_in_p);
    1757           0 :         return;
    1758             :       }
    1759             : 
    1760           0 :       throw mcrl2::runtime_error("Internal error: expect a pCRL process (1) " + process::pp(p));
    1761             :     }
    1762             : 
    1763        1738 :     std::set< variable > find_free_variables_process(const process_expression& p)
    1764             :     {
    1765        1738 :       std::set<variable> free_variables_in_p;
    1766        1738 :       find_free_variables_process(p,free_variables_in_p);
    1767        1738 :       return free_variables_in_p;
    1768             :     }
    1769             : 
    1770             :     /* Remove assignments that do not appear in the parameter list. */
    1771         102 :     assignment_list filter_assignments(const assignment_list& assignments, const variable_list& parameters)
    1772             :     {
    1773         204 :       assignment_vector result;
    1774         926 :       for(const assignment& a: assignments)
    1775             :       {
    1776         824 :         if (std::find(parameters.begin(),parameters.end(),a.lhs())!=parameters.end())   // found.
    1777             :         {
    1778         824 :           result.push_back(a);
    1779             :         }
    1780             :       }
    1781         204 :       return assignment_list(result.begin(),result.end());
    1782             :     }
    1783             : 
    1784             :     /* Check whether the assignments occur in the same order in the list of parameters */
    1785       37736 :     static bool check_assignment_list(
    1786             :               const assignment_list& assignments,
    1787             :               const variable_list& parameters)
    1788             :     {
    1789       37736 :       assignment_list::iterator i=assignments.begin();
    1790       81271 :       for(const variable& v: parameters)
    1791             :       {
    1792       43535 :         if (i!=assignments.end() && v==i->lhs())
    1793             :         {
    1794       32397 :           ++i;
    1795             :         }
    1796             :       }
    1797       37736 :       return i==assignments.end();
    1798             : 
    1799             :     }
    1800             : 
    1801             :     /******************* substitute *****************************************/
    1802             : 
    1803             : 
    1804             :     template <class Substitution>
    1805       37736 :     assignment_list substitute_assignmentlist(
    1806             :       const assignment_list& assignments,
    1807             :       const variable_list& parameters,
    1808             :       const bool replacelhs,
    1809             :       const bool replacerhs,
    1810             :       Substitution& sigma)
    1811             :     {
    1812       37736 :       assert(check_assignment_list(assignments, parameters));
    1813             :       /* precondition: the variables in the assignment occur in
    1814             :          the same sequence as in the parameters, which stands for the
    1815             :          total list of parameters.
    1816             : 
    1817             :          This function replaces the variables in vars by the terms in terms
    1818             :          in the right hand side of the assignments if replacerhs holds, and
    1819             :          in the lefthandside of an assignment if replacelhs holds. If for some variable
    1820             :          occuring in the parameterlist no assignment is present, whereas
    1821             :          this variable occurs in vars, an assignment for it is added.
    1822             : 
    1823             :          It is not possible to use standard substitution functions to replace substitute_assignmentlis
    1824             :          because they do not take the parameters of processes into account.
    1825             :          For instance consider a process P(b:D)=... of which an instance P() exists.
    1826             :          If the substitution sigma(b)=t is applied to P() the result should be P(b=t).
    1827             :          The standard substitutions do not take this parameterlist into account, as it stands.
    1828             :       */
    1829             : 
    1830             :       assert(replacelhs==0 || replacelhs==1);
    1831             :       assert(replacerhs==0 || replacerhs==1);
    1832       37736 :       if (parameters.empty())
    1833             :       {
    1834       14822 :         assert(assignments.empty());
    1835       14822 :         return assignments;
    1836             :       }
    1837             : 
    1838       22914 :       const variable& parameter=parameters.front();
    1839             : 
    1840       22914 :       if (!assignments.empty())
    1841             :       {
    1842       18586 :         const assignment& ass=assignments.front();
    1843       19686 :         variable lhs=ass.lhs();
    1844       18586 :         if (parameter==lhs)
    1845             :         {
    1846             :           /* The assignment refers to parameter par. Substitute its
    1847             :              left and righthandside */
    1848       34972 :           data_expression rhs=ass.rhs();
    1849             : 
    1850       17486 :           if (replacelhs)
    1851             :           {
    1852        5616 :             lhs = atermpp::down_cast<variable>(sigma(lhs));
    1853             :           }
    1854       17486 :           if (replacerhs)
    1855             :           {
    1856       17486 :             rhs=/* data::*/replace_variables_capture_avoiding_alt(rhs,sigma);
    1857             :           }
    1858             : 
    1859       52458 :           assignment_list result=
    1860             :                    substitute_assignmentlist(
    1861       17486 :                      assignments.tail(),
    1862       17486 :                      parameters.tail(),
    1863             :                      replacelhs,
    1864             :                      replacerhs,
    1865             :                      sigma);
    1866       17486 :           result.push_front(assignment(lhs,rhs));
    1867       17486 :           return result;
    1868             :         }
    1869             :       }
    1870             : 
    1871             :       /* Here the first parameter is not equal to the first
    1872             :          assignment. So, we must find out whether a value
    1873             :          for this variable is substituted, that is different
    1874             :          from the variable, in which case an assignment must
    1875             :          be added. */
    1876             : 
    1877       10856 :       variable lhs=parameter;
    1878       10856 :       data_expression rhs=parameter;
    1879             : 
    1880        5428 :       if (replacelhs)
    1881             :       {
    1882        1956 :         lhs = atermpp::down_cast<data::variable>(sigma(lhs));
    1883             :       }
    1884        5428 :       if (replacerhs)
    1885             :       {
    1886        5428 :         rhs=/* data::*/replace_variables_capture_avoiding_alt(rhs,sigma);
    1887             :       }
    1888             : 
    1889        5428 :       if (lhs==rhs)
    1890             :       {
    1891             :         return substitute_assignmentlist(
    1892             :                  assignments,
    1893        5068 :                  parameters.tail(),
    1894             :                  replacelhs,
    1895             :                  replacerhs,
    1896       10136 :                  sigma);
    1897             :       }
    1898        1080 :       assignment_list result=
    1899             :                substitute_assignmentlist(
    1900             :                  assignments,
    1901         360 :                  parameters.tail(),
    1902             :                  replacelhs,
    1903             :                  replacerhs,
    1904             :                  sigma);
    1905         360 :       result.push_front(assignment(lhs,rhs));
    1906         360 :       return result;
    1907             :     }
    1908             : 
    1909             :     // Sort the assignments, such that they have the same order as the parameters
    1910        1796 :     assignment_list sort_assignments(const assignment_list& ass, const variable_list& parameters)
    1911             :     {
    1912        3592 :       std::map<variable,data_expression>assignment_map;
    1913        3224 :       for(assignment_list::const_iterator i=ass.begin(); i!=ass.end(); ++i)
    1914             :       {
    1915        1428 :         assignment_map[i->lhs()]=i->rhs();
    1916             :       }
    1917             : 
    1918        3592 :       assignment_vector result;
    1919        3896 :       for(variable_list::const_iterator i=parameters.begin(); i!=parameters.end(); ++i)
    1920             :       {
    1921        2100 :         const std::map<variable,data_expression>::const_iterator j=assignment_map.find(*i);
    1922        2100 :         if (j!=assignment_map.end()) // found
    1923             :         {
    1924        1428 :           result.push_back(assignment(j->first,j->second));
    1925             :         }
    1926             :       }
    1927        3592 :       return assignment_list(result.begin(),result.end());
    1928             :     }
    1929             : 
    1930       12580 :     bool check_valid_process_instance_assignment(
    1931             :                const process_identifier& id,
    1932             :                const assignment_list& assignments)
    1933             :     {
    1934       12580 :       objectdatatype& object=objectIndex(id);
    1935       25160 :       variable_list parameters=object.parameters;
    1936       21924 :       for(assignment_list::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
    1937             :       {
    1938             :         // Every assignment must occur in the parameter list, in the right sequence.
    1939             : 
    1940       18688 :         variable v;
    1941         539 :         do
    1942             :         {
    1943        9883 :           if (parameters.empty())
    1944             :           {
    1945           0 :             return false;
    1946             :           }
    1947        9883 :           v=parameters.front();
    1948        9883 :           parameters.pop_front();
    1949             :         }
    1950        9883 :         while (v!=i->lhs());
    1951             : 
    1952             :       }
    1953       12580 :       return true;
    1954             :     }
    1955             : 
    1956             :     /* The function below calculates sigma(p) and replaces
    1957             :        all variables that are bound by a sum in p by unique
    1958             :        variables */
    1959             : 
    1960             :    
    1961             :     /* The function below cannot be replace by replace_variables_capture_avoiding although
    1962             :      * the interfaces are the same. As yet it is unclear why, but the difference shows itself
    1963             :      * for instance when linearising lift3_final.mcrl2 and lift3_init.mcrl2 */
    1964             :     template <class Substitution>
    1965       26618 :     process_expression substitute_pCRLproc(
    1966             :       const process_expression& p,
    1967             :       Substitution& sigma)
    1968             :     {
    1969       26618 :       if (is_choice(p))
    1970             :       {
    1971             :         return choice(
    1972             :                  substitute_pCRLproc(choice(p).left(),sigma),
    1973        1728 :                  substitute_pCRLproc(choice(p).right(),sigma));
    1974             :       }
    1975       24890 :       if (is_seq(p))
    1976             :       {
    1977             :         return seq(
    1978             :                  substitute_pCRLproc(seq(p).left(),sigma),
    1979        6341 :                  substitute_pCRLproc(seq(p).right(),sigma));
    1980             :       }
    1981       18549 :       if (is_sync(p))
    1982             :       {
    1983             :         return process::sync(
    1984             :                  substitute_pCRLproc(process::sync(p).left(),sigma),
    1985         387 :                  substitute_pCRLproc(process::sync(p).right(),sigma));
    1986             :       }
    1987       18162 :       if (is_if_then(p))
    1988             :       {
    1989        4390 :         data_expression condition=replace_variables_capture_avoiding_alt(if_then(p).condition(), sigma);
    1990        2195 :         if (condition==sort_bool::false_())
    1991             :         {
    1992          31 :           return delta_at_zero();
    1993             :         }
    1994        2164 :         if (condition==sort_bool::true_())
    1995             :         {
    1996          63 :           return substitute_pCRLproc(if_then(p).then_case(),sigma);
    1997             :         }
    1998        2101 :         return if_then(condition,substitute_pCRLproc(if_then(p).then_case(),sigma));
    1999             :       }
    2000       15967 :       if (is_if_then_else(p))
    2001             :       {
    2002         122 :         data_expression condition=replace_variables_capture_avoiding_alt(if_then_else(p).condition(), sigma);
    2003          61 :         if (condition==sort_bool::false_())
    2004             :         {
    2005           0 :           return substitute_pCRLproc(if_then_else(p).else_case(),sigma);
    2006             :         }
    2007          61 :         if (condition==sort_bool::true_())
    2008             :         {
    2009           0 :           return substitute_pCRLproc(if_then_else(p).then_case(),sigma);
    2010             :         }
    2011             :         return if_then_else(
    2012             :                  condition,
    2013             :                  substitute_pCRLproc(if_then_else(p).then_case(),sigma),
    2014          61 :                  substitute_pCRLproc(if_then_else(p).else_case(),sigma));
    2015             :       }
    2016             : 
    2017       15906 :       if (is_sum(p))
    2018             :       {
    2019         910 :         variable_list sumargs=sum(p).variables();
    2020         910 :         variable_list vars;
    2021         910 :         data_expression_list terms;
    2022             : 
    2023         649 :         for( std::map < variable, data_expression >::const_iterator i=sigma.begin(); i!=sigma.end(); ++i)
    2024             :         {
    2025         194 :           vars=push_back(vars,i->first);
    2026         194 :           terms=push_back(terms,i->second);
    2027             :         }
    2028             : 
    2029         910 :         maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma=sigma;
    2030         455 :         alphaconvert(sumargs,local_sigma,vars,terms);
    2031             : 
    2032             :         return sum(sumargs,
    2033         455 :                    substitute_pCRLproc(sum(p).operand(),local_sigma));
    2034             :       }
    2035             : 
    2036       15451 :       if (is_stochastic_operator(p))
    2037             :       {
    2038         305 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(p);
    2039         610 :         variable_list sumargs=sto.variables();
    2040         610 :         variable_list vars;
    2041         610 :         data_expression_list terms;
    2042             : 
    2043         404 :         for( std::map < variable, data_expression >::const_iterator i=sigma.begin(); i!=sigma.end(); ++i)
    2044             :         {
    2045          99 :           vars=push_back(vars,i->first);
    2046          99 :           terms=push_back(terms,i->second);
    2047             :         }
    2048             : 
    2049         610 :         maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma=sigma;
    2050         305 :         alphaconvert(sumargs,local_sigma,vars,terms);
    2051             : 
    2052             :         return stochastic_operator(
    2053             :                             sumargs,
    2054             :                             replace_variables_capture_avoiding_alt(sto.distribution(),sigma),
    2055         305 :                             substitute_pCRLproc(sto.operand(),local_sigma));
    2056             :       }
    2057             : 
    2058       15146 :       if (is_process_instance(p))
    2059             :       {
    2060           0 :         assert(0);
    2061             :       }
    2062             : 
    2063       15146 :       if (is_process_instance_assignment(p))
    2064             :       {
    2065       11742 :         const process_instance_assignment q(p);
    2066        5871 :         objectdatatype& object=objectIndex(q.identifier());
    2067       11742 :         const variable_list parameters=object.parameters;
    2068       11742 :         const assignment_list new_assignments=substitute_assignmentlist(q.assignments(),parameters,false,true,sigma);
    2069        5871 :         assert(check_valid_process_instance_assignment(q.identifier(),new_assignments));
    2070        5871 :         return process_instance_assignment(q.identifier(),new_assignments);
    2071             :       }
    2072             : 
    2073        9275 :       if (is_action(p))
    2074             :       {
    2075             :         return action(action(p).label(),
    2076        7885 :                       /* data::*/replace_variables_capture_avoiding_alt(action(p).arguments(), sigma));
    2077             :       }
    2078             : 
    2079        1390 :       if (is_at(p))
    2080             :       {
    2081             :         return at(substitute_pCRLproc(at(p).operand(),sigma),
    2082         524 :                   /* data::*/replace_variables_capture_avoiding_alt(at(p).time_stamp(),sigma));
    2083             :       }
    2084             : 
    2085         866 :       if (is_delta(p))
    2086             :       {
    2087         706 :         return p;
    2088             :       }
    2089             : 
    2090         160 :       if (is_tau(p))
    2091             :       {
    2092         160 :         return p;
    2093             :       }
    2094             : 
    2095           0 :       if (is_sync(p))
    2096             :       {
    2097             :         return process::sync(
    2098             :                  substitute_pCRLproc(process::sync(p).left(),sigma),
    2099           0 :                  substitute_pCRLproc(process::sync(p).right(),sigma));
    2100             :       }
    2101             : 
    2102           0 :       throw mcrl2::runtime_error("Internal error: expect a pCRL process (2) " + process::pp(p));
    2103             :       return process_expression();
    2104             :     }
    2105             : 
    2106             : 
    2107             :     // The function below transforms a ProcessAssignment to a Process, provided
    2108             :     // that the process is defined in objectnames.
    2109             : 
    2110        2032 :     process_instance_assignment transform_process_instance_to_process_instance_assignment(
    2111             :               const process_instance& procId,
    2112             :               const std::set<variable>& bound_variables=std::set<variable>())
    2113             :     {
    2114        2032 :       objectdatatype& object=objectIndex(procId.identifier());
    2115        4064 :       const variable_list process_parameters=object.parameters;
    2116        2032 :       const data_expression_list& rhss=procId.actual_parameters();
    2117             : 
    2118        4064 :       assignment_vector new_assignments;
    2119        2032 :       data_expression_list::const_iterator j=rhss.begin();
    2120        3772 :       for(variable_list::const_iterator i=process_parameters.begin(); i!=process_parameters.end(); ++i, ++j)
    2121             :       {
    2122        1740 :         assert(j!=rhss.end());
    2123        1740 :         if (*i==*j)
    2124             :         {
    2125         664 :           if (bound_variables.count(*i)>0) // Now *j is a different variable than *i
    2126             :           {
    2127          63 :             new_assignments.push_back(assignment(*i,*j));
    2128             :           }
    2129             :         }
    2130             :         else
    2131             :         {
    2132        1076 :           new_assignments.push_back(assignment(*i,*j));
    2133             :         }
    2134             :       }
    2135        2032 :       assert(j==rhss.end());
    2136             : 
    2137        2032 :       assert(check_valid_process_instance_assignment(procId.identifier(),assignment_list(new_assignments.begin(),new_assignments.end())));
    2138        2032 :       process_instance_assignment p(procId.identifier(), assignment_list(new_assignments.begin(),new_assignments.end()));
    2139        4064 :       return p;
    2140             :     }
    2141             : 
    2142             :     /********************************************************************/
    2143             :     /*                                                                  */
    2144             :     /*   BELOW THE PROCEDURES ARE GIVEN TO TRANSFORM PROCESSES TO       */
    2145             :     /*   LINEAR PROCESSES.                                              */
    2146             :     /*                                                                  */
    2147             :     /*                                                                  */
    2148             :     /*                                                                  */
    2149             :     /********************************************************************/
    2150             : 
    2151             :     typedef enum { first, later } variableposition;
    2152             : 
    2153             :     /****************  tovarheadGNF  *********************************/
    2154             : 
    2155        3294 :     variable_list parameters_that_occur_in_body(
    2156             :       const variable_list& parameters,
    2157             :       const process_expression& body)
    2158             :     {
    2159        6588 :       variable_vector result; 
    2160        6071 :       for(const variable& p: parameters) 
    2161             :       {
    2162        2777 :         if (occursinpCRLterm(p,body,false))
    2163             :         {
    2164        2309 :           result.push_back(p);
    2165             :         }
    2166             :       }
    2167        6588 :       return variable_list(result.begin(),result.end());
    2168             :     }
    2169             : 
    2170             :     // The variable below is used to count the number of new processes that
    2171             :     // are made. If this number is very high, it is likely that the regular
    2172             :     // flag is used, and an unbounded number of new processes are generated.
    2173             :     // In such a case a warning is printed suggesting to use regular2.
    2174             : 
    2175        3237 :     process_identifier newprocess(
    2176             :       const variable_list& parameters,
    2177             :       const process_expression& body,
    2178             :       const processstatustype ps,
    2179             :       const bool canterminate,
    2180             :       const bool containstime)
    2181             :     {
    2182        3237 :       assert(canterminatebody(body)==canterminate);
    2183        3237 :       assert(containstimebody(body)==containstime);
    2184             : 
    2185        6474 :       process_identifier p1;
    2186        3237 :       if (searchProcDeclaration(parameters,body,ps, canterminate,containstime,p1))
    2187             :       {
    2188          45 :         return p1;  // The process did already exist. No need to make a new one.
    2189             :       }
    2190             : 
    2191             :       static std::size_t numberOfNewProcesses=0, warningNumber=25;
    2192        3192 :       numberOfNewProcesses++;
    2193        3192 :       if (numberOfNewProcesses == warningNumber)
    2194             :       {
    2195          20 :         mCRL2log(mcrl2::log::warning) << "Generated " << numberOfNewProcesses << " new internal processes.";
    2196             : 
    2197          20 :         if (options.lin_method==lmRegular)
    2198             :         {
    2199          14 :           mCRL2log(mcrl2::log::warning) << " A possible unbounded loop can be avoided by using `regular2' or `stack' as linearisation method." << std::endl;
    2200             :         }
    2201           6 :         else if (options.lin_method==lmRegular2)
    2202             :         {
    2203           2 :           mCRL2log(mcrl2::log::warning) << " A possible unbounded loop can be avoided by using `stack' as the linearisation method." << std::endl;
    2204             :         }
    2205             :         else
    2206             :         {
    2207           4 :           mCRL2log(mcrl2::log::warning) << std::endl;
    2208             :         }
    2209          20 :         warningNumber=warningNumber*5;
    2210             :       }
    2211        6384 :       const variable_list parameters1=parameters_that_occur_in_body(parameters, body);
    2212        6384 :       const core::identifier_string s=fresh_identifier_generator("P");
    2213        6384 :       const process_identifier p(s, parameters1);
    2214        3192 :       assert(std::string(p.name()).size()>0);
    2215        3192 :       insert_process_declaration(
    2216             :         p,
    2217             :         parameters1,
    2218             :         body,
    2219             :         ps,
    2220             :         canterminate,
    2221        3192 :         containstime);
    2222        3192 :       return p;
    2223             :     }
    2224             : 
    2225             : 
    2226         267 :     process_expression wraptime(
    2227             :       const process_expression& body,
    2228             :       const data_expression& time,
    2229             :       const variable_list& freevars)
    2230             :     {
    2231         267 :       if (is_choice(body))
    2232             :       {
    2233           0 :         return choice(
    2234           0 :                  wraptime(choice(body).left(),time,freevars),
    2235           0 :                  wraptime(choice(body).right(),time,freevars));
    2236             :       }
    2237             : 
    2238         267 :       if (is_sum(body))
    2239             :       {
    2240           0 :         variable_list sumvars=sum(body).variables();
    2241           0 :         process_expression body1=sum(body).operand();
    2242             : 
    2243           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    2244           0 :         alphaconvert(sumvars,sigma,freevars,data_expression_list());
    2245           0 :         body1=substitute_pCRLproc(body1, sigma);
    2246           0 :         maintain_variables_in_rhs< mutable_map_substitution<> >  sigma_aux(sigma);
    2247           0 :         const data_expression time1=/*data::*/replace_variables_capture_avoiding_alt(time, sigma_aux);
    2248           0 :         body1=wraptime(body1,time1,sumvars+freevars);
    2249           0 :         return sum(sumvars,body1);
    2250             :       }
    2251             : 
    2252         267 :       if (is_stochastic_operator(body))
    2253             :       {
    2254           0 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(body);
    2255           0 :         variable_list sumvars=sto.variables();
    2256           0 :         process_expression body1=sto.operand();
    2257             : 
    2258           0 :         maintain_variables_in_rhs<mutable_map_substitution<> > sigma;
    2259           0 :         alphaconvert(sumvars,sigma,freevars,data_expression_list());
    2260           0 :         body1=substitute_pCRLproc(body1, sigma);
    2261           0 :         const data_expression new_distribution=replace_variables_capture_avoiding_alt(sto.distribution(), sigma);
    2262           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma_aux(sigma);
    2263           0 :         const data_expression time1=replace_variables_capture_avoiding_alt(time, sigma_aux);
    2264           0 :         body1=wraptime(body1,time1,sumvars+freevars);
    2265           0 :         return stochastic_operator(sumvars,new_distribution,body1);
    2266             :       }
    2267             : 
    2268         267 :       if (is_if_then(body))
    2269             :       {
    2270           0 :         return if_then(if_then(body).condition(),wraptime(if_then(body).then_case(),time,freevars));
    2271             :       }
    2272             : 
    2273         267 :       if (is_seq(body))
    2274             :       {
    2275           0 :         return seq(wraptime(seq(body).left(),time,freevars),seq(body).right());
    2276             :       }
    2277             : 
    2278         267 :       if (is_at(body))
    2279             :       {
    2280             :         /* make a new process */
    2281             :         const process_identifier newproc=newprocess(freevars,body,pCRL,
    2282           0 :                                          canterminatebody(body),containstimebody(body));
    2283           0 :         assert(check_valid_process_instance_assignment(newproc,assignment_list()));
    2284           0 :         return at(process_instance_assignment(
    2285             :                     newproc,
    2286           0 :                     assignment_list()),  //data::data_expression_list(objectdata[objectIndex(newproc)].parameters)),
    2287           0 :                   time);
    2288             :       }
    2289             : 
    2290         267 :       if (// (is_process_instance(body))||
    2291         534 :           (is_process_instance_assignment(body))||
    2292         504 :           (is_sync(body))||
    2293         346 :           (is_action(body))||
    2294         485 :           (is_tau(body))||
    2295         109 :           (is_delta(body)))
    2296             :       {
    2297         267 :         return at(body,time);
    2298             :       }
    2299             : 
    2300           0 :       throw mcrl2::runtime_error("Internal error: expect a pCRL process in wraptime " + process::pp(body));
    2301             :       return process_expression();
    2302             :     }
    2303             : 
    2304             :     typedef enum { alt_state, sum_state, /* cond,*/ seq_state, name_state, multiaction_state } state;
    2305             : 
    2306        4743 :     variable get_fresh_variable(const std::string& s, const sort_expression& sort, const int reuse_index=-1)
    2307             :     {
    2308             :       /* If reuse_index is smaller than 0 (-1 is the default value), an unused variable name is returned,
    2309             :          based on the string s with sort `sort'. If reuse_index is larger or equal to
    2310             :          0 the reuse_index+1 generated variable is returned. If for a particular reuse_index
    2311             :          this function is called for the first time, it is guaranteed that the returned
    2312             :          variable is unique, and not used as variable elsewhere. Upon subsequent calls
    2313             :          get_fresh_variable will return the same variable for the same s,sort and reuse_triple.
    2314             :          This feature is added to make it possible to avoid generating too many different variables. */
    2315             : 
    2316             : 
    2317        4743 :       if (reuse_index<0)
    2318             :       {
    2319        9486 :         variable v(fresh_identifier_generator(s),sort);
    2320        4743 :         insertvariable(v,true);
    2321        4743 :         return v;
    2322             :       }
    2323             :       else
    2324             :       {
    2325           0 :         static std::map < int , std::map < variable,variable > > generated_variables;
    2326           0 :         variable table_index_term(s,sort);
    2327           0 :         variable old_variable;
    2328           0 :         if (generated_variables[reuse_index].count(table_index_term)>0)
    2329             :         {
    2330           0 :           old_variable=generated_variables[reuse_index][table_index_term];
    2331             :         }
    2332             :         else
    2333             :         {
    2334             :           /* A new variable must be generated */
    2335           0 :           old_variable=get_fresh_variable(s,sort);
    2336           0 :           generated_variables[reuse_index][table_index_term]=old_variable;
    2337             :         }
    2338           0 :         return old_variable;
    2339             :       }
    2340             :     }
    2341             : 
    2342             :     variable_list make_pars(const sort_expression_list& sortlist)
    2343             :     {
    2344             :       /* this function returns a list of variables,
    2345             :          corresponding to the sorts in sortlist */
    2346             : 
    2347             :       if (sortlist.empty())
    2348             :       {
    2349             :         return variable_list();
    2350             :       }
    2351             : 
    2352             :       const sort_expression& sort=sortlist.front();
    2353             : 
    2354             :       variable_list result=make_pars(sortlist.tail());
    2355             :       result.push_front(get_fresh_variable("a",sort));
    2356             :       return result;
    2357             :     }
    2358             : 
    2359           0 :     process_expression distributeActionOverConditions(
    2360             :       const process_expression& act, // This is a multi-action, actually.
    2361             :       const data_expression& condition,
    2362             :       const process_expression& restterm,
    2363             :       const variable_list& freevars,
    2364             :       const std::set<variable>& variables_bound_in_sum)
    2365             :     {
    2366           0 :       if (is_if_then(restterm))
    2367             :       {
    2368             :         /* Here we check whether the process body has the form
    2369             :            a (c -> x). For state space generation it turns out
    2370             :            to be beneficial to rewrite this to c-> a x + !c -> a.delta@0, as in
    2371             :            certain cases this leads to a reduction of the number
    2372             :            of states. In this code, we recursively check whether
    2373             :            the action must be distributed over x. This optimisation
    2374             :            was observed by Yaroslav Usenko, May 2006. Implemented by JFG.
    2375             :            On industrial examples, it appears to reduce the state space
    2376             :            with a factor up to 2.
    2377             :            Before october 2008 this code was wrong, as it transformed
    2378             :            an expression to c-> a x, ommitting the a.delta@0. */
    2379             : 
    2380           0 :         const data_expression c=if_then(restterm).condition();
    2381           0 :         const process_expression r=choice(
    2382           0 :                                      distributeActionOverConditions(
    2383             :                                        act,
    2384           0 :                                        lazy::and_(condition,c),
    2385           0 :                                        if_then(restterm).then_case(),
    2386             :                                        freevars,variables_bound_in_sum),
    2387           0 :                                      distributeActionOverConditions(
    2388             :                                        act,
    2389           0 :                                        lazy::and_(condition,lazy::not_(c)),
    2390           0 :                                        delta_at_zero(),
    2391           0 :                                        freevars,variables_bound_in_sum));
    2392           0 :         return r;
    2393             :       }
    2394           0 :       if (is_if_then_else(restterm))
    2395             :       {
    2396             :         /* Here we check whether the process body has the form
    2397             :            a (c -> x <> y). For state space generation it turns out
    2398             :            to be beneficial to rewrite this to c-> a x + !c -> a y, as in
    2399             :            certain cases this leads to a reduction of the number
    2400             :            of states, despite the duplication of the a action. In this code,
    2401             :            we recursively check whether the action must be distributed over
    2402             :            x and y. This optimisation
    2403             :            was observed by Yaroslav Usenko, May 2006. Implemented by JFG.
    2404             :            On industrial examples, it appears to reduce the state space
    2405             :            with a factor up to 2. */
    2406             : 
    2407           0 :         const data_expression c=if_then_else(restterm).condition();
    2408           0 :         const process_expression r=choice(
    2409           0 :                                      distributeActionOverConditions(
    2410             :                                        act,
    2411           0 :                                        lazy::and_(condition,c),
    2412           0 :                                        if_then_else(restterm).then_case(),
    2413             :                                        freevars,variables_bound_in_sum),
    2414           0 :                                      distributeActionOverConditions(
    2415             :                                        act,
    2416           0 :                                        lazy::and_(condition,lazy::not_(c)),
    2417           0 :                                        if_then_else(restterm).else_case(),
    2418           0 :                                        freevars,variables_bound_in_sum));
    2419           0 :         return r;
    2420             :       }
    2421           0 :       const process_expression restterm1=bodytovarheadGNF(restterm,seq_state,freevars,later,variables_bound_in_sum);
    2422           0 :       return if_then(condition,seq(act,restterm1));
    2423             :     }
    2424             : 
    2425             : 
    2426        1276 :    assignment_list parameters_to_assignment_list(const variable_list& parameters, const std::set<variable>& variables_bound_in_sum)
    2427             :    {
    2428        2552 :      assignment_vector result;
    2429        2508 :      for(variable_list::const_iterator i=parameters.begin(); i!=parameters.end(); ++i)
    2430             :      {
    2431        1232 :        if (variables_bound_in_sum.count(*i)>0)
    2432             :        {
    2433         568 :          result.push_back(assignment(*i,*i)); // rhs is another variable than the lhs!!
    2434             :        }
    2435             :      }
    2436        2552 :      return assignment_list(result.begin(),result.end());
    2437             :    }
    2438             : 
    2439             : 
    2440        9230 :     process_expression bodytovarheadGNF(
    2441             :       const process_expression& body, 
    2442             :       const state s,
    2443             :       const variable_list& freevars, 
    2444             :       const variableposition v,
    2445             :       const std::set<variable>& variables_bound_in_sum)
    2446             :     {
    2447             :       /* it is assumed that we only receive processes with
    2448             :          operators alt, seq, sum_state, cond, name, delta, tau, sync, at and stochastic operator in it */
    2449             : 
    2450        9230 :       if (is_choice(body))
    2451             :       {
    2452         979 :         if (alt_state>=s)
    2453             :         {
    2454        1262 :           const process_expression body1=bodytovarheadGNF(choice(body).left(),alt_state,freevars,first,variables_bound_in_sum);
    2455        1262 :           const process_expression body2=bodytovarheadGNF(choice(body).right(),alt_state,freevars,first,variables_bound_in_sum);
    2456         631 :           if (isDeltaAtZero(body1))
    2457             :           {
    2458           0 :             return body2;
    2459             :           }
    2460         631 :           if (isDeltaAtZero(body2))
    2461             :           {
    2462           0 :             return body1;
    2463             :           }
    2464         631 :           return choice(body1,body2);
    2465             :         }
    2466         696 :         const process_expression body1=bodytovarheadGNF(body,alt_state,freevars,first,variables_bound_in_sum);
    2467             :         const process_identifier newproc=newprocess(freevars,body1,pCRL,
    2468         348 :                                          canterminatebody(body1),
    2469        1044 :                                          containstimebody(body1));
    2470         348 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2471         348 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2472             :       }
    2473             : 
    2474        8251 :       if (is_sum(body))
    2475             :       {
    2476         602 :         if (sum_state>=s)
    2477             :         {
    2478        1100 :           variable_list sumvars=sum(body).variables();
    2479        1100 :           process_expression body1=sum(body).operand();
    2480             : 
    2481        1100 :           maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    2482         550 :           alphaconvert(sumvars,sigma,freevars,data_expression_list());
    2483         550 :           body1=substitute_pCRLproc(body1,sigma);
    2484        1100 :           std::set<variable> variables_bound_in_sum1=variables_bound_in_sum;
    2485         550 :           variables_bound_in_sum1.insert(sumvars.begin(),sumvars.end());
    2486         550 :           body1=bodytovarheadGNF(body1,sum_state,sumvars+freevars,first,variables_bound_in_sum1);
    2487             :           /* Due to the optimisation below, suggested by Yaroslav Usenko, bodytovarheadGNF(...,sum_state,...)
    2488             :              can deliver a process of the form c -> x + !c -> y. In this case, the
    2489             :              sumvars must be distributed over both summands. */
    2490         550 :           if (is_choice(body1))
    2491             :           {
    2492           0 :             return choice(sum(sumvars,choice(body1).left()),
    2493           0 :                           sum(sumvars,choice(body1).right()));
    2494             :           }
    2495         550 :           return sum(sumvars,body1);
    2496             :         }
    2497         104 :         const process_expression body1=bodytovarheadGNF(body,alt_state,freevars,first,variables_bound_in_sum);
    2498             :         const process_identifier newproc=newprocess(freevars,body1,pCRL,
    2499          52 :                                          canterminatebody(body1),
    2500         156 :                                          containstimebody(body1));
    2501          52 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2502          52 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2503             :       }
    2504             : 
    2505        7649 :       if (is_stochastic_operator(body))
    2506             :       {
    2507          92 :         if (seq_state>=s)
    2508             :         {
    2509          85 :           const stochastic_operator& sto=down_cast<const stochastic_operator>(body);
    2510         170 :           variable_list sumvars=sto.variables();
    2511         170 :           data_expression distribution=sto.distribution();
    2512         170 :           process_expression body1=sto.operand();
    2513             : 
    2514         170 :           maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    2515          85 :           alphaconvert(sumvars,sigma,freevars,data_expression_list());
    2516          85 :           distribution=/* data::*/replace_variables_capture_avoiding_alt(distribution,sigma);
    2517          85 :           body1=substitute_pCRLproc(body1,sigma);
    2518         170 :           std::set<variable> variables_bound_in_sum1=variables_bound_in_sum;
    2519          85 :           variables_bound_in_sum1.insert(sumvars.begin(),sumvars.end());
    2520          85 :           body1=bodytovarheadGNF(body1,name_state,sumvars+freevars,v,variables_bound_in_sum1);
    2521             :           /* Due to the optimisation below, suggested by Yaroslav Usenko, bodytovarheadGNF(...,sum_state,...)
    2522             :              can deliver a process of the form c -> x + !c -> y. In this case, the
    2523             :              sumvars must be distributed over both summands. */
    2524          85 :           return stochastic_operator(sumvars,distribution,body1);
    2525             :         }
    2526          14 :         const process_expression body_=bodytovarheadGNF(body,seq_state,freevars,first,variables_bound_in_sum);
    2527             :         const process_identifier newproc=newprocess(freevars,body_,pCRL,
    2528           7 :                                          canterminatebody(body_),
    2529          21 :                                          containstimebody(body_));
    2530           7 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2531           7 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2532             :       }
    2533             : 
    2534        7557 :       if (is_if_then(body))
    2535             :       {
    2536         508 :         const data_expression condition=if_then(body).condition();
    2537         508 :         const process_expression body1=if_then(body).then_case();
    2538             : 
    2539         254 :         if (s<=sum_state)
    2540             :         {
    2541         490 :           return if_then(
    2542             :                    condition,
    2543         735 :                    bodytovarheadGNF(body1,seq_state,freevars,first,variables_bound_in_sum));
    2544             :         }
    2545          18 :         const process_expression body2=bodytovarheadGNF(body,alt_state,freevars,first,variables_bound_in_sum);
    2546             :         const process_identifier newproc=newprocess(freevars,body2,pCRL,
    2547           9 :                                          canterminatebody(body2),
    2548          27 :                                          containstimebody(body2));
    2549           9 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2550           9 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2551             : 
    2552             :       }
    2553             : 
    2554        7303 :       if (is_if_then_else(body))
    2555             :       {
    2556         448 :         const data_expression condition=data_expression(if_then_else(body).condition());
    2557         448 :         const process_expression body1=if_then_else(body).then_case();
    2558         448 :         const process_expression body2=if_then_else(body).else_case();
    2559             : 
    2560         224 :         if (isDeltaAtZero(body1) && isDeltaAtZero(body2))
    2561             :         {
    2562           0 :           return body1;
    2563             :         }
    2564             : 
    2565         224 :         if ((s<=sum_state) && ((isDeltaAtZero(body1))||(isDeltaAtZero(body2))))
    2566             :         {
    2567           0 :           if (isDeltaAtZero(body2))
    2568             :           {
    2569           0 :             return if_then(
    2570             :                      condition,
    2571           0 :                      bodytovarheadGNF(body1,seq_state,freevars,first,variables_bound_in_sum));
    2572             :           }
    2573             :           /* body1=="Delta@0" */
    2574             :           {
    2575           0 :             return if_then(
    2576           0 :                      lazy::not_(condition),
    2577           0 :                      bodytovarheadGNF(body2,seq_state,freevars,first,variables_bound_in_sum));
    2578             :           }
    2579             :         }
    2580         224 :         if (alt_state==s) /* body1!=Delta@0 and body2!=Delta@0 */
    2581             :         {
    2582             :           return
    2583         244 :             choice(
    2584         244 :               if_then(
    2585             :                 condition,
    2586         244 :                 bodytovarheadGNF(body1,seq_state,freevars,first,variables_bound_in_sum)),
    2587         244 :               if_then(
    2588         244 :                 lazy::not_(condition),
    2589         366 :                 bodytovarheadGNF(body2,seq_state,freevars,first,variables_bound_in_sum)));
    2590             :         }
    2591         204 :         const process_expression body3=bodytovarheadGNF(body,alt_state,freevars,first,variables_bound_in_sum);
    2592             :         const process_identifier newproc=newprocess(freevars,body3,pCRL,
    2593         102 :                                          canterminatebody(body3),
    2594         306 :                                          containstimebody(body3));
    2595         102 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2596         102 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2597             : 
    2598             :       }
    2599             : 
    2600        7079 :       if (is_seq(body))
    2601             :       {
    2602        4508 :         process_expression body1=seq(body).left();
    2603        4508 :         process_expression body2=seq(body).right();
    2604             : 
    2605        2254 :         if (s<=seq_state)
    2606             :         {
    2607        2199 :           body1=bodytovarheadGNF(body1,name_state,freevars,v,variables_bound_in_sum);
    2608        2199 :           if (!canterminatebody(body1))
    2609             :           {
    2610             :             /* In this case there is no need to investigate body2, as it cannot be reached. */
    2611          25 :             return body1;
    2612             :           }
    2613        2174 :           if ((is_if_then(body2)) && (s<=sum_state))
    2614             :           {
    2615             :             /* Here we check whether the process body has the form
    2616             :                a (c -> x) + !c -> delta@0. For state space generation it turns out
    2617             :                to be beneficial to rewrite this to c-> a x, as in
    2618             :                certain cases this leads to a reduction of the number
    2619             :                of states. An extra change (24/12/2006) is that the
    2620             :                conditions are distributed recursively over
    2621             :                all conditions. The optimisation
    2622             :                was observed by Yaroslav Usenko, May 2006. Implemented by JFG.
    2623             :                On industrial examples, it appears to reduce the state space
    2624             :                with a factor up to 2. Until 1/11/2008 this code was incorrect,
    2625             :                because the summand a (!c -> delta@0) was not forgotten.*/
    2626             : 
    2627           0 :             const data_expression c(if_then(body2).condition());
    2628             : 
    2629           0 :             const process_expression r= choice(
    2630           0 :                                           distributeActionOverConditions(body1,c,if_then(body2).then_case(),freevars,variables_bound_in_sum),
    2631           0 :                                           distributeActionOverConditions(body1,lazy::not_(c),delta_at_zero(),freevars,variables_bound_in_sum));
    2632           0 :             return r;
    2633             :           }
    2634        2174 :           if ((is_if_then_else(body2)) && (s<=sum_state))
    2635             :           {
    2636             : 
    2637             :             /* Here we check whether the process body has the form
    2638             :                a (c -> x <> y). For state space generation it turns out
    2639             :                to be beneficial to rewrite this to c-> a x + !c -> a y, as in
    2640             :                certain cases this leads to a reduction of the number
    2641             :                of states, despite the duplication of the a action. An extra
    2642             :                change (24/12/2006) is that the conditions are distributed recursively over
    2643             :                all conditions. The optimisation
    2644             :                was observed by Yaroslav Usenko, May 2006. Implemented by JFG.
    2645             :                On industrial examples, it appears to reduce the state space
    2646             :                with a factor up to 2. */
    2647             : 
    2648             : 
    2649           0 :             const data_expression c(if_then_else(body2).condition());
    2650           0 :             const process_expression r= choice(
    2651           0 :                                           distributeActionOverConditions(body1,c,if_then_else(body2).then_case(),freevars,variables_bound_in_sum),
    2652           0 :                                           distributeActionOverConditions(body1,lazy::not_(c),if_then_else(body2).else_case(),freevars,variables_bound_in_sum));
    2653           0 :             return r;
    2654             :           }
    2655        2174 :           body2=bodytovarheadGNF(body2,seq_state,freevars,later,variables_bound_in_sum);
    2656        2174 :           return seq(body1,body2);
    2657             :         }
    2658          55 :         body1=bodytovarheadGNF(body,alt_state,freevars,first,variables_bound_in_sum);
    2659          55 :         const process_identifier newproc=newprocess(freevars,body1,pCRL,canterminatebody(body1),
    2660         165 :                                          containstimebody(body1));
    2661             : 
    2662          55 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2663          55 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2664             :       }
    2665             : 
    2666        4825 :       if (is_action(body))
    2667             :       {
    2668        2625 :         if ((s==multiaction_state)||(v==first))
    2669             :         {
    2670        2176 :           return body;
    2671             :         }
    2672             : 
    2673         449 :         bool isnew=false;
    2674         449 :         objectdatatype& object=addMultiAction(action(body),isnew);
    2675             : 
    2676         449 :         if (object.process_representing_action==process_identifier())
    2677             :         {
    2678             :           /* this action does not yet have a corresponding process, which
    2679             :              must be constructed. The resulting process is stored in
    2680             :              the variable process_representing_action in objectdata. Tempvar below is
    2681             :              needed as objectdata may be realloced as a side effect
    2682             :              of newprocess */
    2683             :           const process_identifier tempvar=newprocess(
    2684             :                                              object.parameters,
    2685             :                                              object.processbody,
    2686         736 :                                              GNF,true,false);
    2687         368 :           object.process_representing_action=tempvar;
    2688             :         }
    2689        1796 :         return transform_process_instance_to_process_instance_assignment(
    2690         898 :                           process_instance(object.process_representing_action,
    2691        1347 :                           action(body).arguments()));
    2692             :       }
    2693             : 
    2694        2200 :       if (is_sync(body))
    2695             :       {
    2696         195 :         bool isnew=false;
    2697         390 :         const process_expression body1=process::sync(body).left();
    2698         390 :         const process_expression body2=process::sync(body).right();
    2699             :         const action_list ma=linMergeMultiActionListProcess(
    2700         390 :                                bodytovarheadGNF(body1,multiaction_state,freevars,v,variables_bound_in_sum),
    2701         780 :                                bodytovarheadGNF(body2,multiaction_state,freevars,v,variables_bound_in_sum));
    2702             : 
    2703         390 :         const process_expression mp=action_list_to_process(ma);
    2704         195 :         if ((s==multiaction_state)||(v==first))
    2705             :         {
    2706         177 :           return mp;
    2707             :         }
    2708             : 
    2709          18 :         objectdatatype& object=addMultiAction(mp,isnew);
    2710             : 
    2711          18 :         if (object.process_representing_action==process_identifier())
    2712             :         {
    2713             :           /* this action does not yet have a corresponding process, which
    2714             :              must be constructed. The resulting process is stored in
    2715             :              the variable process_representing_action in objectdata. Tempvar below is needed
    2716             :              as objectdata may be realloced as a side effect of newprocess */
    2717             :           process_identifier tempvar=newprocess(
    2718             :                                        object.parameters,
    2719             :                                        object.processbody,
    2720          36 :                                        GNF,true,false);
    2721          18 :           object.process_representing_action=tempvar;
    2722             :         }
    2723          72 :         return transform_process_instance_to_process_instance_assignment(
    2724          36 :                       process_instance(
    2725          36 :                            process_identifier(object.process_representing_action),
    2726          54 :                            getarguments(ma)));
    2727             :       }
    2728             : 
    2729        2005 :       if (is_at(body))
    2730             :       {
    2731             :         process_expression body1=bodytovarheadGNF(
    2732         534 :                                    at(body).operand(),
    2733             :                                    s,
    2734             :                                    freevars,
    2735         534 :                                    first,variables_bound_in_sum);
    2736         534 :         data_expression time=data_expression(at(body).time_stamp());
    2737             :         /* put the time operator around the first action or process */
    2738         267 :         body1=wraptime(body1,time,freevars);
    2739         267 :         if (v==first)
    2740             :         {
    2741         202 :           return body1;
    2742             :         }
    2743             : 
    2744             :         /* make a new process, containing this process */
    2745             :         const process_identifier newproc=newprocess(freevars,body1,pCRL,
    2746          65 :                                          canterminatebody(body1),
    2747         195 :                                          containstimebody(body1));
    2748          65 :         assert(check_valid_process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum)));
    2749          65 :         return process_instance_assignment(newproc,parameters_to_assignment_list(objectIndex(newproc).parameters,variables_bound_in_sum));
    2750             :       }
    2751             : 
    2752        1738 :       if (is_process_instance(body))
    2753             :       {
    2754           0 :         assert(0);
    2755             :         // return body;
    2756             :         return transform_process_instance_to_process_instance_assignment(atermpp::down_cast<process_instance>(body));
    2757             :       }
    2758             : 
    2759        1738 :       if (is_process_instance_assignment(body))
    2760             :       {
    2761             :         // return transform_process_assignment_to_process(body);
    2762        1225 :         return body;
    2763             :       }
    2764             : 
    2765             : 
    2766         513 :       if (is_tau(body))
    2767             :       {
    2768          77 :         if (v==first)
    2769             :         {
    2770          65 :           return tau();
    2771             :         }
    2772          12 :         assert(check_valid_process_instance_assignment(tau_process,assignment_list()));
    2773          12 :         return process_instance_assignment(tau_process,assignment_list());
    2774             :       }
    2775             : 
    2776         436 :       if (is_delta(body))
    2777             :       {
    2778         436 :         if (v==first)
    2779             :         {
    2780         168 :           return body;
    2781             :         }
    2782         268 :         assert(check_valid_process_instance_assignment(delta_process,assignment_list()));
    2783         268 :         return process_instance_assignment(delta_process,assignment_list());
    2784             :       }
    2785             : 
    2786           0 :       throw mcrl2::runtime_error("unexpected process format in bodytovarheadGNF " + process::pp(body) +".");
    2787             :       return process_expression();
    2788             :     }
    2789             : 
    2790         674 :     void procstovarheadGNF(const std::vector < process_identifier>& procs)
    2791             :     {
    2792             :       /* transform the processes in procs into newprocs */
    2793        1915 :       for (const process_identifier& i: procs)
    2794             :       {
    2795        1241 :         objectdatatype& object=objectIndex(i);
    2796             : 
    2797             :         // The intermediate variable result is needed here
    2798             :         // because objectdata can be realloced as a side
    2799             :         // effect of bodytovarheadGNF.
    2800             : 
    2801        2482 :         std::set<variable> variables_bound_in_sum;
    2802             :         const process_expression result=
    2803             :           bodytovarheadGNF(
    2804             :             object.processbody,
    2805             :             alt_state,
    2806             :             object.parameters,
    2807             :             first,
    2808        2482 :             variables_bound_in_sum);
    2809        1241 :         object.processbody=result;
    2810             :       }
    2811         674 :     }
    2812             : 
    2813             :     /**************** towards real GREIBACH normal form **************/
    2814             : 
    2815             :     typedef enum {terminating,infinite} terminationstatus;
    2816             : 
    2817        4012 :     process_expression putbehind(const process_expression& body1, const process_expression& body2)
    2818             :     {
    2819        4012 :       if (is_choice(body1))
    2820             :       {
    2821         706 :         return choice(
    2822         706 :                  putbehind(choice(body1).left(),body2),
    2823        1059 :                  putbehind(choice(body1).right(),body2));
    2824             :       }
    2825             : 
    2826        3659 :       if (is_seq(body1))
    2827             :       {
    2828         324 :         return seq(seq(body1).left(), putbehind(seq(body1).right(),body2));
    2829             :       }
    2830             : 
    2831        3335 :       if (is_if_then(body1))
    2832             :       {
    2833          12 :         return if_then(if_then(body1).condition(),putbehind(if_then(body1).then_case(),body2));
    2834             :       }
    2835             : 
    2836        3323 :       if (is_sum(body1))
    2837             :       {
    2838             :         /* we must take care that no variables in body2 are
    2839             :             inadvertently bound */
    2840         318 :         variable_list sumvars=sum(body1).variables();
    2841             : 
    2842         318 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    2843         159 :         alphaconvertprocess(sumvars,sigma,body2);
    2844         318 :         return sum(sumvars,
    2845         318 :                    putbehind(substitute_pCRLproc(sum(body1).operand(), sigma),
    2846         159 :                              body2));
    2847             :       }
    2848             : 
    2849        3164 :       if (is_stochastic_operator(body1))
    2850             :       {
    2851           9 :         const stochastic_operator& sto=atermpp::down_cast<stochastic_operator>(body1);
    2852          18 :         variable_list stochvars=sto.variables();
    2853             : 
    2854             :         // See explanation at sum operator above.
    2855          18 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    2856           9 :         alphaconvertprocess(stochvars,sigma,body2);
    2857          18 :         return stochastic_operator(
    2858             :                  stochvars,
    2859             :                  sto.distribution(),
    2860          18 :                  putbehind(
    2861          18 :                        substitute_pCRLproc(sto.operand(),sigma),
    2862           9 :                        body2));
    2863             :       }
    2864             : 
    2865             : 
    2866        3155 :       if (is_action(body1))
    2867             :       {
    2868        2098 :         return seq(body1,body2);
    2869             :       }
    2870             : 
    2871        1057 :       if (is_sync(body1))
    2872             :       {
    2873          99 :         return seq(body1,body2);
    2874             :       }
    2875             : 
    2876         958 :       if (is_process_instance_assignment(body1))
    2877             :       {
    2878         696 :         return seq(body1,body2);
    2879             :       }
    2880             : 
    2881         262 :       if (is_delta(body1))
    2882             :       {
    2883          12 :         return body1;
    2884             :       }
    2885             : 
    2886         250 :       if (is_tau(body1))
    2887             :       {
    2888          73 :         return seq(body1,body2);
    2889             :         // throw mcrl2::runtime_error("Expect only multiactions, not a tau.");
    2890             :       }
    2891             : 
    2892         177 :       if (is_at(body1))
    2893             :       {
    2894         177 :         return seq(body1,body2);
    2895             :       }
    2896             : 
    2897           0 :       throw mcrl2::runtime_error("Internal error. Unexpected process format in putbehind " + process::pp(body1) +".");
    2898             :       return process_expression();
    2899             :     }
    2900             : 
    2901             : 
    2902        1392 :     process_expression distribute_condition(
    2903             :       const process_expression& body1,
    2904             :       const data_expression& condition)
    2905             :     {
    2906        1392 :       if (is_choice(body1))
    2907             :       {
    2908         660 :         return choice(
    2909         660 :                  distribute_condition(choice(body1).left(),condition),
    2910         990 :                  distribute_condition(choice(body1).right(),condition));
    2911             :       }
    2912             : 
    2913        1062 :       if (is_seq(body1))
    2914             :       {
    2915         317 :         return if_then(condition,body1);
    2916             :       }
    2917             : 
    2918         745 :       if (is_if_then(body1))
    2919             :       {
    2920        1191 :         return if_then(
    2921         794 :                  lazy::and_(if_then(body1).condition(),condition),
    2922        1191 :                  if_then(body1).then_case());
    2923             :       }
    2924             : 
    2925         348 :       if (is_sum(body1))
    2926             :       {
    2927             :         /* we must take care that no variables in condition are
    2928             :             inadvertently bound */
    2929         132 :         variable_list sumvars=sum(body1).variables();
    2930         132 :         maintain_variables_in_rhs< mutable_map_substitution<> >  sigma;
    2931          66 :         alphaconvert(sumvars,sigma,variable_list(), data_expression_list({ condition }));
    2932         132 :         return sum(
    2933             :                  sumvars,
    2934         132 :                  distribute_condition(
    2935         132 :                    substitute_pCRLproc(sum(body1).operand(),sigma),
    2936          66 :                    condition));
    2937             :       }
    2938             : 
    2939         282 :       if (is_stochastic_operator(body1))
    2940             :       {
    2941             :         /* we must take care that no variables in condition are
    2942             :             inadvertently bound */
    2943         177 :         const stochastic_operator& sto=atermpp::down_cast<stochastic_operator>(body1);
    2944         354 :         variable_list stochvars=sto.variables();
    2945         354 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    2946         177 :         alphaconvert(stochvars,sigma,variable_list(), data_expression_list({ condition }));
    2947         354 :         return stochastic_operator(
    2948             :                  stochvars,
    2949         354 :                  replace_variables_capture_avoiding_alt(
    2950             :                                                sto.distribution(),
    2951             :                                                sigma),
    2952         354 :                  distribute_condition(
    2953         354 :                        substitute_pCRLproc(sto.operand(),sigma),
    2954         177 :                        condition));
    2955             :       }
    2956             : 
    2957         314 :       if (is_at(body1)||
    2958         131 :           is_action(body1)||
    2959          54 :           is_sync(body1)||
    2960          54 :           is_process_instance_assignment(body1)||
    2961         132 :           is_delta(body1)||
    2962           0 :           is_tau(body1))
    2963             :       {
    2964         105 :         return if_then(condition,body1);
    2965             :       }
    2966             : 
    2967           0 :       throw mcrl2::runtime_error("Internal error. Unexpected process format in distribute condition " + process::pp(body1) +".");
    2968             :     }
    2969             :     
    2970             :     /* This process calculates the equivalent of sum sumvars dist stochvars[distribution] body
    2971             :        where the distribution occurs in front. This can only be done under limited circumstances.
    2972             :        Assume we can enumerate the values of sumvars by e1,...,en. Introduce n copies of stochvars,
    2973             :        i.e., stochvars1,...,stochvarsn. The new process becomes 
    2974             : 
    2975             :            dist stochvars1,stochvars2,...,stochvarsn
    2976             :                 [distribution(e1,stochvars1)*distribution(e2,stochvars2)*...*distribution(en,stochvarsn)].
    2977             : 
    2978             :            body(e1,stochvars1)+
    2979             :            body(e2,stochvars2)+
    2980             :            ...
    2981             :            body(en,stochvarsn)
    2982             :     */
    2983             : 
    2984           1 :     process_expression enumerate_distribution_and_sums(
    2985             :                          const variable_list& sumvars, 
    2986             :                          const variable_list& stochvars, 
    2987             :                          const data_expression& distribution,
    2988             :                          const process_expression& body)
    2989             :     {
    2990           1 :       if (options.norewrite)
    2991             :       {
    2992           0 :         throw mcrl2::runtime_error("The use of the rewriter must be allowed to distribute a sum operator over a distribution.");
    2993             :       }
    2994             : 
    2995             : 
    2996           2 :       std::vector < data_expression_vector > data_vector(1,data_expression_vector());
    2997           2 :       for(const variable& v:sumvars) 
    2998             :       {
    2999           2 :         std::vector < data_expression_vector > new_data_vector;
    3000             : 
    3001           1 :         if (!data.is_certainly_finite(v.sort()))
    3002             :         {
    3003           0 :           throw mcrl2::runtime_error("Cannot distribute a sum variable of non finite sort " + pp(v.sort()) + " over a distribution, which is required for linearisation.");
    3004             :         }
    3005             : 
    3006           3 :         for(const data_expression& d: enumerate_expressions(v.sort(),data,rewr))
    3007             :         {
    3008           4 :           for(const data_expression_vector& dv: data_vector)
    3009             :           {
    3010           4 :             data_expression_vector new_dv=dv;
    3011           2 :             new_dv.push_back(d);
    3012           2 :             new_data_vector.push_back(new_dv);
    3013             :           }
    3014             :            
    3015             :         }
    3016           1 :         data_vector.swap(new_data_vector);
    3017             :         
    3018             :       } 
    3019           1 :       assert(!data_vector.empty());
    3020             :       
    3021           2 :       process_expression resulting_body;
    3022           2 :       data_expression resulting_distribution;
    3023           2 :       variable_list resulting_stochastic_variables;
    3024           1 :       bool result_defined=false;
    3025           3 :       for(const data_expression_vector& d: data_vector)
    3026             :       {
    3027           4 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3028           4 :         variable_list vl = stochvars;
    3029           2 :         alphaconvert(vl,sigma,stochvars,data_expression_list());
    3030           2 :         data_expression_vector::const_iterator i=d.begin();
    3031           4 :         for(const variable& v: sumvars)
    3032             :         {
    3033           2 :           sigma[v] = *i;
    3034           2 :           ++i;
    3035             :         }
    3036           4 :         const process_expression d1=substitute_pCRLproc(body,sigma);
    3037           4 :         const data_expression new_distribution=replace_variables_capture_avoiding_alt(distribution, sigma);
    3038             : 
    3039           2 :         if (result_defined)
    3040             :         {
    3041           1 :           resulting_body=choice(resulting_body, d1);
    3042           1 :           resulting_distribution=data::sort_real::times(resulting_distribution,new_distribution);
    3043           1 :           resulting_stochastic_variables=resulting_stochastic_variables + vl;
    3044             :         }
    3045             :         else
    3046             :         {
    3047           1 :           resulting_body=d1;
    3048           1 :           resulting_distribution=new_distribution;
    3049           1 :           resulting_stochastic_variables=vl;
    3050           1 :           result_defined=true;
    3051             :         }
    3052             :       } 
    3053             :       /* Put the distribution in front. */
    3054             : 
    3055           2 :       return stochastic_operator(resulting_stochastic_variables, resulting_distribution, resulting_body);
    3056             :     }
    3057             : 
    3058           1 :     process_expression distribute_sum_over_a_stochastic_operator(
    3059             :                          const variable_list& sumvars, 
    3060             :                          const variable_list& stochastic_variables, 
    3061             :                          const data_expression& distribution,
    3062             :                          const process_expression& body)
    3063             :     {
    3064           3 :       if (is_sum(body)||
    3065           2 :           is_choice(body)||
    3066           1 :           is_seq(body)||
    3067           0 :           is_if_then(body)||
    3068           0 :           is_sync(body)||
    3069           0 :           is_action(body)||
    3070           0 :           is_tau(body)||
    3071           0 :           is_at(body)||
    3072           1 :           is_process_instance_assignment(body)||
    3073           0 :           isDeltaAtZero(body))
    3074             :       {
    3075           1 :         return enumerate_distribution_and_sums(sumvars,stochastic_variables,distribution,body);
    3076             :       }
    3077             : 
    3078           0 :       if (is_delta(body)||
    3079           0 :           is_tau(body))
    3080             :       {
    3081           0 :         return body;
    3082             :       }
    3083             : 
    3084           0 :       if (is_stochastic_operator(body))
    3085             :       {
    3086           0 :         const stochastic_operator& sto=atermpp::down_cast<stochastic_operator>(body);
    3087           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3088           0 :         variable_list inner_stoch_vars=sto.variables();
    3089           0 :         alphaconvert(inner_stoch_vars,sigma,sumvars,data_expression_list());
    3090           0 :         const process_expression new_body=substitute_pCRLproc(sto.operand(), sigma);
    3091           0 :         const data_expression new_distribution=replace_variables_capture_avoiding_alt(sto.distribution(), sigma);
    3092             :         return distribute_sum_over_a_stochastic_operator(sumvars, 
    3093           0 :                                                          stochastic_variables + inner_stoch_vars, 
    3094           0 :                                                          data::sort_real::times(distribution,new_distribution), new_body);
    3095             :       }
    3096             : 
    3097           0 :       throw mcrl2::runtime_error("Internal error. Unexpected process format in distribute_sum " + process::pp(body) +".");
    3098             :       return process_expression();
    3099             :     }
    3100             : 
    3101         728 :     process_expression distribute_sum(
    3102             :       const variable_list& sumvars,
    3103             :       const process_expression& body1)
    3104             :     {
    3105         728 :       if (is_choice(body1))
    3106             :       {
    3107         178 :         return choice(
    3108         178 :                  distribute_sum(sumvars,choice(body1).left()),
    3109         267 :                  distribute_sum(sumvars,choice(body1).right()));
    3110             :       }
    3111             : 
    3112        1579 :       if (is_seq(body1)||
    3113         499 :           is_if_then(body1)||
    3114         390 :           is_sync(body1)||
    3115         266 :           is_action(body1)||
    3116         148 :           is_tau(body1)||
    3117         135 :           is_at(body1)||
    3118         761 :           is_process_instance_assignment(body1)||
    3119          61 :           isDeltaAtZero(body1))
    3120             :       {
    3121         578 :         return sum(sumvars,body1);
    3122             :       }
    3123             : 
    3124          61 :       if (is_sum(body1))
    3125             :       {
    3126         120 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3127         120 :         variable_list inner_sumvars=sum(body1).variables();
    3128          60 :         alphaconvert(inner_sumvars,sigma,sumvars,data_expression_list());
    3129         120 :         const process_expression new_body1=substitute_pCRLproc(sum(body1).operand(), sigma);
    3130          60 :         return sum(sumvars+inner_sumvars,new_body1);
    3131             :       }
    3132             : 
    3133           1 :       if (is_stochastic_operator(body1))
    3134             :       {
    3135           1 :         const stochastic_operator& sto=atermpp::down_cast<stochastic_operator>(body1);
    3136           2 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3137           2 :         variable_list inner_stoch_vars=sto.variables();
    3138           1 :         alphaconvert(inner_stoch_vars,sigma,sumvars,data_expression_list());
    3139           2 :         const process_expression new_body1=substitute_pCRLproc(sto.operand(), sigma);
    3140           2 :         const data_expression new_distribution=replace_variables_capture_avoiding_alt(sto.distribution(), sigma);
    3141           1 :         return distribute_sum_over_a_stochastic_operator(sumvars, inner_stoch_vars, new_distribution, new_body1);
    3142             :       }
    3143             : 
    3144           0 :       if (is_delta(body1)||
    3145           0 :           is_tau(body1))
    3146             :       {
    3147           0 :         return body1;
    3148             :       }
    3149             : 
    3150           0 :       throw mcrl2::runtime_error("Internal error. Unexpected process format in distribute_sum " + process::pp(body1) +".");
    3151             :       return process_expression();
    3152             :     }
    3153             : 
    3154        2109 :     int match_sequence(
    3155             :       const std::vector < process_instance_assignment >& s1,
    3156             :       const std::vector < process_instance_assignment >& s2,
    3157             :       const bool regular2)
    3158             :     {
    3159             :       /* s1 and s2 are sequences of typed variables of
    3160             :          the form Process(ProcVarId("P2",[SortId("Bit"),
    3161             :          SortId("Bit")]),[OpId("b1",SortId("Bit")),OpId("b1",SortId("Bit"))]).
    3162             :          This function yields true if the names and types of
    3163             :          the processes in s1 and s2 match. */
    3164             : 
    3165        2109 :       std::vector < process_instance_assignment >::const_iterator i2=s2.begin();
    3166        2299 :       for (std::vector < process_instance_assignment >::const_iterator i1=s1.begin();
    3167        2299 :            i1!=s1.end(); ++i1,++i2)
    3168             :       {
    3169        2216 :         if (i2==s2.end())
    3170             :         {
    3171        2030 :           return false;
    3172             :         }
    3173        2212 :         if (regular2)
    3174             :         {
    3175          54 :           if (i1->identifier()!=i2->identifier())
    3176             :           {
    3177          32 :             return false;
    3178             :           }
    3179             :         }
    3180             :         else
    3181             :         {
    3182        2158 :           if (*i1!=*i2)
    3183             :           {
    3184        1990 :             return false;
    3185             :           }
    3186             :         }
    3187             :       }
    3188          83 :       if (i2!=s2.end())
    3189             :       {
    3190           0 :         return false;
    3191             :       }
    3192          83 :       return true;
    3193             :     }
    3194             : 
    3195         653 :     bool exists_variable_for_sequence(
    3196             :       const std::vector < process_instance_assignment >& process_names,
    3197             :       process_identifier& result)
    3198             :     {
    3199         653 :       std::vector < std::vector < process_instance_assignment > >::const_iterator rwalker=representedprocesses.begin();
    3200        2679 :       for (std::vector < process_identifier >::const_iterator walker=seq_varnames.begin();
    3201        2679 :            walker!=seq_varnames.end(); ++walker,++rwalker)
    3202             :       {
    3203        2109 :         assert(rwalker!=representedprocesses.end());
    3204        4135 :         const process_identifier process=*walker;
    3205        2109 :         if (match_sequence(process_names,*rwalker,options.lin_method==lmRegular2))
    3206             :         {
    3207          83 :           result=process;
    3208          83 :           return true;
    3209             :         }
    3210             :       }
    3211         570 :       assert(rwalker==representedprocesses.end());
    3212         570 :       return false;
    3213             :     }
    3214             : 
    3215        4171 :     void extract_names(
    3216             :       const process_expression& sequence,
    3217             :       std::vector < process_instance_assignment >& result)
    3218             :     {
    3219        4171 :       if (is_action(sequence)||is_process_instance_assignment(sequence))
    3220             :       {
    3221        3460 :         result.push_back(atermpp::down_cast<process_instance_assignment>(sequence));
    3222        3460 :         return;
    3223             :       }
    3224             : 
    3225         711 :       if (is_stochastic_operator(sequence))
    3226             :       {
    3227           0 :         const stochastic_operator& sto=atermpp::down_cast<stochastic_operator>(sequence);
    3228           0 :         extract_names(sto.operand(),result);
    3229           0 :         return;
    3230             :       }
    3231             : 
    3232         711 :       if (is_seq(sequence))
    3233             :       {
    3234         711 :         const process_expression first=seq(sequence).left();
    3235         711 :         if (is_process_instance_assignment(first))
    3236             :         {
    3237         711 :           result.push_back(atermpp::down_cast<process_instance_assignment>(first));
    3238         711 :           objectdatatype& object=objectIndex(atermpp::down_cast<process_instance_assignment>(first).identifier());
    3239         711 :           if (object.canterminate)
    3240             :           {
    3241         711 :             extract_names(seq(sequence).right(),result);
    3242             :           }
    3243         711 :           return;
    3244             :         }
    3245             :       }
    3246             : 
    3247           0 :       throw mcrl2::runtime_error("Internal error. Expected sequence of process names (1) " + process::pp(sequence) + ".");
    3248             :     }
    3249             : 
    3250          41 :     variable_list parscollect(const process_expression& oldbody, process_expression& newbody)
    3251             :     {
    3252             :       /* we expect that oldbody is a sequence of process instances */
    3253             : 
    3254          41 :       if (is_process_instance_assignment(oldbody))
    3255             :       {
    3256          40 :         const process_identifier procId=process_instance_assignment(oldbody).identifier();
    3257          40 :         const variable_list parameters=objectIndex(procId).parameters;
    3258          20 :         assert(check_valid_process_instance_assignment(procId,data::assignment_list()));
    3259          20 :         newbody=process_instance_assignment(procId,data::assignment_list());
    3260          20 :         return parameters;
    3261             :       }
    3262             : 
    3263          21 :       if (is_seq(oldbody))
    3264             :       {
    3265          21 :         const process_expression first=seq(oldbody).left();
    3266          21 :         if (is_process_instance_assignment(first))
    3267             :         {
    3268          21 :           objectdatatype& object=objectIndex(process_instance_assignment(first).identifier());
    3269          21 :           if (object.canterminate)
    3270             :           {
    3271          42 :             const process_identifier procId=process_instance_assignment(first).identifier();
    3272          42 :             const variable_list pars=parscollect(seq(oldbody).right(),newbody);
    3273          42 :             variable_list pars1, pars2;
    3274             : 
    3275          42 :             const variable_list new_pars=construct_renaming(pars,objectIndex(procId).parameters,pars1,pars2,false);
    3276          42 :             assignment_vector new_assignment;
    3277          21 :             for(variable_list::const_iterator i=pars2.begin(), j=new_pars.begin(); i!=pars2.end(); ++i,++j)
    3278             :             {
    3279           0 :               assert(j!=new_pars.end());
    3280           0 :               new_assignment.push_back(assignment(*i,*j));
    3281             :             }
    3282          21 :             assert(check_valid_process_instance_assignment(procId,assignment_list(new_assignment.begin(),new_assignment.end())));
    3283          21 :             newbody=seq(process_instance_assignment(procId,assignment_list(new_assignment.begin(),new_assignment.end())),newbody);
    3284          21 :             return pars1+pars;
    3285             :           }
    3286             :           else
    3287             :           {
    3288           0 :             return parscollect(first,newbody);
    3289             :           }
    3290             :         }
    3291             :       }
    3292             : 
    3293           0 :       throw mcrl2::runtime_error("Internal error. Expected a sequence of process names (2) " + process::pp(oldbody) +".");
    3294             :       return variable_list();
    3295             :     }
    3296             : 
    3297        1250 :     assignment_list argscollect_regular(
    3298             :                          const process_expression& t,
    3299             :                          const variable_list& vl,
    3300             :                          const std::set<variable>& variables_bound_in_sum)
    3301             :     {
    3302        2500 :       assignment_vector result;
    3303        2422 :       for(variable_list::const_iterator i=vl.begin(); i!=vl.end(); ++i)
    3304             :       {
    3305        1172 :         if (variables_bound_in_sum.count(*i)>0 && occursinpCRLterm(*i,t,false))
    3306             :         {
    3307         446 :           result.push_back(assignment(*i,*i)); // Here an identity assignment is used, as it is possible
    3308             :                                                // that the *i at the lhs is not the same variable as *i at the rhs.
    3309             :         }
    3310             :       }
    3311        2500 :       return assignment_list(result.begin(),result.end());
    3312             :     }
    3313             : 
    3314          86 :     assignment_list argscollect_regular2(const process_expression& t, variable_list& vl)
    3315             :     {
    3316          86 :       if (is_process_instance_assignment(t))
    3317             :       {
    3318         114 :         const process_instance_assignment p(t);
    3319          57 :         objectdatatype& object=objectIndex(p.identifier());
    3320             : 
    3321         114 :         const variable_list pars=object.parameters; // These are the old parameters of the process.
    3322          57 :         assert(pars.size()<=vl.size());
    3323             : 
    3324         114 :         std::map<variable,data_expression>sigma;
    3325          64 :         for(assignment_list::const_iterator i=p.assignments().begin();
    3326          64 :               i!=p.assignments().end(); ++i)
    3327             :         {
    3328           7 :           sigma[i->lhs()]=i->rhs();
    3329             :         }
    3330             : 
    3331         114 :         assignment_list result;
    3332          68 :         for(variable_list::const_iterator i=pars.begin(); i!=pars.end(); ++i, vl.pop_front())
    3333             :         {
    3334          11 :           assert(!vl.empty());
    3335          22 :           const data_expression new_rhs=make_map_substitution(sigma)(*i);
    3336          11 :           result.push_front(assignment(vl.front(),new_rhs)); // Identity assignments are stored as lhs and rhs may
    3337             :                                                              // refer to different variables.
    3338             :         }
    3339          57 :         return reverse(result);
    3340             :       }
    3341             : 
    3342          29 :       if (is_seq(t))
    3343             :       {
    3344          58 :         const process_instance_assignment firstproc=atermpp::down_cast<process_instance_assignment>(seq(t).left());
    3345          29 :         objectdatatype& object=objectIndex(firstproc.identifier());
    3346          58 :         const assignment_list first_assignment=argscollect_regular2(firstproc,vl);
    3347          29 :         if (object.canterminate)
    3348             :         {
    3349          29 :           return first_assignment + argscollect_regular2(seq(t).right(),vl);
    3350             :         }
    3351           0 :         return first_assignment;
    3352             :       }
    3353             : 
    3354           0 :       throw mcrl2::runtime_error("Internal error. Expected a sequence of process names (3) " + process::pp(t) +".");
    3355             :     }
    3356             : 
    3357        4171 :     process_expression cut_off_unreachable_tail(const process_expression& t)
    3358             :     {
    3359        4171 :       if (is_process_instance_assignment(t)||is_delta(t)||is_action(t)||is_tau(t)||is_sync(t))
    3360             :       {
    3361        3460 :         return t;
    3362             :       }
    3363             : 
    3364         711 :       if (is_stochastic_operator(t))
    3365             :       {
    3366           0 :         const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(t);
    3367           0 :         return stochastic_operator(sto.variables(),sto.distribution(), cut_off_unreachable_tail(sto.operand()));
    3368             :       }
    3369             : 
    3370         711 :       if (is_seq(t))
    3371             :       {
    3372        1422 :         const process_expression firstproc=seq(t).left();
    3373         711 :         objectdatatype& object=objectIndex(process_instance_assignment(firstproc).identifier());
    3374         711 :         if (object.canterminate)
    3375             :         {
    3376         711 :           return seq(firstproc,cut_off_unreachable_tail(seq(t).right()));
    3377             :         }
    3378           0 :         return firstproc;
    3379             :       }
    3380             : 
    3381           0 :       throw mcrl2::runtime_error("Internal error. Expected a sequence of process names (4) " + process::pp(t) +".");
    3382             :       return process_expression();
    3383             :     }
    3384             : 
    3385        3472 :     process_expression create_regular_invocation(
    3386             :       process_expression sequence,
    3387             :       std::vector <process_identifier>& todo,
    3388             :       const variable_list& freevars,
    3389             :       const std::set<variable>& variables_bound_in_sum)
    3390             :     {
    3391        6944 :       process_identifier new_process;
    3392             : 
    3393             :       /* Sequence consists of a sequence of process references,
    3394             :          concatenated with the sequential composition operator, which may be preceded by
    3395             :          a stochastic operator.  */
    3396        3472 :       if (is_stochastic_operator(sequence))
    3397             :       {
    3398             :         /* Leave the stochastic operators in place */
    3399          12 :         const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(sequence);
    3400          24 :         std::set<variable> variables_bound_in_sum_new=variables_bound_in_sum;
    3401          12 :         variables_bound_in_sum_new.insert(sto.variables().begin(),sto.variables().end());
    3402          24 :         return stochastic_operator(sto.variables(),
    3403             :                                    sto.distribution(), 
    3404          36 :                                    create_regular_invocation(sto.operand(),todo,freevars+sto.variables(),variables_bound_in_sum_new));
    3405             :       }
    3406             : 
    3407        3460 :       sequence=cut_off_unreachable_tail(sequence);
    3408        3460 :       sequence=pCRLrewrite(sequence);
    3409        6920 :       std::vector < process_instance_assignment > process_names;
    3410        3460 :       extract_names(sequence,process_names);
    3411        3460 :       assert(!process_names.empty());
    3412             : 
    3413        3460 :       if (process_names.size()==1)
    3414             :       {
    3415             :         /* length of list equals 1 */
    3416        2807 :         if (is_process_instance_assignment(sequence))
    3417             :         {
    3418        2807 :           return sequence;
    3419             :         }
    3420           0 :         if (is_seq(sequence))
    3421             :         {
    3422           0 :           return seq(sequence).left();
    3423             :         }
    3424           0 :         throw mcrl2::runtime_error("Internal error. Expected a sequence of process names " + process::pp(sequence) +".");
    3425             :       }
    3426             :       /* There is more than one process name in the sequence,
    3427             :          so, we must replace them by a single name */
    3428             : 
    3429             :       /* We first start out by searching whether
    3430             :          there is already a variable with a matching sequence
    3431             :          of variables */
    3432         653 :       if (!exists_variable_for_sequence(process_names,new_process))
    3433             :       {
    3434             :         /* There does not exist an appropriate variable,
    3435             :            so, make it and return its index in n */
    3436        1140 :         process_expression newbody;
    3437         570 :         if (options.lin_method==lmRegular2)
    3438             :         {
    3439          40 :           variable_list pars=parscollect(sequence,newbody);
    3440          40 :           new_process=newprocess(pars,newbody,pCRL,
    3441          20 :                                  canterminatebody(newbody),
    3442          20 :                                  containstimebody(newbody));
    3443          20 :           representedprocesses.push_back(process_names);
    3444             :         }
    3445             :         else
    3446             :         {
    3447        1100 :           new_process=newprocess(freevars,sequence,pCRL,
    3448        1100 :                                  canterminatebody(sequence),containstimebody(sequence));
    3449         550 :           representedprocesses.push_back(process_names);
    3450             :         }
    3451         570 :         seq_varnames.push_back(new_process);
    3452         570 :         todo.push_back(new_process);
    3453             :       }
    3454             :       /* now we must construct arguments */
    3455        1306 :       variable_list parameters=objectIndex(new_process).parameters;
    3456         653 :       if (options.lin_method==lmRegular2)
    3457             :       {
    3458          56 :         const assignment_list args=argscollect_regular2(sequence,parameters);
    3459          28 :         assert(check_valid_process_instance_assignment(new_process,args));
    3460          56 :         const process_expression p=process_instance_assignment(new_process,args);
    3461          28 :         return p;
    3462             :       }
    3463             :       else
    3464             :       {
    3465         625 :         assert(check_valid_process_instance_assignment(new_process,argscollect_regular(sequence,parameters,variables_bound_in_sum)));
    3466         625 :         return process_instance_assignment(new_process,argscollect_regular(sequence,parameters,variables_bound_in_sum));
    3467             :       }
    3468             :     }
    3469             : 
    3470        6619 :     process_expression to_regular_form(
    3471             :       const process_expression& t,
    3472             :       std::vector <process_identifier>& todo,
    3473             :       const variable_list& freevars,
    3474             :       const std::set<variable>& variables_bound_in_sum)
    3475             :     /* t has the form of the sum, and condition over actions
    3476             :        each followed by a sequence of variables. We replace
    3477             :        this variable by a single one, putting the new variable
    3478             :        on the todo list, to be transformed to regular form also. */
    3479             :     {
    3480        6619 :       if (is_choice(t))
    3481             :       {
    3482        2288 :         const process_expression t1=to_regular_form(choice(t).left(),todo,freevars,variables_bound_in_sum);
    3483        2288 :         const process_expression t2=to_regular_form(choice(t).right(),todo,freevars,variables_bound_in_sum);
    3484        1144 :         return choice(t1,t2);
    3485             :       }
    3486             : 
    3487        5475 :       if (is_seq(t))
    3488             :       {
    3489        6920 :         const process_expression firstact=seq(t).left();
    3490        3460 :         assert(is_at(firstact)||is_tau(firstact)||is_action(firstact)||is_sync(firstact));
    3491             :         /* the sequence of variables in
    3492             :                    the second argument must be replaced */
    3493        3460 :         return seq(firstact,create_regular_invocation(seq(t).right(),todo,freevars,variables_bound_in_sum));
    3494             :       }
    3495             : 
    3496        2015 :       if (is_if_then(t))
    3497             :       {
    3498         500 :         return if_then(if_then(t).condition(),to_regular_form(if_then(t).then_case(),todo,freevars,variables_bound_in_sum));
    3499             :       }
    3500             : 
    3501        1515 :       if (is_sum(t))
    3502             :       {
    3503         976 :         variable_list sumvars=sum(t).variables();
    3504             : 
    3505         976 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3506         488 :         alphaconvert(sumvars,sigma,freevars,data_expression_list());
    3507         976 :         const process_expression body=substitute_pCRLproc(sum(t).operand(), sigma);
    3508             : 
    3509         976 :         std::set<variable> variables_bound_in_sum1=variables_bound_in_sum;
    3510         488 :         variables_bound_in_sum1.insert(sumvars.begin(),sumvars.end());
    3511         976 :         return sum(sumvars,
    3512         976 :                    to_regular_form(
    3513             :                      body,
    3514             :                      todo,
    3515         976 :                      sumvars+freevars,
    3516         488 :                      variables_bound_in_sum1));
    3517             :       }
    3518             : 
    3519        1027 :       if (is_stochastic_operator(t))
    3520             :       {
    3521         131 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(t);
    3522         262 :         variable_list sumvars=sto.variables();
    3523             : 
    3524         262 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3525         131 :         alphaconvert(sumvars,sigma,freevars,data_expression_list());
    3526             :         const data_expression distribution=replace_variables_capture_avoiding_alt(
    3527             :                                                sto.distribution(),
    3528         262 :                                                sigma);
    3529         262 :         const process_expression body=substitute_pCRLproc(sto.operand(),sigma);
    3530             : 
    3531         262 :         std::set<variable> variables_bound_in_sum1=variables_bound_in_sum;
    3532         131 :         variables_bound_in_sum1.insert(sumvars.begin(),sumvars.end());
    3533         262 :         return stochastic_operator(
    3534             :                    sumvars,
    3535             :                    distribution,
    3536         262 :                    to_regular_form(
    3537             :                      body,
    3538             :                      todo,
    3539         262 :                      sumvars+freevars,
    3540         131 :                      variables_bound_in_sum1));
    3541             :       }
    3542             : 
    3543         896 :       if (is_sync(t)||is_action(t)||is_delta(t)||is_tau(t)||is_at(t))
    3544             :       {
    3545         896 :         return t;
    3546             :       }
    3547             : 
    3548           0 :       throw mcrl2::runtime_error("to regular form expects GNF " + process::pp(t) +".");
    3549             :       return process_expression();
    3550             :     }
    3551             : 
    3552         255 :     process_expression distributeTime(
    3553             :       const process_expression& body,
    3554             :       const data_expression& time,
    3555             :       const variable_list& freevars,
    3556             :       data_expression& timecondition)
    3557             :     {
    3558         255 :       if (is_choice(body))
    3559             :       {
    3560           0 :         return choice(
    3561           0 :                  distributeTime(choice(body).left(),time,freevars,timecondition),
    3562           0 :                  distributeTime(choice(body).right(),time,freevars,timecondition));
    3563             :       }
    3564             : 
    3565         255 :       if (is_sum(body))
    3566             :       {
    3567           0 :         variable_list sumvars=sum(body).variables();
    3568           0 :         process_expression body1=sum(body).operand();
    3569           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3570           0 :         alphaconvert(sumvars,sigma,freevars,data_expression_list());
    3571           0 :         body1=substitute_pCRLproc(body1, sigma);
    3572           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma_aux(sigma);
    3573           0 :         const data_expression time1=replace_variables_capture_avoiding_alt(time,sigma_aux);
    3574           0 :         body1=distributeTime(body1,time1,sumvars+freevars,timecondition);
    3575           0 :         return sum(sumvars,body1);
    3576             :       }
    3577             : 
    3578         255 :       if (is_stochastic_operator(body))
    3579             :       {
    3580           0 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(body);
    3581           0 :         variable_list sumvars=sto.variables();
    3582           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3583           0 :         alphaconvert(sumvars,sigma,freevars,data_expression_list());
    3584           0 :         process_expression new_body=substitute_pCRLproc(sto.operand(), sigma);
    3585           0 :         data_expression new_distribution=/*data::*/replace_variables_capture_avoiding_alt(sto.distribution(), sigma);
    3586           0 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma_aux(sigma);
    3587           0 :         const data_expression time1=/*data::*/replace_variables_capture_avoiding_alt(time,sigma_aux);
    3588           0 :         new_body=distributeTime(new_body,time1,sumvars+freevars,timecondition);
    3589           0 :         return stochastic_operator(sumvars,new_distribution,new_body);
    3590             :       }
    3591             : 
    3592         255 :       if (is_if_then(body))
    3593             :       {
    3594           0 :         data_expression timecondition=sort_bool::true_();
    3595             :         process_expression body1=distributeTime(
    3596           0 :                                    if_then(body).then_case(),
    3597             :                                    time,
    3598             :                                    freevars,
    3599           0 :                                    timecondition);
    3600             : 
    3601           0 :         return if_then(
    3602           0 :                  lazy::and_(data_expression(if_then(body).condition()),timecondition),
    3603           0 :                  body1);
    3604             :       }
    3605             : 
    3606         255 :       if (is_seq(body))
    3607             :       {
    3608           0 :         return seq(
    3609           0 :                  distributeTime(seq(body).left(), time,freevars,timecondition),
    3610           0 :                  seq(body).right());
    3611             :       }
    3612             : 
    3613         255 :       if (is_at(body))
    3614             :       {
    3615             :         /* make a new process */
    3616           0 :         timecondition=equal_to(time,data_expression(at(body).time_stamp()));
    3617           0 :         return body;
    3618             :       }
    3619             : 
    3620         735 :       if ((is_sync(body))||
    3621         322 :           (is_action(body))||
    3622         449 :           (is_tau(body))||
    3623          97 :           (is_delta(body)))
    3624             :       {
    3625         255 :         return at(body,time);
    3626             :       }
    3627             : 
    3628           0 :       throw mcrl2::runtime_error("Internal error: expect a pCRL process in distributeTime " + process::pp(body) +".");
    3629             :       return process_expression();
    3630             :     }
    3631             : 
    3632       12643 :     process_expression procstorealGNFbody(
    3633             :       const process_expression& body,
    3634             :       variableposition v,
    3635             :       std::vector <process_identifier>& todo,
    3636             :       const bool regular,
    3637             :       processstatustype mode,
    3638             :       const variable_list& freevars,
    3639             :       const std::set <variable>& variables_bound_in_sum)
    3640             :     /* This process delivers the transformation of body
    3641             :        to GNF with actions as a head symbol, or it
    3642             :        delivers NULL if body is not a pCRL process.
    3643             :        If regular=1, then an attempt is made to obtain a
    3644             :        GNF where one action is always followed by a
    3645             :        variable. */
    3646             :     {
    3647       12643 :       if (is_at(body))
    3648             :       {
    3649         510 :         data_expression timecondition=sort_bool::true_();
    3650             :         process_expression body1=procstorealGNFbody(
    3651         510 :                                    at(body).operand(),
    3652             :                                    first,
    3653             :                                    todo,
    3654             :                                    regular,
    3655             :                                    mode,
    3656             :                                    freevars,
    3657         765 :                                    variables_bound_in_sum);
    3658             :         return distributeTime(
    3659             :                  body1,
    3660         510 :                  at(body).time_stamp(),
    3661             :                  freevars,
    3662         255 :                  timecondition);
    3663             :       }
    3664             : 
    3665       12388 :       if (is_choice(body))
    3666             :       {
    3667        1494 :         const process_expression body1=procstorealGNFbody(choice(body).left(),first,todo,
    3668        2241 :                                        regular,mode,freevars,variables_bound_in_sum);
    3669        1494 :         const process_expression body2=procstorealGNFbody(choice(body).right(),first,todo,
    3670        2241 :                                        regular,mode,freevars,variables_bound_in_sum);
    3671         747 :         return choice(body1,body2);
    3672             :       }
    3673             : 
    3674       11641 :       if (is_seq(body))
    3675             :       {
    3676        5604 :         const process_expression body1=procstorealGNFbody(seq(body).left(),v,
    3677        8406 :                                        todo,regular,mode,freevars,variables_bound_in_sum);
    3678        5604 :         const process_expression body2=procstorealGNFbody(seq(body).right(),later,
    3679        8406 :                                        todo,regular,mode,freevars,variables_bound_in_sum);
    3680        5604 :         process_expression t3=putbehind(body1,body2);
    3681        2802 :         if ((regular) && (v==first))
    3682             :         {
    3683             :           /* We must transform t3 to regular form */
    3684        2092 :           t3=to_regular_form(t3,todo,freevars,variables_bound_in_sum);
    3685             :         }
    3686        2802 :         return t3;
    3687             :       }
    3688             : 
    3689        8839 :       if (is_if_then(body))
    3690             :       {
    3691             :         const process_expression r=distribute_condition(
    3692         978 :                                      procstorealGNFbody(if_then(body).then_case(),first,
    3693             :                                          todo,regular,mode,freevars,variables_bound_in_sum),
    3694        1956 :                                      if_then(body).condition());
    3695         489 :         return r;
    3696             :       }
    3697             : 
    3698        8350 :       if (is_sum(body))
    3699             :       {
    3700        1100 :         const variable_list sumvars=sum(body).variables();
    3701        1100 :         std::set<variable> variables_bound_in_sum1=variables_bound_in_sum;
    3702         550 :         variables_bound_in_sum1.insert(sumvars.begin(),sumvars.end());
    3703             :         return distribute_sum(sumvars,
    3704        1100 :                               procstorealGNFbody(sum(body).operand(),first,
    3705        1650 :                                   todo,regular,mode,sumvars+freevars,variables_bound_in_sum1));
    3706             :       }
    3707             : 
    3708        7800 :       if (is_stochastic_operator(body))
    3709             :       {
    3710          92 :         const stochastic_operator& sto=down_cast<const stochastic_operator>(body);
    3711          92 :         const variable_list& sumvars=sto.variables();
    3712         184 :         std::set<variable> variables_bound_in_sum1=variables_bound_in_sum;
    3713          92 :         variables_bound_in_sum1.insert(sumvars.begin(),sumvars.end());
    3714         184 :         return stochastic_operator(
    3715             :                               sumvars,
    3716             :                               sto.distribution(),
    3717         184 :                               procstorealGNFbody(sto.operand(),v,
    3718         276 :                                   todo,regular,mode,sumvars+freevars,variables_bound_in_sum1));
    3719             :       }
    3720             : 
    3721        7708 :       if (is_action(body))
    3722             :       {
    3723        1834 :         return body;
    3724             :       }
    3725             : 
    3726        5874 :       if (is_sync(body))
    3727             :       {
    3728         117 :         return body;
    3729             :       }
    3730             : 
    3731        5757 :       if (is_process_instance_assignment(body))
    3732             :       {
    3733        9438 :         process_identifier t=process_instance_assignment(body).identifier();
    3734             : 
    3735        4719 :         if (v==later)
    3736             :         {
    3737        3395 :           if (regular)
    3738             :           {
    3739        2921 :             mode=mCRL;
    3740             :           }
    3741        3395 :           todo.push_back(t);
    3742             :           /* if ((!regular)||(mode=mCRL))
    3743             :               todo.push_back(t);
    3744             :                 / * single = in `mode=mCRL' is important, otherwise crash
    3745             :                    I do not understand the reason for this at this moment
    3746             :                    JFG (9/5/2000) */
    3747        3395 :           return body;
    3748             :         }
    3749             : 
    3750        1324 :         objectdatatype& object=objectIndex(t);
    3751        1324 :         if (object.processstatus==mCRL)
    3752             :         {
    3753          30 :           todo.push_back(t);
    3754          30 :           return process_expression();
    3755             :         }
    3756             :         /* The variable is a pCRL process and v==first, so,
    3757             :            we must now substitute */
    3758        1294 :         procstorealGNFrec(t,first,todo,regular);
    3759             : 
    3760             : 
    3761        1294 :         const assignment_list& dl= process_instance_assignment(body).assignments();
    3762             : 
    3763        2588 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    3764             : 
    3765        2030 :         for(assignment_list::const_iterator i=dl.begin(); i!=dl.end(); ++i)
    3766             :         {
    3767         736 :           sigma[i->lhs()]=i->rhs();
    3768         736 :           const std::set<variable> varset=find_free_variables(i->rhs());
    3769             :         }
    3770        2588 :         process_expression t3=substitute_pCRLproc(object.processbody,sigma);
    3771        1294 :         if (regular)
    3772             :         {
    3773        1120 :           t3=to_regular_form(t3,todo,freevars,variables_bound_in_sum);
    3774             :         }
    3775             : 
    3776        1294 :         return t3;
    3777             :       }
    3778             : 
    3779        1038 :       if (is_delta(body))
    3780             :       {
    3781         400 :         return body;
    3782             :       }
    3783             : 
    3784         638 :       if (is_tau(body))
    3785             :       {
    3786          77 :         return body;
    3787             :       }
    3788             : 
    3789         561 :       if (is_merge(body))
    3790             :       {
    3791         342 :         procstorealGNFbody(process::merge(body).left(),later,
    3792             :                            todo,regular,mode,freevars,variables_bound_in_sum);
    3793         342 :         procstorealGNFbody(process::merge(body).right(),later,
    3794             :                            todo,regular,mode,freevars,variables_bound_in_sum);
    3795         342 :         return process_expression();
    3796             :       }
    3797             : 
    3798         219 :       if (is_hide(body))
    3799             :       {
    3800          18 :         procstorealGNFbody(hide(body).operand(),later,todo,regular,mode,freevars,variables_bound_in_sum);
    3801          18 :         return process_expression();
    3802             :       }
    3803             : 
    3804         201 :       if (is_rename(body))
    3805             :       {
    3806           0 :         procstorealGNFbody(process::rename(body).operand(),later,todo,regular,mode,freevars,variables_bound_in_sum);
    3807           0 :         return process_expression();
    3808             :       }
    3809             : 
    3810         201 :       if (is_allow(body))
    3811             :       {
    3812          89 :         procstorealGNFbody(allow(body).operand(),later,todo,regular,mode,freevars,variables_bound_in_sum);
    3813          89 :         return process_expression();
    3814             :       }
    3815             : 
    3816         112 :       if (is_block(body))
    3817             :       {
    3818           0 :         procstorealGNFbody(block(body).operand(),later,todo,regular,mode,freevars,variables_bound_in_sum);
    3819           0 :         return process_expression();
    3820             :       }
    3821             : 
    3822         112 :       if (is_comm(body))
    3823             :       {
    3824         112 :         procstorealGNFbody(comm(body).operand(),later,todo,regular,mode,freevars,variables_bound_in_sum);
    3825         112 :         return process_expression();
    3826             :       }
    3827             : 
    3828             :       // The exception below can especially trigger on a process_instance as these ought to have
    3829             :       // been removed earlier in favour of process_instance_assignments.
    3830           0 :       throw mcrl2::runtime_error("unexpected process format in procstorealGNF " + process::pp(body) +".");
    3831             :       return process_expression();
    3832             :     }
    3833             : 
    3834             : 
    3835        5963 :     void procstorealGNFrec(
    3836             :       const process_identifier& procIdDecl,
    3837             :       const variableposition v,
    3838             :       std::vector <process_identifier>& todo,
    3839             :       const bool regular)
    3840             : 
    3841             :     /* Do a depth first search on process variables and substitute
    3842             :        for the headvariable of a pCRL process, in case it is a process,
    3843             :        such that we obtain a Greibach Normal Form. All pCRL processes will
    3844             :        be labelled with GNF to indicate that they are in
    3845             :        Greibach Normal Form. */
    3846             : 
    3847             :     {
    3848        5963 :       objectdatatype& object=objectIndex(procIdDecl);
    3849        5963 :       if (object.processstatus==pCRL)
    3850             :       {
    3851        2687 :         object.processstatus=GNFbusy;
    3852        5374 :         std::set<variable> variables_bound_in_sum;
    3853             :         const process_expression t=procstorealGNFbody(object.processbody,first,
    3854        5374 :                                    todo,regular,pCRL,object.parameters,variables_bound_in_sum);
    3855        2687 :         if (object.processstatus!=GNFbusy)
    3856             :         {
    3857           0 :           throw mcrl2::runtime_error("There is something wrong with recursion.");
    3858             :         }
    3859             : 
    3860        2687 :         object.processbody=t;
    3861        2687 :         object.processstatus=GNF;
    3862        2687 :         return;
    3863             :       }
    3864             : 
    3865        3276 :       if (object.processstatus==mCRL)
    3866             :       {
    3867         569 :         object.processstatus=mCRLbusy;
    3868        1138 :         std::set<variable> variables_bound_in_sum;
    3869             :         const process_expression t=procstorealGNFbody(object.processbody,first,todo,
    3870        1138 :                                    regular,mCRL,object.parameters,variables_bound_in_sum);
    3871             :         /* if the last result is not equal to NULL,
    3872             :            the body of this process is itself a processidentifier */
    3873             : 
    3874         569 :         object.processstatus=mCRLdone;
    3875         569 :         return;
    3876             :       }
    3877             : 
    3878        2707 :       if ((object.processstatus==GNFbusy) && (v==first))
    3879             :       {
    3880           0 :         throw mcrl2::runtime_error("Unguarded recursion in process " + process::pp(procIdDecl) +".");
    3881             :       }
    3882             : 
    3883        5414 :       if ((object.processstatus==GNFbusy)||
    3884        2707 :           (object.processstatus==GNF)||
    3885           0 :           (object.processstatus==mCRLdone)||
    3886           0 :           (object.processstatus==multiAction))
    3887             :       {
    3888        2707 :         return;
    3889             :       }
    3890             : 
    3891           0 :       if (object.processstatus==mCRLbusy)
    3892             :       {
    3893           0 :         throw mcrl2::runtime_error("Unguarded recursion in process " + process::pp(procIdDecl) +".");
    3894             :       }
    3895             : 
    3896           0 :       throw mcrl2::runtime_error("strange process type: " + std::to_string(object.processstatus));
    3897             :     }
    3898             : 
    3899         674 :     void procstorealGNF(const process_identifier& procsIdDecl,
    3900             :                         const bool regular)
    3901             :     {
    3902        1348 :       std::vector <process_identifier> todo;
    3903         674 :       todo.push_back(procsIdDecl);
    3904       10012 :       for (; !todo.empty() ;)
    3905             :       {
    3906        9338 :         const process_identifier pi=todo.back();
    3907        4669 :         todo.pop_back();
    3908        4669 :         procstorealGNFrec(pi,first,todo,regular);
    3909             :       }
    3910         674 :     }
    3911             : 
    3912             : 
    3913             :     /**************** GENERaTE LPE **********************************/
    3914             :     /*                                                              */
    3915             :     /*                                                              */
    3916             :     /*                                                              */
    3917             :     /*                                                              */
    3918             :     /*                                                              */
    3919             :     /*                                                              */
    3920             :     /****************************************************************/
    3921             : 
    3922             : 
    3923             :     /**************** Make pCRL procs  ******************************/
    3924             : 
    3925             :     /* make_pCRL_procs searches for all process identifiers reachable from id in pCRL equations. */
    3926             : 
    3927        3619 :     void make_pCRL_procs(const process_identifier& id,
    3928             :                          std::set<process_identifier>& reachable_process_identifiers)
    3929             :     {
    3930        3619 :       if (reachable_process_identifiers.count(id)==0)  // not found
    3931             :       {
    3932        2310 :         reachable_process_identifiers.insert(id);
    3933        2310 :         make_pCRL_procs(objectIndex(id).processbody,reachable_process_identifiers);
    3934             :       }
    3935        3619 :       return;
    3936             :     }
    3937             : 
    3938       10090 :     void make_pCRL_procs(const process_expression& t,
    3939             :                          std::set<process_identifier>& reachable_process_identifiers)
    3940             :     {
    3941       10090 :       if (is_choice(t))
    3942             :       {
    3943         767 :         make_pCRL_procs(choice(t).left(),reachable_process_identifiers);
    3944         767 :         make_pCRL_procs(choice(t).right(),reachable_process_identifiers);
    3945         767 :         return;
    3946             :       }
    3947             : 
    3948        9323 :       if (is_seq(t))
    3949             :       {
    3950        2603 :         make_pCRL_procs(seq(t).left(),reachable_process_identifiers);
    3951        2603 :         make_pCRL_procs(seq(t).right(),reachable_process_identifiers);
    3952        2603 :         return;
    3953             :       }
    3954             : 
    3955        6720 :       if (is_if_then(t))
    3956             :       {
    3957         354 :         make_pCRL_procs(if_then(t).then_case(),reachable_process_identifiers);
    3958         354 :         return;
    3959             :       }
    3960             : 
    3961        6366 :       if (is_sum(t))
    3962             :       {
    3963         599 :         make_pCRL_procs(sum(t).operand(),reachable_process_identifiers);
    3964         599 :         return;
    3965             :       }
    3966             : 
    3967        5767 :       if (is_stochastic_operator(t))
    3968             :       {
    3969          87 :         make_pCRL_procs(stochastic_operator(t).operand(),reachable_process_identifiers);
    3970          87 :         return;
    3971             :       }
    3972             : 
    3973        5680 :       if (is_process_instance_assignment(t))
    3974             :       {
    3975        2603 :         make_pCRL_procs(atermpp::down_cast<process_instance_assignment>(t).identifier(), reachable_process_identifiers);
    3976        2603 :         return;
    3977             :       }
    3978             : 
    3979        3077 :       if (is_sync(t)||is_action(t)||is_tau(t)||is_delta(t)||is_at(t))
    3980             :       {
    3981        3077 :         return;
    3982             :       }
    3983             : 
    3984           0 :       throw mcrl2::runtime_error("unexpected process format " + process::pp(t) + " in make_pCRL_procs");
    3985             :     }
    3986             : 
    3987             :     /**************** minimize_set_of_reachable_process_identifiers  ******************************/
    3988             : 
    3989             :     /* The process identifiers in reachable_process_identifiers have bodies and parameters lists
    3990             :      * that can be the same. If that is the case, they are identified. The right hand sides are substituted to
    3991             :      * reflect the identified processes. Example: P1 = a.P2, P3=a.P4, P2=b.Q, P4=b.Q. This reduces to P1 = a.P2, P2 = b.Q.
    3992             :      * The result is a map from remaining process identifiers to their adapted process bodies.
    3993             :      * The initial process was part of the reachable_process_identifiers and must be part of the map.
    3994             :      */
    3995             : 
    3996             :     /* set_proc_identifier_map is an auxiliary procedure that effectively sets identfier_identifier_map[id1]:=... or
    3997             :        identifier_identifier_map[id1]:=... in such a way that they map to the same element. In this way identifier_identifier_map
    3998             :        acts as a representation of the equivalence set induced by equations id1==id2. A constraint is that
    3999             :        initial_process may never occur as a left hand side. An invariant of identifier_identifier_map is
    4000             :        that no id1 that occurs at the right of the map can occur at the left.
    4001             :     */
    4002             : 
    4003           0 :     process_identifier get_last(const process_identifier& id, const std::map< process_identifier, process_identifier >& identifier_identifier_map)
    4004             :     {
    4005           0 :       process_identifier target_id=id;
    4006           0 :       bool ready=false;
    4007           0 :       do
    4008             :       {
    4009           0 :         const std::map< process_identifier, process_identifier >::const_iterator i=identifier_identifier_map.find(target_id);
    4010           0 :         if (i==identifier_identifier_map.end())
    4011             :         {
    4012           0 :           ready=true;
    4013             :         }
    4014             :         else
    4015             :         {
    4016           0 :           target_id=i->second;
    4017             :         }
    4018             :       }
    4019           0 :       while (!ready);
    4020           0 :       return target_id;
    4021             :     }
    4022             : 
    4023             : 
    4024           0 :     void set_proc_identifier_map(
    4025             :             std::map< process_identifier, process_identifier >& identifier_identifier_map,
    4026             :             const process_identifier& id1_,
    4027             :             const process_identifier& id2_,
    4028             :             const process_identifier& initial_process)
    4029             :     {
    4030           0 :       assert(id1_!=id2_);
    4031             : 
    4032             :       /* Take care that id1 is the last identifier or that id2 is arger than id1. This guarantees
    4033             :          that there will be no loops in the mapping of identifiers. */
    4034             :       // make_substitution sigma(identifier_identifier_map);
    4035           0 :       process_identifier id1= get_last(id1_,identifier_identifier_map);
    4036           0 :       process_identifier id2= get_last(id2_,identifier_identifier_map);
    4037           0 :       if (id1==initial_process)
    4038             :       {
    4039           0 :         id1.swap(id2);
    4040             :       }
    4041           0 :       if (id1!=id2)
    4042             :       {
    4043           0 :         identifier_identifier_map[id1]=id2;
    4044             :       }
    4045           0 :     }
    4046             : 
    4047        1016 :     void complete_proc_identifier_map(std::map< process_identifier, process_identifier >& identifier_identifier_map)
    4048             :     {
    4049        2032 :       std::map< process_identifier, process_identifier > new_identifier_identifier_map;
    4050        1016 :       for(const std::pair<const process_identifier, process_identifier >& p: identifier_identifier_map)
    4051             :       {
    4052           0 :         new_identifier_identifier_map[p.first]=get_last(p.second,identifier_identifier_map);
    4053             :       }
    4054        1016 :       identifier_identifier_map.swap(new_identifier_identifier_map);
    4055             : #ifndef NDEBUG
    4056             :       /* In the result no right hand side occurs as the left hand side of identifier_identifier_map */
    4057             :       typedef std::pair< const process_identifier, process_identifier > identifier_identifier_pair;
    4058        1016 :       for(const identifier_identifier_pair& p: identifier_identifier_map)
    4059             :       {
    4060           0 :         assert(identifier_identifier_map.count(p.second)==0);
    4061             :       }
    4062             : #endif
    4063        1016 :     }
    4064             : 
    4065             :     struct make_substitution
    4066             :     {
    4067             :       typedef process_identifier result_type;
    4068             :       typedef process_identifier argument_type;
    4069             :       const std::map< process_identifier, process_identifier >& m_map;
    4070             : 
    4071           0 :       make_substitution(const std::map< process_identifier, process_identifier >& map)
    4072           0 :         : m_map(map)
    4073           0 :       {}
    4074             : 
    4075           0 :       process_identifier operator()(const process_identifier& id) const
    4076             :       {
    4077           0 :         const std::map< process_identifier, process_identifier >::const_iterator i=m_map.find(id);
    4078           0 :         if (i==m_map.end()) // Not found
    4079             :         {
    4080           0 :           return id;
    4081             :         }
    4082           0 :         return i->second;
    4083             :       }
    4084             :     };
    4085             : 
    4086             :     std::set< process_identifier >
    4087        1016 :           minimize_set_of_reachable_process_identifiers(const std::set<process_identifier>& reachable_process_identifiers,
    4088             :                                                         const process_identifier& initial_process)
    4089             :     {
    4090        1016 :       assert(reachable_process_identifiers.count(initial_process)>0);
    4091             :       typedef std::pair< variable_list, process_expression > parameters_process_pair;
    4092             :       typedef std::map< std::pair< variable_list, process_expression >, process_identifier > mapping_type;
    4093             :       typedef std::pair<const std::pair< variable_list, process_expression >, process_identifier > mapping_type_pair;
    4094             : 
    4095             :       /* First put the identifiers in reachable_process_identifiers in the process mapping */
    4096        2032 :       mapping_type process_mapping;
    4097        2032 :       std::map< process_identifier, process_identifier > identifier_identifier_map;
    4098        3326 :       for(const process_identifier& id: reachable_process_identifiers)
    4099             :       {
    4100        2310 :         objectdatatype& object=objectIndex(id);
    4101        4620 :         const parameters_process_pair p(object.parameters,object.processbody);
    4102        2310 :         mapping_type::const_iterator i=process_mapping.find(p);
    4103        2310 :         if (i==process_mapping.end())   // Not found.
    4104             :         {
    4105        2310 :           process_mapping[p]=id;
    4106             :         }
    4107             :         else
    4108             :         {
    4109           0 :           set_proc_identifier_map(identifier_identifier_map,id,i->second,initial_process);
    4110             :         }
    4111             :       }
    4112        1016 :       complete_proc_identifier_map(identifier_identifier_map);
    4113             : 
    4114        1016 :       while (!identifier_identifier_map.empty())
    4115             :       {
    4116             :         /* Move the elements of process_mapping into new_process_mapping, under application
    4117             :          * of the identifier_identifier_map. If this yields new process_identifiers to be identified store
    4118             :          * these in new_proc_identifier_map. Do this until no process_identifiers are mapped onto
    4119             :          * each other anymore. */
    4120           0 :         std::map< process_identifier, process_identifier > new_identifier_identifier_map;
    4121           0 :         mapping_type new_process_mapping;
    4122           0 :         for(const mapping_type_pair& p: process_mapping)
    4123             :         {
    4124           0 :           const make_substitution sigma(identifier_identifier_map);
    4125           0 :           const parameters_process_pair p_new(p.first.first, replace_process_identifiers( p.first.second, sigma));
    4126           0 :           mapping_type::const_iterator i=new_process_mapping.find(p_new);
    4127           0 :           if (i==new_process_mapping.end())   // Not found.
    4128             :           {
    4129           0 :             new_process_mapping[p_new]=sigma(p.second);
    4130             :           }
    4131             :           else
    4132             :           {
    4133           0 :             set_proc_identifier_map(new_identifier_identifier_map,sigma(p.second),sigma(i->second),initial_process);
    4134             :           }
    4135             :         }
    4136           0 :         complete_proc_identifier_map(new_identifier_identifier_map);
    4137           0 :         identifier_identifier_map.swap(new_identifier_identifier_map);
    4138           0 :         process_mapping.swap(new_process_mapping);
    4139             :       }
    4140             : 
    4141             :       /* Store the pairs from process mapping into result */
    4142             :       /* std::map< process_identifier, process_expression > result;
    4143             :       for(const mapping_type_pair& p: process_mapping)
    4144             :       {
    4145             :         result[p.second]=p.first.second;
    4146             :       }
    4147             :       assert(result.count(initial_process)>0);
    4148             :       return result; */
    4149        1016 :       std::set< process_identifier > result;
    4150        3326 :       for(const mapping_type_pair& p: process_mapping)
    4151             :       {
    4152        2310 :         result.insert(p.second);
    4153        2310 :         objectdatatype& object=objectIndex(p.second);
    4154        2310 :         object.processbody=p.first.second;
    4155             :       }
    4156        1016 :       assert(result.count(initial_process)>0);
    4157        2032 :       return result;
    4158             :     }
    4159             : 
    4160             :     /****************   remove_stochastic_operators_from_front **********************/
    4161             : 
    4162       11550 :    class process_pid_pair
    4163             :    {
    4164             :      protected:
    4165             :        process_expression m_process_body;
    4166             :        process_identifier m_pid;
    4167             : 
    4168             :      public:
    4169        2310 :        process_pid_pair(const process_expression& process_body, const process_identifier& pid)
    4170        2310 :          : m_process_body(process_body), m_pid(pid)
    4171        2310 :        {}
    4172             : 
    4173             :        process_pid_pair& operator=(const process_pid_pair& other) = default;
    4174             : 
    4175        3619 :        const process_expression& process_body() const
    4176             :        {
    4177        3619 :          return m_process_body;
    4178             :        }
    4179             : 
    4180        2442 :        const process_identifier& process_id() const
    4181             :        {
    4182        2442 :          return m_pid;
    4183             :        }
    4184             :     };  // end process_pid_pair
    4185             : 
    4186             :     /* Take the process expressions from process_equations and transform these such that
    4187             :        no process equation has an initial distribution. The changed equations are reported
    4188             :        back, including adapted parameter lists because sometimes the variables bound in the
    4189             :        stochastic operators need to be added.
    4190             :        The initial distribution of the initial process is reported back in
    4191             :        initial_stochastic_distribution, including if necessary adapted sets of arguments. */
    4192             : 
    4193             :     std::set< process_identifier >
    4194        1016 :               remove_stochastic_operators_from_front(
    4195             :                    const std::set< process_identifier >& reachable_process_identifiers,
    4196             :                    process_identifier& initial_process_id, // If parameters change, another initial_process_id will be substituted.
    4197             :                    stochastic_distribution& initial_stochastic_distribution)
    4198             :     {
    4199             :       /* First obtain the stochastic distribution for each process variable. */
    4200        2032 :       std::map< process_identifier, process_pid_pair > processes_with_stochastic_distribution_first;
    4201        1016 :       std::set< process_identifier > result;
    4202        3326 :       for(const process_identifier& p: reachable_process_identifiers)
    4203             :       {
    4204        2310 :         objectdatatype& object = objectIndex(p);
    4205        4620 :         process_expression proc_=obtain_initial_distribution_term(object.processbody);
    4206        2310 :         if (!is_stochastic_operator(proc_))
    4207             :         {
    4208        2273 :           processes_with_stochastic_distribution_first.insert(std::pair< process_identifier, process_pid_pair >(p, process_pid_pair(proc_,p)));
    4209        2273 :           result.insert(p);
    4210             :         }
    4211             :         else
    4212             :         {
    4213          37 :           const stochastic_operator& proc=down_cast<const stochastic_operator>(proc_);
    4214          37 :           assert(!is_process_instance_assignment(proc.operand()));
    4215          37 :           objectdatatype& object=objectIndex(p);
    4216          74 :           maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma;
    4217          74 :           variable_list vars=proc.variables();
    4218          37 :           alphaconvert(vars,local_sigma, vars + object.parameters, data_expression_list());
    4219             : 
    4220             :           const process_identifier newproc=newprocess(
    4221          74 :                                            vars + object.parameters,
    4222          74 :                                            process::replace_variables_capture_avoiding_with_an_identifier_generator(proc.operand(),
    4223             :                                                                                        local_sigma,
    4224             :                                                                                        fresh_identifier_generator),
    4225             :                                            pCRL,
    4226          37 :                                            canterminatebody(proc.operand()),
    4227         148 :                                            containstimebody(proc.operand()));
    4228             :           // calculate the substitution to be applied on proc.distribution() which is moved outside the
    4229             :           // body the process.
    4230          37 :           processes_with_stochastic_distribution_first.insert(
    4231          74 :                         std::pair< process_identifier, process_pid_pair >
    4232             :                                  (p,
    4233         111 :                                   process_pid_pair(stochastic_operator(
    4234             :                                                         vars,
    4235          74 :                                                         replace_variables_capture_avoiding_alt(proc.distribution(), local_sigma),
    4236             :                                                         proc.operand()),
    4237             :                                                    newproc)));
    4238          37 :           result.insert(newproc);
    4239             :         }
    4240             :       }
    4241             : 
    4242        3326 :       for(const process_identifier& p: reachable_process_identifiers)
    4243             :       {
    4244        2310 :         objectdatatype& object=objectIndex(processes_with_stochastic_distribution_first.at(p).process_id());
    4245        2310 :         assert(!is_stochastic_operator(object.processbody));
    4246        2310 :         object.processbody=transform_initial_distribution_term(object.processbody,processes_with_stochastic_distribution_first);
    4247        2310 :         assert(!is_stochastic_operator(object.processbody));
    4248             :       }
    4249             : 
    4250             :       // Adapt the initial process
    4251        2032 :       process_expression initial_distribution=processes_with_stochastic_distribution_first.at(initial_process_id).process_body();
    4252        1016 :       if (is_stochastic_operator(initial_distribution))
    4253             :       {
    4254          60 :         const stochastic_operator sto=atermpp::down_cast<stochastic_operator>(initial_distribution);
    4255          30 :         initial_stochastic_distribution = stochastic_distribution(sto.variables(), sto.distribution());
    4256          30 :         initial_process_id=processes_with_stochastic_distribution_first.at(initial_process_id).process_id();
    4257             :       }
    4258             :       else
    4259             :       {
    4260         986 :         initial_stochastic_distribution = stochastic_distribution(variable_list(), real_one());
    4261             :       }
    4262             : 
    4263        2032 :       return result;
    4264             :     }
    4265             : 
    4266             : 
    4267             :     /**************** Collectparameterlist ******************************/
    4268             : 
    4269        1805 :     bool alreadypresent(variable& var,const variable_list& vl)
    4270             :     {
    4271             :       /* Note: variables can be different, although they have the
    4272             :          same string, due to different types. If they have the
    4273             :          same string, but different types, the conflict must
    4274             :          be resolved by renaming the name of the variable */
    4275             : 
    4276        1805 :       if (vl.empty())
    4277             :       {
    4278         914 :         return false;
    4279             :       }
    4280         891 :       const variable& var1=vl.front();
    4281         891 :       assert(is_variable(var1));
    4282             : 
    4283             :       /* The variable with correct type is present: */
    4284         891 :       if (var==var1)
    4285             :       {
    4286         480 :         return true;
    4287             :       }
    4288             : 
    4289         411 :       assert(var.name()!=var1.name());
    4290             : 
    4291             :       /* otherwise it can be present in vl */
    4292         411 :       return alreadypresent(var,vl.tail());
    4293             :     }
    4294             : 
    4295        3704 :     variable_list joinparameters(const variable_list& par1,
    4296             :                                  const variable_list& par2)
    4297             :     {
    4298        3704 :       if (par2.empty())
    4299             :       {
    4300        2310 :         return par1;
    4301             :       }
    4302             : 
    4303        2788 :       variable var2=par2.front();
    4304        1394 :       assert(is_variable(var2));
    4305             : 
    4306        2788 :       variable_list result=joinparameters(par1,par2.tail());
    4307        1394 :       if (alreadypresent(var2,par1))
    4308             :       {
    4309         480 :         return result;
    4310             :       }
    4311             : 
    4312         914 :       result.push_front(var2);
    4313         914 :       return result;
    4314             :     }
    4315             : 
    4316        1016 :     variable_list collectparameterlist(const std::set< process_identifier >& pCRLprocs)
    4317             :     {
    4318        1016 :       variable_list parameters;
    4319        3326 :       for (const process_identifier& p: pCRLprocs)
    4320             :       {
    4321        2310 :         const objectdatatype& object=objectIndex(p);
    4322        2310 :         parameters=joinparameters(parameters,object.parameters);
    4323             :       }
    4324        1016 :       return parameters;
    4325             :     }
    4326             : 
    4327             :     /****************  Declare local datatypes  ******************************/
    4328             : 
    4329         232 :     void declare_control_state(
    4330             :       const std::set < process_identifier >& pCRLprocs)
    4331             :     {
    4332         232 :       create_enumeratedtype(pCRLprocs.size());
    4333         232 :     }
    4334             : 
    4335             :     class stackoperations
    4336             :     {
    4337             :       public:
    4338             :         variable_list parameter_list;
    4339             :         sort_expression stacksort;
    4340             :         sort_expression_list sorts;
    4341             :         function_symbol_list get;
    4342             :         data::function_symbol push;
    4343             :         data::function_symbol emptystack;
    4344             :         data::function_symbol empty;
    4345             :         data::function_symbol pop;
    4346             :         data::function_symbol getstate;
    4347             :         stackoperations* next;
    4348             : 
    4349             :         // Stack operations are not supposed to be copied.
    4350             :         stackoperations(const stackoperations& )=delete;
    4351             :         stackoperations& operator=(const stackoperations& )=delete;
    4352             : 
    4353         232 :         stackoperations(const variable_list& pl,
    4354             :                         specification_basic_type& spec)
    4355         232 :         {
    4356         232 :           parameter_list=pl;
    4357         232 :           next=spec.stack_operations_list;
    4358         232 :           spec.stack_operations_list=this;
    4359             : 
    4360             :           //create structured sort
    4361             :           //  Stack = struct emptystack?is_empty
    4362             :           //               | push(getstate: Pos, getx1: S1, ..., getxn: Sn, pop: Stack)
    4363             :           //               ;
    4364             : 
    4365         464 :           basic_sort stack_sort_alias(spec.fresh_identifier_generator("Stack"));
    4366         464 :           structured_sort_constructor_argument_vector sp_push_arguments;
    4367         608 :           for (const variable& v: pl)
    4368             :           {
    4369         376 :             sp_push_arguments.push_back(structured_sort_constructor_argument(spec.fresh_identifier_generator("get" + std::string(v.name())), v.sort()));
    4370         376 :             sorts.push_front(v.sort());
    4371             :           }
    4372         232 :           sp_push_arguments.push_back(structured_sort_constructor_argument(spec.fresh_identifier_generator("pop"), stack_sort_alias));
    4373         232 :           sorts=reverse(sorts);
    4374         464 :           structured_sort_constructor sc_push(spec.fresh_identifier_generator("push"), sp_push_arguments);
    4375         464 :           structured_sort_constructor sc_emptystack(spec.fresh_identifier_generator("emptystack"),spec.fresh_identifier_generator("isempty"));
    4376             : 
    4377         464 :           structured_sort_constructor_vector constructors(1,sc_push);
    4378         232 :           constructors.push_back(sc_emptystack);
    4379             :           //add data declarations for structured sort
    4380         232 :           spec.data.add_alias(alias(stack_sort_alias,structured_sort(constructors)));
    4381         232 :           stacksort=data::normalize_sorts(stack_sort_alias,spec.data);
    4382         232 :           push=sc_push.constructor_function(stack_sort_alias);
    4383         232 :           emptystack=sc_emptystack.constructor_function(stack_sort_alias);
    4384         232 :           empty=sc_emptystack.recogniser_function(stack_sort_alias);
    4385             :           const std::vector< data::function_symbol > projection_functions =
    4386         464 :             sc_push.projection_functions(stack_sort_alias);
    4387         232 :           pop=projection_functions.back();
    4388         232 :           getstate=projection_functions.front();
    4389         232 :           get=function_symbol_list(projection_functions.begin()+1,projection_functions.end()-1);
    4390         232 :         }
    4391             : 
    4392         232 :         ~stackoperations()
    4393         232 :         {
    4394         232 :         }
    4395             :     };
    4396             : 
    4397             :     class stacklisttype
    4398             :     {
    4399             :       public:
    4400             :         stackoperations* opns;
    4401             :         variable_list parameters;
    4402             :         variable stackvar;
    4403             :         std::size_t no_of_states;
    4404             :         /* the boolean state variables occur in reverse
    4405             :            order, i.e. the least significant first, whereas
    4406             :            in parameter lists, the order is reversed. */
    4407             :         variable_list booleanStateVariables;
    4408             : 
    4409             : 
    4410             :         /* All datatypes for different stacks that are being generated
    4411             :            are stored in the following list, such that it can be investigated
    4412             :            whether a suitable stacktype already exist, before generating a new
    4413             :            one */
    4414             : 
    4415             :         stacklisttype(const stacklisttype& )=delete;
    4416             :         stacklisttype& operator=(const stacklisttype& )=delete;
    4417             : 
    4418             : 
    4419         306 :         stackoperations* find_suitable_stack_operations(
    4420             :           const variable_list& parameters,
    4421             :           stackoperations* stack_operations_list)
    4422             :         {
    4423         306 :           if (stack_operations_list==nullptr)
    4424             :           {
    4425         232 :             return nullptr;
    4426             :           }
    4427          74 :           if (parameters==stack_operations_list->parameter_list)
    4428             :           {
    4429           0 :             return stack_operations_list;
    4430             :           }
    4431          74 :           return find_suitable_stack_operations(parameters,stack_operations_list->next);
    4432             :         }
    4433             : 
    4434             :         /// \brief Constructor
    4435        1016 :         stacklisttype(const variable_list& parlist,
    4436             :                       specification_basic_type& spec,
    4437             :                       const bool regular,
    4438             :                       const std::set < process_identifier >& pCRLprocs,
    4439             :                       const bool singlecontrolstate)
    4440        1016 :         {
    4441        1016 :           assert(pCRLprocs.size()>0);
    4442        1016 :           parameters=parlist;
    4443             : 
    4444        1016 :           no_of_states=pCRLprocs.size();
    4445        2032 :           process_identifier last= *pCRLprocs.begin();
    4446        2032 :           const std::string s3((spec.options.statenames)?std::string(last.name()):std::string("s"));
    4447        1016 :           if ((spec.options.binary) && (spec.options.newstate))
    4448             :           {
    4449           0 :             std::size_t i=spec.upperpowerof2(no_of_states);
    4450           0 :             for (; i>0 ; i--)
    4451             :             {
    4452           0 :               variable name(spec.fresh_identifier_generator("bst"),sort_bool::bool_());
    4453           0 :               spec.insertvariable(name,true);
    4454           0 :               booleanStateVariables.push_front(name);
    4455             :             }
    4456             :           }
    4457             : 
    4458        1016 :           if (regular)
    4459             :           {
    4460         784 :             opns=nullptr;
    4461         784 :             if (spec.options.newstate)
    4462             :             {
    4463           0 :               if (!spec.options.binary)
    4464             :               {
    4465           0 :                 if (!singlecontrolstate)
    4466             :                 {
    4467           0 :                   const std::size_t e=spec.create_enumeratedtype(no_of_states);
    4468           0 :                   stackvar=variable(spec.fresh_identifier_generator(s3), spec.enumeratedtypes[e].sortId);
    4469             :                 }
    4470             :                 else
    4471             :                 {
    4472             :                   /* Generate a stackvariable that is never used */
    4473           0 :                   stackvar=variable(spec.fresh_identifier_generator("Never_used"), sort_bool::bool_());
    4474             :                 }
    4475             :               }
    4476             :               else
    4477             :               {
    4478           0 :                 stackvar=variable(spec.fresh_identifier_generator(s3),sort_bool::bool_());
    4479             :               }
    4480             :             }
    4481             :             else
    4482             :             {
    4483         784 :               stackvar=variable(spec.fresh_identifier_generator(s3), sort_pos::pos());
    4484             :             }
    4485         784 :             spec.insertvariable(stackvar,true);
    4486             :           }
    4487             :           else
    4488             :           {
    4489         232 :             if (spec.options.newstate)
    4490             :             {
    4491           0 :               throw mcrl2::runtime_error("cannot combine stacks with " +
    4492           0 :                                          (spec.options.binary?std::string("binary"):std::string("an enumerated type")));
    4493             :             }
    4494         232 :             opns=find_suitable_stack_operations(parlist,spec.stack_operations_list);
    4495             : 
    4496         232 :             if (opns!=nullptr)
    4497             :             {
    4498           0 :               stackvar=variable(spec.fresh_identifier_generator(s3),opns->stacksort);
    4499           0 :               spec.insertvariable(stackvar,true);
    4500             :             }
    4501             :             else
    4502             :             {
    4503         464 :               variable_list temp=parlist;
    4504         232 :               temp.push_front(variable("state",sort_pos::pos()));
    4505         232 :               opns=(stackoperations*) new stackoperations(temp,spec);
    4506         232 :               stackvar = variable(spec.fresh_identifier_generator(s3), opns->stacksort);
    4507         232 :               spec.insertvariable(stackvar,true);
    4508             :             }
    4509             :           }
    4510        1016 :         }
    4511             : 
    4512        1016 :         ~stacklisttype()
    4513        1016 :         {
    4514        1016 :         }
    4515             : 
    4516             :     };
    4517             : 
    4518        2873 :     bool is_global_variable(const data_expression& d) const
    4519             :     {
    4520        2873 :       return is_variable(d) && global_variables.count(atermpp::down_cast<variable>(d)) > 0;
    4521             :     }
    4522             : 
    4523         510 :     data_expression getvar(const variable& var,
    4524             :                            const stacklisttype& stack)
    4525             :     {
    4526             :       /* first search whether the variable is a free process variable */
    4527         510 :       if (global_variables.count(var)>0)
    4528             :       {
    4529         146 :         return var;
    4530             :       }
    4531             : 
    4532             :       /* otherwise find out whether the variable matches a parameter */
    4533         364 :       function_symbol_list::const_iterator getmappings=stack.opns->get.begin();
    4534        1592 :       for (variable_list::const_iterator walker=stack.parameters.begin() ;
    4535        1592 :            walker!=stack.parameters.end() ; ++walker,++getmappings)
    4536             :       {
    4537        1592 :         if (*walker==var)
    4538             :         {
    4539         364 :           return application(*getmappings,stack.stackvar);
    4540             :         }
    4541        1228 :         assert(getmappings!=stack.opns->get.end());
    4542             :       }
    4543           0 :       assert(0); /* We cannot end up here, because that means that we
    4544             :                     are looking for in non-existing variable */
    4545             :       return var;
    4546             :     }
    4547             : 
    4548        4640 :     assignment_list processencoding(
    4549             :       std::size_t i,
    4550             :       const assignment_list& t1,
    4551             :       const stacklisttype& stack)
    4552             :     {
    4553        4640 :       assert(i>0);
    4554        9280 :       assignment_list t(t1);
    4555        4640 :       if (!options.newstate)
    4556             :       {
    4557        9280 :         assignment_list result=t;
    4558        4640 :         result.push_front(assignment(stack.stackvar,sort_pos::pos(i)));
    4559        4640 :         return result;
    4560             :       }
    4561             : 
    4562           0 :       i=i-1; /* below we count from 0 instead from 1 as done in the
    4563             :                 first version of the prover */
    4564             : 
    4565           0 :       if (!options.binary)
    4566             :       {
    4567           0 :         const std::size_t e=create_enumeratedtype(stack.no_of_states);
    4568           0 :         data_expression_list l=enumeratedtypes[e].elementnames;
    4569           0 :         for (; i>0 ; i--)
    4570             :         {
    4571           0 :           assert(l.size()>0);
    4572           0 :           l.pop_front();
    4573             :         }
    4574           0 :         assignment_list result=t;
    4575           0 :         assert(l.size()>0);
    4576           0 :         result.push_front(assignment(stack.stackvar,l.front()));
    4577           0 :         return result;
    4578             :       }
    4579             :       /* else a sequence of boolean values needs to be generated,
    4580             :          representing the value i, when there are l->n elements */
    4581             :       {
    4582           0 :         std::size_t k=upperpowerof2(stack.no_of_states);
    4583           0 :         variable_list::const_iterator boolean_state_variables=stack.booleanStateVariables.begin();
    4584           0 :         for (; k>0 ; k--, ++boolean_state_variables)
    4585             :         {
    4586           0 :           if ((i % 2)==0)
    4587             :           {
    4588           0 :             t.push_front(assignment(*boolean_state_variables,sort_bool::false_()));
    4589           0 :             i=i/2;
    4590             :           }
    4591             :           else
    4592             :           {
    4593           0 :             t.push_front(assignment(*boolean_state_variables,sort_bool::true_()));
    4594           0 :             i=(i-1)/2;
    4595             :           }
    4596             :         }
    4597           0 :         return t;
    4598             :       }
    4599             :     }
    4600             : 
    4601        1149 :     data_expression_list processencoding(
    4602             :       std::size_t i,
    4603             :       const data_expression_list& t1,
    4604             :       const stacklisttype& stack)
    4605             :     {
    4606        2298 :       data_expression_list t(t1);
    4607        1149 :       if (!options.newstate)
    4608             :       {
    4609        2298 :         data_expression_list result=t;
    4610        1149 :         result.push_front(sort_pos::pos(i));
    4611        1149 :         return result;
    4612             :       }
    4613             : 
    4614           0 :       i=i-1; /* below we count from 0 instead from 1 as done in the
    4615             :                 first version of the linearizer */
    4616             : 
    4617           0 :       if (!options.binary)
    4618             :       {
    4619           0 :         const std::size_t e=create_enumeratedtype(stack.no_of_states);
    4620           0 :         data_expression_list l(enumeratedtypes[e].elementnames);
    4621           0 :         for (; i>0 ; i--)
    4622             :         {
    4623           0 :           l.pop_front();
    4624             :         }
    4625           0 :         data_expression_list result=t;
    4626           0 :         result.push_front(l.front());
    4627           0 :         return result;
    4628             :       }
    4629             :       /* else a sequence of boolean values needs to be generated,
    4630             :          representing the value i, when there are l->n elements */
    4631             :       {
    4632           0 :         std::size_t k=upperpowerof2(stack.no_of_states);
    4633           0 :         variable_list::const_iterator boolean_state_variables=stack.booleanStateVariables.begin();
    4634           0 :         for (; k>0 ; k--, ++boolean_state_variables)
    4635             :         {
    4636           0 :           if ((i % 2)==0)
    4637             :           {
    4638           0 :             t.push_front(sort_bool::false_());
    4639           0 :             i=i/2;
    4640             :           }
    4641             :           else
    4642             :           {
    4643           0 :             t.push_front(sort_bool::true_());
    4644           0 :             i=(i-1)/2;
    4645             :           }
    4646             :         }
    4647           0 :         return t;
    4648             :       }
    4649             :     }
    4650             : 
    4651        2596 :     data_expression correctstatecond(
    4652             :       const process_identifier& procId,
    4653             :       const std::set < process_identifier >& pCRLproc,
    4654             :       const stacklisttype& stack,
    4655             :       int regular)
    4656             :     {
    4657        2596 :       std::size_t i=1;
    4658        5448 :       for (const process_identifier& p: pCRLproc)
    4659             :       {
    4660        5448 :         if (p==procId)
    4661             :         {
    4662        2596 :           break;
    4663             :         }
    4664        2852 :         ++i;
    4665             :       }
    4666             :       /* i is the index of the current process */
    4667             : 
    4668        2596 :       if (!options.newstate)
    4669             :       {
    4670        2596 :         if (regular)
    4671             :         {
    4672        2044 :           return equal_to(stack.stackvar, processencoding(i,assignment_list(),stack).front().rhs());
    4673             :         }
    4674        1656 :         return equal_to(
    4675        1104 :                  application(stack.opns->getstate,stack.stackvar),
    4676        1656 :                  processencoding(i,assignment_list(),stack).front().rhs());
    4677             :       }
    4678             : 
    4679           0 :       if (!options.binary) /* Here a state encoding using enumerated types
    4680             :                               must be declared */
    4681             :       {
    4682           0 :         create_enumeratedtype(stack.no_of_states);
    4683           0 :         if (regular)
    4684             :         {
    4685           0 :           return equal_to(stack.stackvar,
    4686           0 :                           processencoding(i,assignment_list(),stack).front().rhs());
    4687             :         }
    4688           0 :         return equal_to(
    4689           0 :                  application(stack.opns->getstate, stack.stackvar),
    4690           0 :                  processencoding(i,assignment_list(),stack).front().rhs());
    4691             :       }
    4692             : 
    4693             :       /* in this case we must encode the condition using
    4694             :          boolean variables */
    4695             : 
    4696           0 :       const variable_list vars=stack.booleanStateVariables;
    4697             : 
    4698           0 :       i=i-1; /* start counting from 0, instead from 1 */
    4699           0 :       data_expression t3(sort_bool::true_());
    4700           0 :       for (const variable& v: vars)
    4701             :       {
    4702           0 :         if ((i % 2)==0)
    4703             :         {
    4704           0 :           t3=lazy::and_(lazy::not_(v),t3);
    4705           0 :           i=i/2;
    4706             :         }
    4707             :         else
    4708             :         {
    4709           0 :           t3=lazy::and_(v,t3);
    4710           0 :           i=(i-1)/2;
    4711             :         }
    4712             : 
    4713             :       }
    4714           0 :       assert(i==0);
    4715           0 :       return t3;
    4716             :     }
    4717             : 
    4718        8960 :     data_expression adapt_term_to_stack(
    4719             :       const data_expression& t,
    4720             :       const stacklisttype& stack,
    4721             :       const variable_list& vars,
    4722             :       const variable_list& stochastic_variables)
    4723             :     {
    4724        8960 :       if (is_function_symbol(t))
    4725             :       {
    4726        5154 :         return t;
    4727             :       }
    4728             : 
    4729        3806 :       if (is_variable(t))
    4730             :       {
    4731         858 :         if (std::find(vars.begin(),vars.end(),t)!=vars.end())
    4732             :         {
    4733             :           /* t occurs in vars, so, t does not have to be reconstructed
    4734             :              from the stack */
    4735         128 :           return t;
    4736             :         }
    4737             :         else
    4738         730 :         if (std::find(stochastic_variables.begin(),stochastic_variables.end(),t)!=stochastic_variables.end())
    4739             :         {
    4740             :           /* t occurs in stochastic_variables, so, t does not have to be reconstructed
    4741             :              from the stack */
    4742         220 :           return t;
    4743             :         }
    4744             :         else
    4745             :         {
    4746         510 :           return getvar(atermpp::down_cast<variable>(t), stack);
    4747             :         }
    4748             :       }
    4749             : 
    4750        2948 :       if (is_application(t))
    4751             :       {
    4752        2944 :         const application&a=atermpp::down_cast<application>(t);
    4753        5888 :         return application(
    4754        5888 :                  adapt_term_to_stack(a.head(),stack,vars,stochastic_variables),
    4755        8832 :                  adapt_termlist_to_stack(a.begin(),a.end(),stack,vars,stochastic_variables));
    4756             :       }
    4757             : 
    4758           4 :       if (is_abstraction(t))
    4759             :       {
    4760           8 :         const abstraction& abs_t(t);
    4761           8 :         return abstraction(
    4762             :                  abs_t.binding_operator(),
    4763             :                  abs_t.variables(),
    4764          12 :                  adapt_term_to_stack(abs_t.body(),stack,abs_t.variables() + vars,stochastic_variables));
    4765             :       }
    4766             : 
    4767           0 :       if (is_where_clause(t))
    4768             :       {
    4769           0 :         const where_clause where_t(t);
    4770           0 :         const assignment_list old_assignments=reverse(where_t.assignments());
    4771           0 :         variable_list new_vars=vars;
    4772           0 :         assignment_list new_assignments;
    4773           0 :         for (assignment_list::const_iterator i=old_assignments.begin();
    4774           0 :              i!=old_assignments.end(); ++i)
    4775             :         {
    4776           0 :           new_vars.push_front(i->lhs());
    4777           0 :           new_assignments.push_front(
    4778           0 :                              assignment(
    4779             :                                i->lhs(),
    4780           0 :                                adapt_term_to_stack(i->rhs(),stack,vars,stochastic_variables)));
    4781             : 
    4782             :         }
    4783           0 :         return where_clause(
    4784           0 :                  adapt_term_to_stack(where_t,stack,new_vars,stochastic_variables),
    4785           0 :                  new_assignments);
    4786             : 
    4787             :       }
    4788             : 
    4789           0 :       assert(0);  // expected a term;
    4790             :       return t;   // in case of non-debug mode, try to return something as decent as possible.
    4791             :     }
    4792             : 
    4793             :     template <typename Iterator>
    4794        3390 :     data_expression_vector adapt_termlist_to_stack(
    4795             :       Iterator begin,
    4796             :       const Iterator& end,
    4797             :       const stacklisttype& stack,
    4798             :       const variable_list& vars,
    4799             :       const variable_list& stochastic_variables)
    4800             :     {
    4801        3390 :       data_expression_vector result;
    4802       13234 :       for (; begin != end; ++begin)
    4803             :       {
    4804        4922 :         result.push_back(adapt_term_to_stack(*begin,stack, vars,stochastic_variables));
    4805             :       }
    4806        3390 :       return result;
    4807             :     }
    4808             : 
    4809             : 
    4810         994 :     action_list adapt_multiaction_to_stack_rec(
    4811             :       const action_list& multiAction,
    4812             :       const stacklisttype& stack,
    4813             :       const variable_list& vars)
    4814             :     {
    4815         994 :       if (multiAction.empty())
    4816             :       {
    4817         548 :         return multiAction;
    4818             :       }
    4819             : 
    4820         892 :       const action act=action(multiAction.front());
    4821             : 
    4822         892 :       action_list result=adapt_multiaction_to_stack_rec(multiAction.tail(),stack,vars);
    4823             : 
    4824             :       const data_expression_vector vec(adapt_termlist_to_stack(
    4825         892 :                             act.arguments().begin(),
    4826         892 :                             act.arguments().end(),
    4827             :                             stack,
    4828             :                             vars,
    4829        1784 :                             variable_list()));
    4830         446 :       result.push_front(action(act.label(),data_expression_list(vec.begin(),vec.end())));
    4831         446 :       return result;
    4832             :     }
    4833             : 
    4834         548 :     action_list adapt_multiaction_to_stack(
    4835             :       const action_list& multiAction,
    4836             :       const stacklisttype& stack,
    4837             :       const variable_list& vars)
    4838             :     {
    4839         548 :       return adapt_multiaction_to_stack_rec(multiAction,stack,vars);
    4840             :     }
    4841             : 
    4842        1954 :     data_expression representative_generator_internal(const sort_expression& s, const bool allow_dont_care_var=true)
    4843             :     {
    4844        1954 :       if ((!options.noglobalvars) && allow_dont_care_var)
    4845             :       {
    4846        3252 :         const variable newVariable(fresh_identifier_generator("dc"),s);
    4847        1626 :         insertvariable(newVariable,true);
    4848        1626 :         global_variables.insert(newVariable);
    4849        1626 :         return newVariable;
    4850             :       }
    4851         333 :       return representative_generator(data)(s);
    4852             :     }
    4853             : 
    4854         580 :     data_expression find_(
    4855             :       const variable& s,
    4856             :       const assignment_list& args,
    4857             :       const stacklisttype& stack,
    4858             :       const variable_list& vars,
    4859             :       const std::set<variable>& free_variables_in_body,
    4860             :       const variable_list& stochastic_variables)
    4861             :     {
    4862             :       /* We generate the value for variable s in the list of
    4863             :          the parameters of the process. If s is equal to some
    4864             :          variable in pars, it is an argument of the current
    4865             :          process, and it must be replaced by the corresponding
    4866             :          argument in args.
    4867             :            If s does not occur in pars, it must be replaced
    4868             :          by a dummy value.
    4869             :       */
    4870        1776 :       for (assignment_list::const_iterator i=args.begin(); i!=args.end(); ++i)
    4871             :       {
    4872        1574 :         if (s==i->lhs())
    4873             :         {
    4874         378 :           return adapt_term_to_stack(i->rhs(),stack,vars,stochastic_variables);
    4875             :         }
    4876             :       }
    4877             : 
    4878         202 :       if (free_variables_in_body.find(s)==free_variables_in_body.end())
    4879             :       {
    4880         288 :         const data_expression result=representative_generator_internal(s.sort());
    4881         144 :         return adapt_term_to_stack(result,stack,vars,stochastic_variables);
    4882             :       }
    4883          58 :       return adapt_term_to_stack(s,stack,vars,stochastic_variables);
    4884             :     }
    4885             : 
    4886             : 
    4887         992 :     data_expression_list findarguments(
    4888             :       const variable_list& pars,
    4889             :       const variable_list& parlist,
    4890             :       const assignment_list& args,
    4891             :       const data_expression_list& t2,
    4892             :       const stacklisttype& stack,
    4893             :       const variable_list& vars,
    4894             :       const std::set<variable>& free_variables_in_body,
    4895             :       const variable_list& stochastic_variables)
    4896             :     {
    4897         992 :       if (parlist.empty())
    4898             :       {
    4899         412 :         return t2;
    4900             :       }
    4901        1160 :       data_expression_list result=findarguments(pars,parlist.tail(),args,t2,stack,vars,free_variables_in_body,stochastic_variables);
    4902        1160 :       data_expression rhs=find_(parlist.front(),args,stack,vars,free_variables_in_body,stochastic_variables);
    4903             : 
    4904         580 :       result.push_front(rhs);
    4905         580 :       return result;
    4906             :     }
    4907             : 
    4908        2191 :     assignment_list find_dummy_arguments(
    4909             :       const variable_list& parlist,   // The list of all parameters.
    4910             :       const assignment_list& args,
    4911             :       const std::set<variable>& free_variables_in_body,
    4912             :       const variable_list& stochastic_variables)
    4913             :     {
    4914        4382 :       std::map<variable,data_expression> assignment_map;
    4915        3490 :       for(assignment_list::const_iterator k=args.begin(); k!=args.end(); ++k)
    4916             :       {
    4917        1299 :         assignment_map[k->lhs()]=k->rhs();
    4918             :       }
    4919             : 
    4920        4382 :       assignment_vector result;
    4921        5666 :       for(variable_list::const_iterator i=parlist.begin(); i!=parlist.end(); ++i)
    4922             :       {
    4923        3475 :         if (std::find(stochastic_variables.begin(),stochastic_variables.end(),*i)!=stochastic_variables.end())
    4924             :         {
    4925             :           // *i is a stochastic variable. Insert the identity assignment.
    4926         438 :           result.push_back(assignment(*i,*i));
    4927             :         }
    4928        3037 :         else if (free_variables_in_body.find(*i)==free_variables_in_body.end())
    4929             :         {
    4930             :           {
    4931             :             // The variable *i must get a default value.
    4932        2250 :             const data_expression rhs=representative_generator_internal(i->sort());
    4933        1125 :             result.push_back(assignment(*i,rhs));
    4934             :           }
    4935             :         }
    4936             :         else
    4937             :         {
    4938        1912 :           const std::map<variable,data_expression>::iterator k=assignment_map.find(*i);
    4939        1912 :           if (k!=assignment_map.end())  // There is assignment for *i. Use it.
    4940             :           {
    4941         770 :             result.push_back(assignment(k->first,k->second));
    4942         770 :             assignment_map.erase(k);
    4943             :           }
    4944             :         }
    4945             : 
    4946             :       }
    4947        4382 :       return assignment_list(result.begin(), result.end());
    4948             :     }
    4949             : 
    4950             : 
    4951             : 
    4952        2191 :     assignment_list push_regular(
    4953             :       const process_identifier& procId,
    4954             :       const assignment_list& args,
    4955             :       const stacklisttype& stack,
    4956             :       const std::set < process_identifier >& pCRLprocs,
    4957             :       bool singlestate,
    4958             :       const variable_list& stochastic_variables)
    4959             :     {
    4960        2191 :       objectdatatype& object=objectIndex(procId);
    4961        4382 :       const assignment_list t=find_dummy_arguments(stack.parameters,args,get_free_variables(object),stochastic_variables);
    4962             : 
    4963        2191 :       if (singlestate)
    4964             :       {
    4965         409 :         return t;
    4966             :       }
    4967             : 
    4968        1782 :       std::size_t i=1;
    4969        3691 :       for (const process_identifier& p: pCRLprocs)
    4970             :       {
    4971        3691 :         if (p==procId)
    4972             :         {
    4973        1782 :           break;
    4974             :         }
    4975        1909 :         ++i;
    4976             :       }
    4977        1782 :       return processencoding(i,t,stack);
    4978             :     }
    4979             : 
    4980             : 
    4981        2191 :     assignment_list make_procargs_regular(
    4982             :       const process_expression& t,
    4983             :       const stacklisttype& stack,
    4984             :       const std::set < process_identifier >& pcrlprcs,
    4985             :       const bool singlestate,
    4986             :       const variable_list& stochastic_variables)
    4987             :     {
    4988             :       /* t is a sequential composition of process variables */
    4989             : 
    4990        2191 :       if (is_seq(t))
    4991             :       {
    4992           0 :         throw mcrl2::runtime_error("Process is not regular, as it has stacking vars: " + process::pp(t) + ".");
    4993             :       }
    4994             : 
    4995        2191 :       if (is_process_instance_assignment(t))
    4996             :       {
    4997        4382 :         const process_identifier procId=process_instance_assignment(t).identifier();
    4998        4382 :         const assignment_list t1=process_instance_assignment(t).assignments();
    4999             :         return push_regular(procId,
    5000             :                             t1,
    5001             :                             stack,
    5002             :                             pcrlprcs,
    5003             :                             singlestate,
    5004        4382 :                             stochastic_variables);
    5005             :       }
    5006             : 
    5007           0 :       throw mcrl2::runtime_error("Expect seq or name constructing a recursive invocation: " + process::pp(t) + ".");
    5008             :     }
    5009             : 
    5010         412 :     data_expression push_stack(
    5011             :       const process_identifier& procId,
    5012             :       const assignment_list& args,
    5013             :       const data_expression_list& t2,
    5014             :       const stacklisttype& stack,
    5015             :       const std::set < process_identifier >& pCRLprocs,
    5016             :       const variable_list& vars,
    5017             :       const variable_list& stochastic_variables)
    5018             :     {
    5019         412 :       objectdatatype& object=objectIndex(procId);
    5020             :       const data_expression_list t=findarguments(object.parameters,
    5021             :                                                  stack.parameters,
    5022             :                                                  args,t2,stack,vars,
    5023             :                                                  get_free_variables(object),
    5024         824 :                                                  stochastic_variables);
    5025             : 
    5026         412 :       std::size_t i=1;
    5027         626 :       for (const process_identifier& p: pCRLprocs)
    5028             :       {
    5029         626 :         if (p==procId)
    5030             :         {
    5031         412 :           break;
    5032             :         }
    5033         214 :         ++i;
    5034             :       }
    5035         824 :       const data_expression_list l=processencoding(i,t,stack);
    5036         412 :       assert(l.size()==function_sort(stack.opns->push.sort()).domain().size());
    5037         824 :       return application(stack.opns->push,l);
    5038             :     }
    5039             : 
    5040         412 :     data_expression make_procargs_stack(
    5041             :       const process_expression& t,
    5042             :       const stacklisttype& stack,
    5043             :       const std::set < process_identifier >& pcrlprcs,
    5044             :       const variable_list& vars,
    5045             :       const variable_list& stochastic_variables)
    5046             :     {
    5047             :       /* t is a sequential composition of process variables */
    5048             : 
    5049         412 :       if (is_seq(t))
    5050             :       {
    5051          72 :         const process_instance_assignment process=atermpp::down_cast<process_instance_assignment>(seq(t).left());
    5052          72 :         const process_expression process2=seq(t).right();
    5053          36 :         const process_identifier& procId=process.identifier();
    5054          36 :         const assignment_list& t1=process.assignments();
    5055             : 
    5056          36 :         if (objectIndex(procId).canterminate)
    5057             :         {
    5058          72 :           const data_expression stackframe=make_procargs_stack(process2,stack,pcrlprcs, vars,stochastic_variables);
    5059          36 :           return push_stack(procId,t1, data_expression_list({ stackframe }),stack,pcrlprcs,vars,stochastic_variables);
    5060             :         }
    5061             : 
    5062           0 :         return push_stack(procId,t1, data_expression_list({ data_expression(stack.opns->emptystack) }),
    5063           0 :                                            stack,pcrlprcs,vars,stochastic_variables);
    5064             :       }
    5065             : 
    5066         376 :       if (is_process_instance_assignment(t))
    5067             :       {
    5068         752 :         const process_identifier procId=process_instance_assignment(t).identifier();
    5069         752 :         const assignment_list t1=process_instance_assignment(t).assignments();
    5070             : 
    5071         376 :         if (objectIndex(procId).canterminate)
    5072             :         {
    5073             :           return push_stack(procId,
    5074             :                             t1,
    5075           8 :                             data_expression_list({ data_expression(application(stack.opns->pop,stack.stackvar)) }),
    5076             :                             stack,
    5077             :                             pcrlprcs,
    5078             :                             vars,
    5079           4 :                             stochastic_variables);
    5080             :         }
    5081             :         return push_stack(procId,
    5082             :                           t1,
    5083         744 :                           data_expression_list({ data_expression(stack.opns->emptystack) }),
    5084             :                           stack,
    5085             :                           pcrlprcs,
    5086             :                           vars,
    5087         372 :                           stochastic_variables);
    5088             :       }
    5089             : 
    5090           0 :       throw mcrl2::runtime_error("Expect seq or name putting processes on a stack: " + process::pp(t) +".");
    5091             :     }
    5092             : 
    5093        2567 :     assignment_list make_procargs(
    5094             :       const process_expression& t,
    5095             :       const stacklisttype& stack,
    5096             :       const std::set < process_identifier >& pcrlprcs,
    5097             :       const variable_list& vars,
    5098             :       const bool regular,
    5099             :       const bool singlestate,
    5100             :       const variable_list& stochastic_variables)
    5101             :     {
    5102        2567 :       if (regular)
    5103             :       {
    5104        2191 :         return make_procargs_regular(t,stack,pcrlprcs,singlestate,stochastic_variables);
    5105             :       }
    5106             :       /* return a stackframe */
    5107         752 :       data_expression sf=make_procargs_stack(t,stack,pcrlprcs,vars,stochastic_variables);
    5108         376 :       return assignment_list({ assignment(stack.stackvar,sf) });
    5109             :     }
    5110             : 
    5111          11 :     bool occursin(const variable& name,
    5112             :                   const variable_list& pars)
    5113             :     {
    5114          11 :       assert(is_variable(name));
    5115          11 :       for (const variable& v: pars)
    5116             :       {
    5117           0 :         if (name.name()==v.name())
    5118             :         {
    5119           0 :           return true;
    5120             :         }
    5121             :       }
    5122          11 :       return false;
    5123             :     }
    5124             : 
    5125             : 
    5126         784 :     data_expression_list pushdummy_regular_data_expressions(
    5127             :       const variable_list& pars,
    5128             :       const stacklisttype& stack)
    5129             :     {
    5130             :       /* stack.parameters is the total list of parameters of the
    5131             :          aggregated pCRL process. The variable pars contains
    5132             :          the list of all variables occuring in the initial
    5133             :          process. */
    5134             : 
    5135        1568 :       data_expression_vector result;
    5136        1554 :       for(const variable& par: stack.parameters)
    5137             :       {
    5138             :         /* // Check whether it is a stochastic variable.
    5139             :         if (std::find(stochastic_variables.begin(),stochastic_variables.end(),par)!=pars.end())
    5140             :         {
    5141             :           result.push_back(assignment(par,par)); 
    5142             :         } 
    5143             :         // Otherwise, check that is is an ordinary parameter.
    5144             :         else */ 
    5145         770 :         if (std::find(pars.begin(),pars.end(),par)!=pars.end())
    5146             :         {
    5147         447 :           result.push_back(par); 
    5148             :         }
    5149             :         /* otherwise the value of this argument is irrelevant, so
    5150             :            make it a don't care variable. */
    5151             :         else
    5152             :         {
    5153         323 :           result.push_back(representative_generator_internal(par.sort()));
    5154             :         }
    5155             :       }
    5156        1568 :       return data_expression_list(result.begin(), result.end());
    5157             :     }
    5158             : 
    5159             :     assignment_list pushdummy_regular(
    5160             :       const variable_list& pars,
    5161             :       const stacklisttype& stack,
    5162             :       const variable_list& stochastic_variables)
    5163             :     {
    5164             :       /* stack.parameters is the total list of parameters of the
    5165             :          aggregated pCRL process. The variable pars contains
    5166             :          the list of all variables occuring in the initial
    5167             :          process. */
    5168             : 
    5169             :       assignment_vector result;
    5170             :       for(const variable& par: stack.parameters)
    5171             :       {
    5172             :         // Check whether it is a stochastic variable.
    5173             :         if (std::find(stochastic_variables.begin(),stochastic_variables.end(),par)!=pars.end())
    5174             :         {
    5175             :           result.push_back(assignment(par,par)); 
    5176             :         }
    5177             :         // Otherwise, check that is is an ordinary parameter.
    5178             :         else if (std::find(pars.begin(),pars.end(),par)!=pars.end())
    5179             :         {
    5180             :         }
    5181             :         /* otherwise the value of this argument is irrelevant, so
    5182             :            make it a don't care variable. */
    5183             :         else
    5184             :         {
    5185             :           result.push_back(assignment(par,representative_generator_internal(par.sort())));
    5186             :         }
    5187             :       }
    5188             :       return assignment_list(result.begin(), result.end());
    5189             :     }
    5190             : 
    5191         376 :     data_expression_list pushdummyrec_stack(
    5192             :       const variable_list& totalpars,
    5193             :       const variable_list& pars,
    5194             :       const stacklisttype& stack,
    5195             :       const variable_list& stochastic_variables)
    5196             :     {
    5197             :       /* totalpars is the total list of parameters of the
    5198             :          aggregated pCRL process. The variable pars contains
    5199             :          the list of all variables occuring in the initial
    5200             :          process. */
    5201             : 
    5202         376 :       if (totalpars.empty())
    5203             :       {
    5204         232 :         return data_expression_list({ data_expression(stack.opns->emptystack) });
    5205             :       }
    5206             : 
    5207         144 :       const variable& par=totalpars.front();
    5208         144 :       if (std::find(pars.begin(),pars.end(),par)!=pars.end())
    5209             :       {
    5210         216 :         data_expression_list result=pushdummyrec_stack(totalpars.tail(),pars,stack,stochastic_variables);
    5211         108 :         result.push_front(par);
    5212         108 :         return result;
    5213             :       }
    5214             :       /* Check whether the parameter par refers to a stochastic variables */
    5215          36 :       if (std::find(stochastic_variables.begin(),stochastic_variables.end(),par)!=pars.end())
    5216             :       {
    5217           0 :         data_expression_list result=pushdummyrec_stack(totalpars.tail(),pars,stack,stochastic_variables);
    5218           0 :         result.push_front(par);
    5219           0 :         return result;
    5220             :       }
    5221             :       /* otherwise the value of this argument is irrelevant, so
    5222             :          make it Nil, if a regular translation is made. If a translation
    5223             :          with stacks is made, then yield a default `unique' term. */
    5224          72 :       data_expression_list result=pushdummyrec_stack(totalpars.tail(),pars,stack,stochastic_variables);
    5225          36 :       result.push_front(representative_generator_internal(par.sort()));
    5226          36 :       return result;
    5227             :     }
    5228             : 
    5229         232 :     data_expression_list pushdummy_stack(
    5230             :       const variable_list& parameters,
    5231             :       const stacklisttype& stack,
    5232             :       const variable_list& stochastic_variables)
    5233             :     {
    5234         232 :       return pushdummyrec_stack(stack.parameters,parameters,stack,stochastic_variables);
    5235             :     }
    5236             : 
    5237        1016 :     data_expression_list make_initialstate(
    5238             :       const process_identifier& initialProcId,
    5239             :       const stacklisttype& stack,
    5240             :       const std::set < process_identifier >& pcrlprcs,
    5241             :       const bool regular,
    5242             :       const bool singlecontrolstate,
    5243             :       const stochastic_distribution& initial_stochastic_distribution)
    5244             :     {
    5245        1016 :       std::size_t i=1;
    5246        1487 :       for (const process_identifier& p: pcrlprcs)
    5247             :       {
    5248        1487 :         if (p==initialProcId)
    5249             :         {
    5250        1016 :           break;
    5251             :         }
    5252         471 :         ++i;
    5253             :       }
    5254             :       /* i is the index of the initial state */
    5255             : 
    5256        1016 :       if (regular)
    5257             :       {
    5258             :         data_expression_list result=
    5259         784 :           pushdummy_regular_data_expressions(objectIndex(initialProcId).parameters,
    5260        1568 :                                              stack);
    5261         784 :         if (!singlecontrolstate)
    5262             :         {
    5263         505 :           return processencoding(i,result,stack);
    5264             :         }
    5265         279 :         return result;
    5266             :       }
    5267             :       else
    5268             :       {
    5269             :         data_expression_list result=
    5270         232 :                 pushdummy_stack(objectIndex(initialProcId).parameters,
    5271             :                                 stack,
    5272         696 :                                 initial_stochastic_distribution.variables());
    5273         464 :         const data_expression_list l=processencoding(i,result,stack);
    5274         232 :         assert(l.size()==function_sort(stack.opns->push.sort()).domain().size());
    5275         232 :         return data_expression_list({ application(stack.opns->push,l) });
    5276             :       }
    5277             :     }
    5278             : 
    5279             :     /*************************  Routines for summands  **************************/
    5280             : 
    5281         328 :     assignment_list dummyparameterlist(const stacklisttype& stack,
    5282             :                                        const bool singlestate)
    5283             :     {
    5284         328 :       if (singlestate)
    5285             :       {
    5286          66 :         return assignment_list();
    5287             :       }
    5288             : 
    5289         262 :       return processencoding(1,assignment_list(),stack); /* Take 1 as dummy indicator */
    5290             :     }
    5291             : 
    5292             : 
    5293        3071 :     void insert_summand(
    5294             :       stochastic_action_summand_vector& action_summands,
    5295             :       deadlock_summand_vector& deadlock_summands,
    5296             :       const variable_list& sumvars,
    5297             :       const data_expression& condition,
    5298             :       const action_list& multiAction,
    5299             :       const data_expression& actTime,
    5300             :       const stochastic_distribution& distribution,
    5301             :       const assignment_list& procargs,
    5302             :       const bool has_time,
    5303             :       const bool is_deadlock_summand)
    5304             :     {
    5305        3071 :       assert(distribution!=stochastic_distribution());
    5306        6142 :       const data_expression rewritten_condition=RewriteTerm(condition);
    5307        3071 :       if (rewritten_condition==sort_bool::false_())
    5308             :       {
    5309           0 :         return;
    5310             :       }
    5311             : 
    5312        3071 :       if (is_deadlock_summand)
    5313             :       {
    5314         491 :         insert_timed_delta_summand(action_summands,
    5315             :                                    deadlock_summands,
    5316         982 :                                    deadlock_summand(sumvars,
    5317             :                                                     rewritten_condition,
    5318         982 :                                                     has_time?deadlock(actTime):deadlock()));
    5319             :       }
    5320             :       else
    5321             :       {
    5322        2580 :         action_summands.push_back(stochastic_action_summand(
    5323             :                                                  sumvars,
    5324             :                                                  rewritten_condition,
    5325        5160 :                                                  has_time?multi_action(multiAction,actTime):multi_action(multiAction),
    5326             :                                                  procargs,
    5327        5160 :                                                  stochastic_distribution(distribution.variables(),
    5328        5160 :                                                                          RewriteTerm(distribution.distribution()))));
    5329             :       }
    5330             :     }
    5331             : 
    5332             : 
    5333        3077 :     void add_summands(
    5334             :       const process_identifier& procId,
    5335             :       stochastic_action_summand_vector& action_summands,
    5336             :       deadlock_summand_vector& deadlock_summands,
    5337             :       process_expression summandterm,
    5338             :       const std::set < process_identifier >& pCRLprocs,
    5339             :       const stacklisttype& stack,
    5340             :       const bool regular,
    5341             :       const bool singlestate,
    5342             :       const variable_list& process_parameters)
    5343             :     {
    5344        6154 :       data_expression atTime;
    5345        6154 :       action_list multiAction;
    5346        3077 :       bool is_delta_summand=false;
    5347        3077 :       bool has_time=false;
    5348             : 
    5349        3077 :       if (isDeltaAtZero(summandterm))
    5350             :       {
    5351             :         // delta@0 does not need to be added.
    5352           6 :         return;
    5353             :       }
    5354             : 
    5355             :       /* remove the sum operators; collect the sum variables in the
    5356             :          list sumvars */
    5357             : 
    5358        6142 :       variable_list sumvars;
    5359        4269 :       for (; is_sum(summandterm) ;)
    5360             :       {
    5361         599 :         sumvars=sum(summandterm).variables() + sumvars;
    5362         599 :         summandterm=sum(summandterm).operand();
    5363             :       }
    5364             : 
    5365             :       // Check whether the variables in sumvars clash with the parameter list,
    5366             :       // and rename the summandterm accordingly.
    5367        6142 :       maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma;
    5368        3071 :       alphaconvert(sumvars,local_sigma,process_parameters,data_expression_list());
    5369        3071 :       summandterm=substitute_pCRLproc(summandterm, local_sigma);
    5370             : 
    5371             : 
    5372             :       /* translate the condition */
    5373             : 
    5374        6142 :       data_expression condition1;
    5375        3071 :       if (regular && singlestate)
    5376             :       {
    5377         475 :         condition1=sort_bool::true_();
    5378             :       }
    5379             :       else
    5380             :       {
    5381        2596 :         condition1=correctstatecond(procId,pCRLprocs,stack,regular);
    5382             :       }
    5383             : 
    5384        6142 :       stochastic_distribution cumulative_distribution(variable_list(),real_one());
    5385             : 
    5386             :       /* The conditions are collected for use. The stochastic operators before the action are ignored */
    5387        3765 :       for (; (is_if_then(summandterm)||is_stochastic_operator(summandterm)) ;)
    5388             :       {
    5389         347 :         if (is_if_then(summandterm))
    5390             :         {
    5391         694 :           const data_expression localcondition=data_expression(if_then(summandterm).condition());
    5392         347 :           if (!(regular && singlestate))
    5393             :           {
    5394         262 :             condition1=lazy::and_(
    5395             :                          condition1,
    5396         262 :                          ((regular)?localcondition:
    5397             :                           adapt_term_to_stack(
    5398             :                             localcondition,
    5399             :                             stack,
    5400             :                             sumvars,
    5401             :                             cumulative_distribution.variables())));
    5402             :           }
    5403             :           else
    5404             :           {
    5405             :             /* regular and singlestate */
    5406         216 :             condition1=lazy::and_(localcondition,condition1);
    5407             :           }
    5408         347 :           summandterm=if_then(summandterm).then_case();
    5409             :         }
    5410             :         else
    5411             :         {
    5412           0 :           const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(summandterm);
    5413           0 :           cumulative_distribution=stochastic_distribution(
    5414           0 :                                     cumulative_distribution.variables()+sto.variables(),
    5415           0 :                                     real_times_optimized(cumulative_distribution.distribution(),
    5416             :                                                          sto.distribution()));
    5417           0 :           summandterm=sto.operand();
    5418             :         }
    5419             :       }
    5420             : 
    5421        3071 :       if (!cumulative_distribution.variables().empty() && !sumvars.empty())
    5422             :       {
    5423           0 :         throw mcrl2::runtime_error("Cannot permute sum operator and stochastic distribution in " + data::pp(summandterm));
    5424             :       }
    5425             : 
    5426        3071 :       if (is_seq(summandterm))
    5427             :       {
    5428             :         /* only one summand is needed */
    5429        5134 :         process_expression t1=seq(summandterm).left();
    5430        5134 :         process_expression t2=seq(summandterm).right();
    5431        2567 :         if (is_at(t1))
    5432             :         {
    5433         189 :           has_time=true;
    5434         189 :           atTime=at(t1).time_stamp();
    5435         189 :           t1=at(t1).operand();
    5436             :         }
    5437             : 
    5438        2567 :         if (t1==delta())
    5439             :         {
    5440          21 :           is_delta_summand=true;
    5441             :         }
    5442             :         else
    5443             :         {
    5444        2546 :           assert(is_tau(t1)||is_action(t1)||is_sync(t1));
    5445        2546 :           multiAction=to_action_list(t1);
    5446             :         }
    5447             : 
    5448        5134 :         stochastic_distribution distribution(variable_list(),real_one());
    5449        5134 :         process_expression t2_new=t2;
    5450        2567 :         if (is_stochastic_operator(t2))
    5451             :         {
    5452         103 :           const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(t2);
    5453         103 :           distribution=stochastic_distribution(sto.variables(),sto.distribution());
    5454         103 :           t2_new=sto.operand();
    5455             :         }
    5456        5134 :         const assignment_list procargs=make_procargs(t2_new,stack,pCRLprocs,sumvars,regular,singlestate,distribution.variables());
    5457             : 
    5458        2567 :         if (!regular)
    5459             :         {
    5460         376 :           if (!is_delta_summand)
    5461             :           {
    5462         372 :             multiAction=adapt_multiaction_to_stack(
    5463             :                           multiAction,stack,sumvars);
    5464             :           }
    5465         376 :           if (has_time)
    5466             :           {
    5467          54 :             atTime=adapt_term_to_stack(
    5468         108 :                      atTime,stack,sumvars,variable_list());
    5469             :           }
    5470         376 :           distribution=stochastic_distribution(
    5471             :                                   distribution.variables(),
    5472         752 :                                   adapt_term_to_stack(distribution.distribution(),stack,sumvars,distribution.variables()));
    5473             :         }
    5474        2567 :         insert_summand(action_summands,deadlock_summands,
    5475             :                        sumvars,condition1,multiAction,
    5476             :                        atTime,distribution,procargs,
    5477             :                        has_time,is_delta_summand);
    5478        2567 :         return;
    5479             :       }
    5480             : 
    5481             :       /* There is a single initial multiaction or deadlock, possibly timed*/
    5482         504 :       if (is_at(summandterm))
    5483             :       {
    5484         127 :         atTime=at(summandterm).time_stamp();
    5485         127 :         summandterm=at(summandterm).operand();
    5486         127 :         has_time=true;
    5487             :       }
    5488             :       else
    5489             :       {
    5490             :         // do nothing
    5491             :       }
    5492             : 
    5493         504 :       if (is_delta(summandterm))
    5494             :       {
    5495         470 :         is_delta_summand=true;
    5496             :       }
    5497          34 :       else if (is_tau(summandterm))
    5498             :       {
    5499             :         // multiAction is already empty.
    5500             :       }
    5501          30 :       else if (is_action(summandterm))
    5502             :       {
    5503          24 :         multiAction.push_front(action(summandterm));
    5504             :       }
    5505           6 :       else if (is_sync(summandterm))
    5506             :       {
    5507           6 :         multiAction=to_action_list(summandterm);
    5508             :       }
    5509             :       else
    5510             :       {
    5511           0 :         throw mcrl2::runtime_error("expected multiaction " + process::pp(summandterm) +".");
    5512             :       }
    5513             : 
    5514         504 :       if (regular)
    5515             :       {
    5516         328 :         if (!is_delta_summand)
    5517             :           /* As termination has been replaced by an explicit action terminated, followed
    5518             :            * by delta, a single terminating action cannot exist for regular processes. */
    5519             :         {
    5520           0 :           throw mcrl2::runtime_error("terminating processes should not exist when using the regular flag");
    5521             :         }
    5522         656 :         insert_summand(action_summands,
    5523             :                        deadlock_summands,
    5524             :                        sumvars,
    5525             :                        condition1,
    5526             :                        multiAction,
    5527             :                        atTime,
    5528         656 :                        stochastic_distribution(variable_list(),real_one()),
    5529         656 :                        dummyparameterlist(stack,singlestate),
    5530             :                        has_time,
    5531             :                        is_delta_summand);
    5532         328 :         return;
    5533             :       }
    5534             : 
    5535         176 :       multiAction=adapt_multiaction_to_stack(multiAction,stack,sumvars);
    5536         352 :       assignment_list procargs ({ assignment(stack.stackvar,application(stack.opns->pop,stack.stackvar)) });
    5537             : 
    5538         352 :       insert_summand(
    5539             :                 action_summands,
    5540             :                 deadlock_summands,
    5541             :                 sumvars,
    5542             :                 condition1,
    5543             :                 multiAction,
    5544             :                 atTime,
    5545         352 :                 stochastic_distribution(variable_list(),real_one()),   // TODO: UNLIKELY THAT THIS IS CORRECT.
    5546             :                 procargs,
    5547             :                 has_time,
    5548             :                 is_delta_summand);
    5549             : 
    5550         176 :       return;
    5551             :     }
    5552             : 
    5553             : 
    5554        3844 :     void collectsumlistterm(
    5555             :       const process_identifier& procId,
    5556             :       stochastic_action_summand_vector& action_summands,
    5557             :       deadlock_summand_vector& deadlock_summands,
    5558             :       const process_expression& body,
    5559             :       const variable_list& pars,
    5560             :       const stacklisttype& stack,
    5561             :       const bool regular,
    5562             :       const bool singlestate,
    5563             :       const std::set < process_identifier >& pCRLprocs)
    5564             :     {
    5565        3844 :       if (is_choice(body))
    5566             :       {
    5567        1534 :         const process_expression t1=choice(body).left();
    5568        1534 :         const process_expression t2=choice(body).right();
    5569             : 
    5570         767 :         collectsumlistterm(procId,action_summands,deadlock_summands,t1,pars,stack,
    5571             :                            regular,singlestate,pCRLprocs);
    5572         767 :         collectsumlistterm(procId,action_summands,deadlock_summands,t2,pars,stack,
    5573             :                            regular,singlestate,pCRLprocs);
    5574         767 :         return;
    5575             :       }
    5576        3077 :       if (is_stochastic_operator(body))
    5577             :       {
    5578             :         /* Remove leading stochastic operators. They will not become
    5579             :            part of this summand */
    5580           0 :         const stochastic_operator& sto=atermpp::down_cast<const stochastic_operator>(body);
    5581           0 :         collectsumlistterm(procId,action_summands,deadlock_summands,sto.operand(),pars,stack,
    5582             :                            regular,singlestate,pCRLprocs);
    5583             :       }
    5584             :       else
    5585             :       {
    5586        3077 :         add_summands(procId,action_summands,deadlock_summands,body,pCRLprocs,stack,
    5587             :                      regular,singlestate,pars);
    5588             :       }
    5589             :     }
    5590             : 
    5591        1016 :     void collectsumlist(
    5592             :       stochastic_action_summand_vector& action_summands,
    5593             :       deadlock_summand_vector& deadlock_summands,
    5594             :       const std::set < process_identifier >& pCRLprocs,
    5595             :       const variable_list& pars,
    5596             :       const stacklisttype& stack,
    5597             :       bool regular,
    5598             :       bool singlestate)
    5599             :     {
    5600        3326 :       for (const process_identifier& p: pCRLprocs)
    5601             :       {
    5602        2310 :         objectdatatype& object=objectIndex(p);
    5603             : 
    5604        2310 :         collectsumlistterm(
    5605             :           p,
    5606             :           action_summands,
    5607             :           deadlock_summands,
    5608             :           object.processbody,
    5609             :           pars,
    5610             :           stack,
    5611             :           regular,
    5612             :           singlestate,
    5613             :           pCRLprocs);
    5614             :       }
    5615        1016 :     }
    5616             : 
    5617             : 
    5618             :     /**************** Enumtype and enumeratedtype **********************************/
    5619             : 
    5620             :     class enumeratedtype
    5621             :     {
    5622             :       public:
    5623             :         std::size_t size;
    5624             :         sort_expression sortId;
    5625             :         data_expression_list elementnames;
    5626             :         function_symbol_list functions;
    5627             : 
    5628         362 :         enumeratedtype(const std::size_t n,
    5629             :                        specification_basic_type& spec)
    5630         362 :         {
    5631         362 :           size=n;
    5632         362 :           if (n==2)
    5633             :           {
    5634         201 :             sortId = sort_bool::bool_();
    5635         201 :             elementnames = data_expression_list({ sort_bool::false_(), sort_bool::true_()});
    5636             :           }
    5637             :           else
    5638             :           {
    5639             :             //create new sort identifier
    5640         322 :             basic_sort sort_id(spec.fresh_identifier_generator("Enum" + std::to_string(n)));
    5641         161 :             sortId=sort_id;
    5642             :             //create structured sort
    5643             :             //  Enumi = struct en_i | ... | e0_i;
    5644         322 :             structured_sort_constructor_list struct_conss;
    5645         550 :             for (std::size_t j=0 ; (j<n) ; j++)
    5646             :             {
    5647             :               //create constructor declaration of the structured sort
    5648         778 :               const identifier_string s=spec.fresh_identifier_generator("e" + std::to_string(j) + "_" + std::to_string(n));
    5649         778 :               const structured_sort_constructor struct_cons(s,"");
    5650             : 
    5651         389 :               struct_conss.push_front(struct_cons);
    5652             :             }
    5653         322 :             structured_sort sort_struct(struct_conss);
    5654             : 
    5655             :             //add declaration of standard functions
    5656         161 :             spec.data.add_alias(alias(sort_id, sort_struct));
    5657             : 
    5658             :             //store new declarations in return value w
    5659         161 :             sortId = sort_id;
    5660         161 :             const function_symbol_vector& constructors=spec.data.constructors(sort_id);
    5661         161 :             assert(constructors.size()==n);
    5662         161 :             elementnames = data::data_expression_list(constructors.begin(),constructors.end());
    5663             :           }
    5664         362 :         }
    5665             : 
    5666         422 :         enumeratedtype(const enumeratedtype& e)
    5667         422 :         {
    5668         422 :           size=e.size;
    5669         422 :           sortId=e.sortId;
    5670         422 :           elementnames=e.elementnames;
    5671         422 :           functions=e.functions;
    5672         422 :         }
    5673             : 
    5674             :         void operator=(const enumeratedtype& e)
    5675             :         {
    5676             :           size=e.size;
    5677             :           sortId=e.sortId;
    5678             :           elementnames=e.elementnames;
    5679             :           functions=e.functions;
    5680             :         }
    5681             : 
    5682         784 :         ~enumeratedtype()
    5683         784 :         {
    5684         784 :         }
    5685             :     };
    5686             : 
    5687         655 :     std::size_t create_enumeratedtype(const std::size_t n)
    5688             :     {
    5689             :       std::size_t w;
    5690             : 
    5691         655 :       for (w=0; ((w<enumeratedtypes.size()) && (enumeratedtypes[w].size!=n)); ++w) {};
    5692             : 
    5693         655 :       if (w==enumeratedtypes.size()) // There is no enumeratedtype of arity n.
    5694             :       {
    5695         362 :         enumeratedtypes.push_back(enumeratedtype(n,*this));
    5696             :       }
    5697         655 :       return w;
    5698             :     }
    5699             : 
    5700        1190 :     data::function_symbol find_case_function(std::size_t index, const sort_expression& sort)
    5701             :     {
    5702        2380 :       const function_symbol_list functions=enumeratedtypes[index].functions;
    5703        4152 :       for (function_symbol_list::const_iterator w=functions.begin();
    5704        2671 :            w!=functions.end(); ++w)
    5705             :       {
    5706        4152 :         sort_expression_list domain = function_sort(w->sort()).domain();
    5707        2671 :         assert(domain.size() >= 2);
    5708        2671 :         if (*(++domain.begin())==sort)
    5709             :         {
    5710        1190 :           return *w;
    5711             :         }
    5712             :       };
    5713             : 
    5714           0 :       throw mcrl2::runtime_error("searching for a nonexisting case function on sort " + data::pp(sort) +".");
    5715             :       return data::function_symbol();
    5716             :     }
    5717             : 
    5718          63 :     void define_equations_for_case_function(
    5719             :       const std::size_t index,
    5720             :       const data::function_symbol& functionname,
    5721             :       const sort_expression& sort)
    5722             :     {
    5723         126 :       variable_list vars;
    5724         126 :       data_expression_list args;
    5725         126 :       data_expression_list xxxterm;
    5726             : 
    5727          63 :       const sort_expression& normalised_sort=sort;
    5728         126 :       const variable v1=get_fresh_variable("x",normalised_sort);
    5729          63 :       const std::size_t n=enumeratedtypes[index].size;
    5730         400 :       for (std::size_t j=0; (j<n); j++)
    5731             :       {
    5732         674 :         const variable v=get_fresh_variable("y",normalised_sort);
    5733         337 :         vars.push_front(v);
    5734         337 :         args.push_front(data_expression(v));
    5735         337 :         xxxterm.push_front(data_expression(v1));
    5736             :       }
    5737             : 
    5738             :       /* I generate here an equation of the form
    5739             :          C(e,x,x,x,...x)=x for a variable x. */
    5740         126 :       const sort_expression s=enumeratedtypes[index].sortId;
    5741         126 :       const variable v=get_fresh_variable("e",s);
    5742         126 :       data_expression_list tempxxxterm=xxxterm;
    5743          63 :       tempxxxterm.push_front(data_expression(v));
    5744         126 :       data.add_equation(
    5745         126 :         data_equation(
    5746         126 :           variable_list({ v1, v }),
    5747         126 :           application(functionname,tempxxxterm),
    5748         126 :           data_expression(v1)));
    5749          63 :       fresh_equation_added=true;
    5750             : 
    5751         126 :       variable_list auxvars=vars;
    5752             : 
    5753         126 :       const data_expression_list elementnames=enumeratedtypes[index].elementnames;
    5754         400 :       for (data_expression_list::const_iterator w=elementnames.begin();
    5755         400 :            w!=elementnames.end() ; ++w)
    5756             :       {
    5757         337 :         assert(auxvars.size()>0);
    5758         674 :         data_expression_list tempargs=args;
    5759         337 :         tempargs.push_front(*w);
    5760        1011 :         data.add_equation(data_equation(
    5761             :                           vars,
    5762         674 :                           application(functionname,tempargs),
    5763         337 :                           auxvars.front()));
    5764         337 :         fresh_equation_added=true;
    5765             : 
    5766         337 :         auxvars.pop_front();
    5767             :       }
    5768          63 :     }
    5769             : 
    5770        1747 :     void create_case_function_on_enumeratedtype(
    5771             :       const sort_expression& sort,
    5772             :       const std::size_t enumeratedtype_index)
    5773             :     {
    5774        1747 :       assert(enumeratedtype_index<enumeratedtypes.size());
    5775             :       /* first find out whether the function exists already, in which
    5776             :          case nothing needs to be done */
    5777             : 
    5778        3494 :       const function_symbol_list functions=enumeratedtypes[enumeratedtype_index].functions;
    5779        3775 :       for (function_symbol_list::const_iterator w=functions.begin();
    5780        3775 :            w!=functions.end(); ++w)
    5781             :       {
    5782        5292 :         const sort_expression w1sort=w->sort();
    5783        3264 :         assert(function_sort(w1sort).domain().size()>1);
    5784             :         // Check that the second sort of the case function equals sort
    5785        3264 :         if (*(++(function_sort(w1sort).domain().begin()))==sort)
    5786             :         {
    5787        1236 :           return; // The case function does already exist
    5788             :         }
    5789             :       };
    5790             : 
    5791             :       /* The function does not exist;
    5792             :          Create a new function of enumeratedtype e, on sort */
    5793             : 
    5794         511 :       if (enumeratedtypes[enumeratedtype_index].sortId==sort_bool::bool_())
    5795             :       {
    5796             :         /* take the if function on sort 'sort' */
    5797         896 :         function_symbol_list f=enumeratedtypes[enumeratedtype_index].functions;
    5798         448 :         f.push_front(if_(sort));
    5799         448 :         enumeratedtypes[enumeratedtype_index].functions=f;
    5800         448 :         return;
    5801             :       }
    5802             :       // else
    5803         126 :       sort_expression_list newsortlist;
    5804          63 :       std::size_t n=enumeratedtypes[enumeratedtype_index].size;
    5805         400 :       for (std::size_t j=0; j<n ; j++)
    5806             :       {
    5807         337 :         newsortlist.push_front(sort);
    5808             :       }
    5809         126 :       sort_expression sid=enumeratedtypes[enumeratedtype_index].sortId;
    5810          63 :       newsortlist.push_front(sid);
    5811             : 
    5812         126 :       const function_sort newsort(newsortlist,sort);
    5813             :       const data::function_symbol casefunction(
    5814         189 :         fresh_identifier_generator("C" + std::to_string(n) + "_" +
    5815         252 :                          (!is_basic_sort(newsort)?"":std::string(basic_sort(sort).name()))), newsort);
    5816             :       // insertmapping(casefunction,true);
    5817          63 :       data.add_mapping(casefunction);
    5818         126 :       function_symbol_list f=enumeratedtypes[enumeratedtype_index].functions;
    5819          63 :       f.push_front(casefunction);
    5820          63 :       enumeratedtypes[enumeratedtype_index].functions=f;
    5821             : 
    5822          63 :       define_equations_for_case_function(enumeratedtype_index,casefunction,sort);
    5823          63 :       return;
    5824             :     }
    5825             : 
    5826             :     class enumtype
    5827             :     {
    5828             :       public:
    5829             :         // enumtypes are not supposed to be copied.
    5830             :         enumtype(const enumtype&)=delete;
    5831             :         enumtype& operator =(const enumtype& )=delete;
    5832             : 
    5833             :         std::size_t enumeratedtype_index;
    5834             :         variable var;
    5835             : 
    5836         423 :         enumtype(std::size_t n,
    5837             :                  const sort_expression_list& fsorts,
    5838             :                  const sort_expression_list& gsorts,
    5839             :                  specification_basic_type& spec)
    5840         423 :         {
    5841         423 :           enumeratedtype_index=spec.create_enumeratedtype(n);
    5842             : 
    5843         423 :           var=variable(spec.fresh_identifier_generator("e"),spec.enumeratedtypes[enumeratedtype_index].sortId);
    5844         423 :           spec.insertvariable(var,true);
    5845             : 
    5846         701 :           for (sort_expression_list::const_iterator w=fsorts.begin(); w!=fsorts.end(); ++w)
    5847             :           {
    5848         278 :             spec.create_case_function_on_enumeratedtype(*w,enumeratedtype_index);
    5849             :           }
    5850             : 
    5851        1441 :           for (sort_expression_list::const_iterator w=gsorts.begin(); w!=gsorts.end(); ++w)
    5852             :           {
    5853        1018 :             spec.create_case_function_on_enumeratedtype(*w,enumeratedtype_index);
    5854             :           }
    5855             : 
    5856         423 :           spec.create_case_function_on_enumeratedtype(sort_bool::bool_(),enumeratedtype_index);
    5857             : 
    5858         423 :           if (spec.timeIsBeingUsed || spec.stochastic_operator_is_being_used)
    5859             :           {
    5860          28 :             spec.create_case_function_on_enumeratedtype(sort_real::real_(),enumeratedtype_index);
    5861             :           }
    5862         423 :         }
    5863             : 
    5864         423 :         ~enumtype()
    5865         423 :         {
    5866         423 :         }
    5867             :     };
    5868             :     /************** Merge summands using enumerated type ***********************/
    5869             : 
    5870             :     /* The function below returns true if the variable var could be mapped
    5871             :        on an existing variable v' in matchinglist. The pars and args form pair
    5872             :        form a substitution that will be extended with the pair [var,v']. i
    5873             :        It returns false if the variable is new.
    5874             : 
    5875             :        If var is added (and not mapped on some other variable in the matchinglist/aka v)
    5876             :        it is checked whether var occurs in  v or in the process_parameters,
    5877             :        in which case var is renamed to a fresh variable. The renaming is added
    5878             :        to the substitution encoded in pars/args.
    5879             :     */
    5880             : 
    5881             : 
    5882         918 :     bool mergeoccursin(
    5883             :       variable& var,
    5884             :       const variable_list& v,
    5885             :       variable_list& matchinglist,
    5886             :       variable_list& pars,
    5887             :       data_expression_list& args,
    5888             :       const variable_list& process_parameters)
    5889             :     {
    5890        1836 :       variable_list auxmatchinglist;
    5891             : 
    5892             :       /* First find out whether var:sort can be matched to a
    5893             :          term in the matching list */
    5894             : 
    5895             :       /* first find out whether the variable occurs in the matching
    5896             :          list, so, they can be joined */
    5897             : 
    5898         918 :       for (variable_list::const_iterator i=matchinglist.begin();
    5899         918 :            i!=matchinglist.end(); ++i)
    5900             :       {
    5901         627 :         variable var1=*i;
    5902         627 :         if (var.sort()==var1.sort())
    5903             :         {
    5904             :           /* sorts match, so, we join the variables */
    5905         627 :           if (var!=var1)
    5906             :           {
    5907         379 :             pars.push_front(var);
    5908         379 :             args.push_front(data_expression(var1));
    5909             :           }
    5910             :           /* copy remainder of matching list */
    5911        2025 :           for (++i ; i!=matchinglist.end(); ++i)
    5912             :           {
    5913        1398 :             auxmatchinglist.push_front(*i);
    5914             :           }
    5915         627 :           matchinglist=reverse(auxmatchinglist);
    5916         627 :           return true;
    5917             :         }
    5918             :         else
    5919             :         {
    5920           0 :           auxmatchinglist.push_front(var1);
    5921             :         }
    5922             :       }
    5923             : 
    5924             :       /* turn auxmatchinglist back in normal order, and put the result
    5925             :          in *matchinglist */
    5926             : 
    5927         291 :       matchinglist=reverse(auxmatchinglist);
    5928             : 
    5929             :       /* in this case no matching argument has been found.
    5930             :       So, we must find out whether *var is an allowed variable, not
    5931             :       occuring in the variablelist v.
    5932             :       But if so, we must replace it by a new one. */
    5933         311 :       for (variable_list::const_iterator i=v.begin() ; i!=v.end() ; ++i)
    5934             :       {
    5935          40 :         variable var1=*i;
    5936          20 :         if (var.name()==var1.name())
    5937             :         {
    5938           0 :           pars.push_front(var);
    5939           0 :           var=get_fresh_variable(var.name(),var.sort());
    5940           0 :           args.push_front(data_expression(var));
    5941           0 :           return false;
    5942             :         }
    5943             :       }
    5944             : 
    5945             :       /* Check whether the variable occurs in the prcoess parameter list, in which case
    5946             :          it also needs to be renamed */
    5947         640 :       for (variable_list::const_iterator i=process_parameters.begin() ; i!=process_parameters.end() ; ++i)
    5948             :       {
    5949         722 :         variable var1=*i;
    5950         373 :         if (var.name()==var1.name())
    5951             :         {
    5952          24 :           pars.push_front(var);
    5953          24 :           var=get_fresh_variable(var.name(),var.sort());
    5954          24 :           args.push_front(data_expression(var));
    5955          24 :           return false;
    5956             :         }
    5957             :       }
    5958             : 
    5959             : 
    5960         267 :       return false;
    5961             :     }
    5962             : 
    5963         286 :     data_expression_list extend(const data_expression& c, const data_expression_list& cl)
    5964             :     {
    5965         572 :       return data_expression_list(cl.begin(), 
    5966         572 :                                   cl.end(), 
    5967         964 :                                   [&c](const data_expression& e)->data_expression { return lazy::and_(c,e);} );
    5968             : 
    5969             :     }
    5970             : 
    5971           0 :     data_expression variables_are_equal_to_default_values(const variable_list& vl)
    5972             :     {
    5973           0 :       data_expression result=sort_bool::true_();
    5974           0 :       for(const variable& v: vl)
    5975             :       {
    5976           0 :         const data_expression unique=representative_generator_internal(v.sort(),false);
    5977           0 :         result=lazy::and_(result,equal_to(v,unique));
    5978             :       }
    5979           0 :       return result;
    5980             :     }
    5981             : 
    5982             : 
    5983         291 :     data_expression_list extend_conditions(
    5984             :       const variable& var,
    5985             :       const data_expression_list& conditionlist)
    5986             :     {
    5987             :       try 
    5988             :       {
    5989         577 :         const data_expression unique=representative_generator_internal(var.sort(),false);
    5990         572 :         const data_expression newcondition=equal_to(var,unique);
    5991         286 :         return extend(newcondition,conditionlist);
    5992             :       }
    5993          10 :       catch (mcrl2::runtime_error&)
    5994             :       {
    5995             :         // The representative generator failed to find a term of var.sort(). 
    5996             :         // No condition is generated, meaning that var will be unrestrained. This
    5997             :         // is correct, and as the var.sort() has no concrete value, this will most
    5998             :         // likely not effect matters as state space generation. 
    5999           5 :         return conditionlist;
    6000             :       }
    6001             :     }
    6002             : 
    6003             : 
    6004        2502 :     data_expression transform_matching_list(const variable_list& matchinglist)
    6005             :     {
    6006        2502 :       data_expression result=sort_bool::true_();
    6007        2537 :       for(const variable& v: matchinglist)
    6008             :       {
    6009             :         try
    6010             :         {
    6011          70 :           data_expression unique=representative_generator_internal(v.sort(),false);
    6012          35 :           result=lazy::and_(result, equal_to(v,unique));
    6013             :         }
    6014           0 :         catch (mcrl2::runtime_error&)
    6015             :         {
    6016             :           // No representant for sort v.sort() could be found. No condition is added. 
    6017             :         }
    6018             :       }
    6019        2502 :       return result;
    6020             :     }
    6021             : 
    6022             : 
    6023        2502 :     data_expression_list addcondition(
    6024             :       const variable_list& matchinglist,
    6025             :       const data_expression_list& conditionlist)
    6026             :     {
    6027        2502 :       data_expression_list result=conditionlist;
    6028        2502 :       result.push_front(transform_matching_list(matchinglist));
    6029        2502 :       return result;
    6030             :     }
    6031             : 
    6032             : /* Join the variables of v1 to v2 and rename the variables in v1
    6033             :  * if needed. The conditionlist gives conditions to restrain variables
    6034             :  * that did not occur in the other list. renaming pars and args give
    6035             :  * renamings to be applied if variables in v1 had to be renamed. It
    6036             :  * is not allowed to rename to names already occurring in the parameter
    6037             :  * list. */
    6038             : 
    6039        2502 :    variable_list merge_var(
    6040             :       const variable_list& v1,
    6041             :       const variable_list& v2,
    6042             :       std::vector < variable_list>& renamings_pars,
    6043             :       std::vector < data_expression_list>& renamings_args,
    6044             :       data_expression_list& conditionlist,
    6045             :       const variable_list& process_parameters)
    6046             :     {
    6047        5004 :       data_expression_list renamingargs;
    6048        5004 :       variable_list renamingpars;
    6049        5004 :       variable_list matchinglist=v2;
    6050             : 
    6051             :       /* If the sequence of sum variables is reversed,
    6052             :        * the variables are merged in the same sequence for all
    6053             :        * summands (due to a suggestion of Muck van Weerdenburg) */
    6054             : 
    6055        5004 :       variable_list v1h=(v2.empty()?reverse(v1):v1);
    6056             : 
    6057        2502 :       variable_list result=v2;
    6058        3420 :       for (const variable& v_: v1h)
    6059             :       {
    6060        1836 :         variable v=v_;
    6061         918 :         if (!mergeoccursin(v,v2,
    6062             :                            matchinglist,renamingpars,renamingargs,process_parameters))
    6063             :         {
    6064         291 :           result.push_front(v);
    6065         291 :           conditionlist=extend_conditions(v,conditionlist);
    6066             :         }
    6067             :       }
    6068        2502 :       conditionlist=addcondition(matchinglist,conditionlist);
    6069        2502 :       renamings_pars.push_back(renamingpars);
    6070        2502 :       renamings_args.push_back(renamingargs);
    6071        5004 :       return result;
    6072             :     }
    6073             : 
    6074          62 :     variable_list make_binary_sums(
    6075             :       std::size_t n,
    6076             :       const sort_expression& enumtypename,
    6077             :       data_expression& condition,
    6078             :       const variable_list& tail)
    6079             :     {
    6080          62 :       variable_list result;
    6081          62 :       assert(n>1);
    6082          62 :       condition=sort_bool::true_();
    6083             : 
    6084          62 :       n=n-1;
    6085         146 :       for (result=tail ; (n>0) ; n=n/2)
    6086             :       {
    6087         168 :         variable sumvar=get_fresh_variable("e",enumtypename);
    6088          84 :         result.push_front(sumvar);
    6089          84 :         if ((n % 2)==0)
    6090             :         {
    6091          17 :           condition=lazy::and_(sumvar,condition);
    6092             :         }
    6093             :         else
    6094             :         {
    6095          67 :           condition=lazy::or_(sumvar,condition);
    6096             :         }
    6097             :       }
    6098          62 :       return result;
    6099             :     }
    6100             : 
    6101        1611 :     data_expression construct_binary_case_tree_rec(
    6102             :       std::size_t n,
    6103             :       const variable_list& sums,
    6104             :       data_expression_list& terms,
    6105             :       const sort_expression& termsort,
    6106             :       const enumtype& e)
    6107             :     {
    6108        1611 :       assert(!terms.empty());
    6109             : 
    6110        1611 :       if (n<=0)
    6111             :       {
    6112         911 :         assert(!terms.empty());
    6113        1822 :         const data_expression t=terms.front();
    6114         911 :         terms.pop_front();
    6115         911 :         return t;
    6116             :       }
    6117             : 
    6118         700 :       assert(!sums.empty());
    6119         700 :       const variable& casevar=sums.front();
    6120             : 
    6121        1400 :       const data_expression t=construct_binary_case_tree_rec(n / 2,sums.tail(),terms,termsort,e);
    6122             : 
    6123         700 :       if (terms.empty())
    6124             :       {
    6125         102 :         return t;
    6126             :       }
    6127             : 
    6128        1196 :       const data_expression t1=construct_binary_case_tree_rec(n / 2,sums.tail(),terms,termsort,e);
    6129             : 
    6130         598 :       if (t==t1)
    6131             :       {
    6132         364 :         return t;
    6133             :       }
    6134         234 :       return application(find_case_function(e.enumeratedtype_index, termsort), casevar, t, t1);
    6135             :     }
    6136             : 
    6137             :     template <class T>
    6138         721 :     bool all_equal(const atermpp::term_list<T>& l)
    6139             :     {
    6140         721 :       if (l.empty())
    6141             :       {
    6142           0 :         return true;
    6143             :       }
    6144         721 :       typename atermpp::term_list<T>::const_iterator i=l.begin();
    6145         721 :       const T& first=*i;
    6146        1561 :       for(++i ; i!=l.end(); ++i)
    6147             :       {
    6148         857 :         if (*i!=first)
    6149             :         {
    6150          17 :           return false;
    6151             :         }
    6152             :       }
    6153         704 :       return true;
    6154             :     }
    6155             : 
    6156         313 :     data_expression construct_binary_case_tree(
    6157             :       std::size_t n,
    6158             :       const variable_list& sums,
    6159             :       data_expression_list terms,
    6160             :       const sort_expression& termsort,
    6161             :       const enumtype& e)
    6162             :     {
    6163         313 :       return construct_binary_case_tree_rec(n-1,sums,terms,termsort,e);
    6164             :     }
    6165             : 
    6166        5299 :     bool summandsCanBeClustered(
    6167             :       const stochastic_action_summand& summand1,
    6168             :       const stochastic_action_summand& summand2)
    6169             :     {
    6170        5299 :       if (summand1.has_time()!= summand2.has_time())
    6171             :       {
    6172          46 :         return false;
    6173             :       }
    6174             : 
    6175             :       /* Here the multiactions are proper multi actions,
    6176             :          both with or without a time indication */
    6177             : 
    6178             :       /* The actions can be clustered if they contain
    6179             :          the same actions, with the same sorts for the
    6180             :          actions. We assume that the multiactions are
    6181             :          ordered.
    6182             :       */
    6183             : 
    6184       10506 :       const action_list multiactionlist1=summand1.multi_action().actions();
    6185       10506 :       const action_list multiactionlist2=summand2.multi_action().actions();
    6186        5253 :       action_list::const_iterator i2=multiactionlist2.begin();
    6187        7731 :       for (action_list::const_iterator i1=multiactionlist1.begin(); i1!=multiactionlist1.end(); ++i1,++i2)
    6188             :       {
    6189        5326 :         if (i2==multiactionlist2.end())
    6190             :         {
    6191        2890 :           return false;
    6192             :         }
    6193        5284 :         if (i1->label()!=i2->label())
    6194             :         {
    6195        2806 :           return false;
    6196             :         }
    6197             :       }
    6198        4810 :       return i2 == multiactionlist2.end();
    6199             :     }
    6200             : 
    6201        2451 :     data_expression getRHSassignment(const variable& var, const assignment_list& as)
    6202             :     {
    6203        5631 :       for (assignment_list::const_iterator i=as.begin(); i!=as.end(); ++i)
    6204             :       {
    6205        5181 :         if (i->lhs()==var)
    6206             :         {
    6207        2001 :           return i->rhs();
    6208             :         }
    6209             :       }
    6210         450 :       return data_expression(var);
    6211             :     }
    6212             : 
    6213         422 :     stochastic_action_summand collect_sum_arg_arg_cond(
    6214             :       const enumtype& e,
    6215             :       std::size_t n,
    6216             :       const stochastic_action_summand_vector& action_summands,
    6217             :       const variable_list& parameters)
    6218             :     {
    6219             :       /* This function gets a list of summands, with
    6220             :          the same multiaction and time
    6221             :          status. It yields a single clustered summand
    6222             :          by introducing an auxiliary sum operator, with
    6223             :          a variable of enumtype. In case binary is used,
    6224             :          a sequence of variables are introduced of sort Bool */
    6225             : 
    6226         844 :       variable_list resultsum;
    6227         844 :       data_expression resultcondition;
    6228         844 :       action_list resultmultiaction;
    6229         844 :       data_expression resulttime;
    6230             : 
    6231         844 :       std::vector < variable_list > rename_list_pars;
    6232         844 :       std::vector < data_expression_list > rename_list_args;
    6233             :       /* rename list is a list of pairs of variable and term lists */
    6234         844 :       data_expression_list conditionlist;
    6235         844 :       data_expression binarysumcondition;
    6236         422 :       int equaluptillnow=1;
    6237             : 
    6238        1383 :       for (const stochastic_action_summand& smmnd: action_summands)
    6239             :       {
    6240        1922 :         const variable_list sumvars=smmnd.summation_variables();
    6241         961 :         resultsum=merge_var(sumvars,resultsum,rename_list_pars,rename_list_args,conditionlist,parameters);
    6242             :       }
    6243             : 
    6244         422 :       if (options.binary)
    6245             :       {
    6246          62 :         resultsum=make_binary_sums(
    6247             :                     n,
    6248          62 :                     enumeratedtypes[e.enumeratedtype_index].sortId,
    6249             :                     binarysumcondition,
    6250             :                     resultsum);
    6251             :       }
    6252             :       else
    6253             :       {
    6254         360 :         resultsum.push_front(e.var);
    6255             :       }
    6256             : 
    6257             :       /* we construct the resulting condition */
    6258         844 :       data_expression_list auxresult;
    6259         422 :       std::vector < variable_list >::const_iterator auxrename_list_pars=rename_list_pars.begin();
    6260         422 :       std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    6261             : 
    6262         844 :       data_expression equalterm;
    6263         422 :       equaluptillnow=1;
    6264        1383 :       for (const stochastic_action_summand& smmnd: action_summands)
    6265             :       {
    6266         961 :         const data_expression& condition=smmnd.condition();
    6267         961 :         assert(auxrename_list_pars!=rename_list_pars.end());
    6268         961 :         assert(auxrename_list_args!=rename_list_args.end());
    6269        1922 :         const variable_list auxpars= *auxrename_list_pars;
    6270         961 :         ++auxrename_list_pars;
    6271        1922 :         const data_expression_list auxargs= *auxrename_list_args;
    6272         961 :         ++auxrename_list_args;
    6273        1922 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    6274         961 :         data_expression_list::const_iterator j=auxargs.begin();
    6275        1045 :         for (variable_list::const_iterator i=auxpars.begin();
    6276        1045 :              i!=auxpars.end(); ++i, ++j)
    6277             :         {
    6278             :           /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6279          84 :           if (sigma(*i)==*i)  // sigma *i is undefined. 
    6280             :           {
    6281          84 :             sigma[*i]=*j;
    6282          84 :             const std::set<variable> varset=find_free_variables(*j);
    6283             :           }
    6284             :         }
    6285        1922 :         maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    6286             : 
    6287        1922 :         const data_expression auxresult1=replace_variables_capture_avoiding_alt(condition,mutable_sigma);
    6288         961 :         if (equalterm==data_expression()||is_global_variable(equalterm))
    6289             :         {
    6290         422 :           equalterm=auxresult1;
    6291             :         }
    6292             :         else
    6293             :         {
    6294         539 :           if (equaluptillnow)
    6295             :           {
    6296         452 :             equaluptillnow=((auxresult1==equalterm)||is_global_variable(auxresult1));
    6297             :           }
    6298             :         }
    6299         961 :         auxresult.push_front(auxresult1);
    6300             :       }
    6301         422 :       if (options.binary)
    6302             :       {
    6303          62 :         resultcondition=construct_binary_case_tree(n,
    6304          62 :                         resultsum,auxresult,sort_bool::bool_(),e);
    6305          62 :         resultcondition=lazy::and_(binarysumcondition,resultcondition);
    6306          62 :         resultcondition=lazy::and_(
    6307         124 :                           construct_binary_case_tree(n,
    6308          62 :                               resultsum,conditionlist,sort_bool::bool_(),e),
    6309             :                           resultcondition);
    6310             :       }
    6311             :       else
    6312             :       {
    6313         360 :         if (equaluptillnow)
    6314             :         {
    6315         249 :           if (all_equal(conditionlist))
    6316             :           {
    6317         240 :             resultcondition=lazy::and_(conditionlist.front(), equalterm);
    6318             :           }
    6319             :           else
    6320             :           {
    6321          18 :             data_expression_list tempconditionlist=conditionlist;
    6322           9 :             tempconditionlist.push_front(data_expression(e.var));
    6323           9 :             resultcondition=lazy::and_(
    6324          18 :                               application(
    6325          18 :                                 find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6326             :                                 tempconditionlist),
    6327             :                               equalterm);
    6328             :           }
    6329             :         }
    6330             :         else
    6331             :         {
    6332         222 :           data_expression_list tempauxresult=auxresult;
    6333         111 :           tempauxresult.push_front(data_expression(e.var));
    6334         111 :           resultcondition=application(
    6335         222 :                             find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6336             :                             tempauxresult);
    6337         111 :           if (all_equal(conditionlist))
    6338             :           {
    6339         105 :            resultcondition=lazy::and_(conditionlist.front(),resultcondition);
    6340             :           }
    6341             :           else
    6342             :           {
    6343          12 :            data_expression_list tempconditionlist=conditionlist;
    6344           6 :            tempconditionlist.push_front(data_expression(e.var));
    6345           6 :            resultcondition=lazy::and_(
    6346          12 :                             application(
    6347          12 :                               find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6348             :                               tempconditionlist),
    6349             :                             resultcondition);
    6350             :           }
    6351             :         }
    6352             :       }
    6353             : 
    6354             :       /* now we construct the arguments of the action */
    6355             :       /* First we collect all multi-actions in a separate vector
    6356             :          of multiactions */
    6357         844 :       std::vector < action_list > multiActionList;
    6358             : 
    6359        1383 :       for (const stochastic_action_summand& smmnd: action_summands)
    6360             :       {
    6361         961 :         multiActionList.push_back(smmnd.multi_action().actions());
    6362             :       }
    6363             : 
    6364         844 :       action_list resultmultiactionlist;
    6365         422 :       std::size_t multiactioncount= multiActionList[0].size(); // The number of multi actions.
    6366        1244 :       for (; multiactioncount>0 ; multiactioncount--)
    6367             :       {
    6368         822 :         data_expression_list resultf;
    6369             :         // fcnt is the arity of the action with index multiactioncount-1;
    6370             :         // const action a= *(multiActionList[0].begin()+(multiactioncount-1));
    6371         411 :         action_list::const_iterator a=multiActionList[0].begin();
    6372         411 :         for (std::size_t i=1 ; i<multiactioncount ; ++i,++a) {}
    6373             :         // const action a= *((multiActionList[0]).begin()+(multiactioncount-1));
    6374         411 :         std::size_t fcnt=(a->arguments()).size();
    6375         822 :         data_expression f;
    6376             : 
    6377         967 :         for (; fcnt>0 ; fcnt--)
    6378             :         {
    6379         556 :           data_expression_list auxresult;
    6380         556 :           data_expression equalterm;
    6381         278 :           bool equaluptillnow=true;
    6382         278 :           std::vector < variable_list >  ::const_iterator auxrename_list_pars=rename_list_pars.begin();
    6383         278 :           std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    6384         278 :           std::vector<action_list>::const_iterator  multiactionwalker=multiActionList.begin();
    6385         945 :           for (stochastic_action_summand_vector::const_iterator walker=action_summands.begin(); walker!=action_summands.end();
    6386             :                ++walker,++multiactionwalker)
    6387             :           {
    6388         667 :             assert(auxrename_list_pars!=rename_list_pars.end());
    6389         667 :             assert(auxrename_list_args!=rename_list_args.end());
    6390        1334 :             const variable_list auxpars= *auxrename_list_pars;
    6391         667 :             ++auxrename_list_pars;
    6392        1334 :             const data_expression_list auxargs= *auxrename_list_args;
    6393         667 :             ++auxrename_list_args;
    6394             :             // f is the fcnt-th argument of the multiactioncount-th action in the list
    6395         667 :             action_list::const_iterator a1=multiactionwalker->begin();
    6396         667 :             for (std::size_t i=1; i<multiactioncount; ++i, ++a1) {};
    6397         667 :             data_expression_list::const_iterator d1=(a1->arguments()).begin();
    6398         667 :             for (std::size_t i=1; i<fcnt; ++i, ++d1) {};
    6399         667 :             f= *d1;
    6400        1334 :             maintain_variables_in_rhs< mutable_map_substitution<> > sigma; 
    6401         667 :             data_expression_list::const_iterator j=auxargs.begin();
    6402         787 :             for (variable_list::const_iterator i=auxpars.begin();
    6403         787 :                  i!=auxpars.end(); ++i, ++j)
    6404             :             {
    6405             :               /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6406         120 :               if (sigma(*i)==*i)  // *i is not assigned in sigma. 
    6407             :               {
    6408         120 :                 sigma[*i]=*j;
    6409         120 :                 std::set<variable> varset=find_free_variables(*j);
    6410             :               }
    6411             :             }
    6412             : 
    6413        1334 :             maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    6414        1334 :             const data_expression auxresult1=replace_variables_capture_avoiding_alt(f,mutable_sigma);
    6415             : 
    6416         667 :             if (equalterm==data_expression()||is_global_variable(equalterm))
    6417             :             {
    6418         278 :               equalterm=auxresult1;
    6419             :             }
    6420             :             else
    6421             :             {
    6422         389 :               if (equaluptillnow)
    6423             :               {
    6424         298 :                 equaluptillnow=((equalterm==auxresult1)||is_global_variable(auxresult1));
    6425             :               }
    6426             :             }
    6427         667 :             auxresult.push_front(auxresult1);
    6428             :           }
    6429         278 :           if (equaluptillnow)
    6430             :           {
    6431          61 :             resultf.push_front(equalterm);
    6432             :           }
    6433             :           else
    6434             :           {
    6435         217 :             if (!options.binary)
    6436             :             {
    6437         386 :               data_expression_list tempauxresult=auxresult;
    6438         193 :               tempauxresult.push_front(data_expression(e.var));
    6439         193 :               resultf.push_front(data_expression(application(
    6440         386 :                                                    find_case_function(e.enumeratedtype_index,f.sort()),
    6441             :                                                    tempauxresult)));
    6442             :             }
    6443             :             else
    6444             :             {
    6445             :               data_expression temp=construct_binary_case_tree(
    6446             :                                      n,
    6447             :                                      resultsum,
    6448             :                                      auxresult,
    6449          48 :                                      f.sort(),
    6450          48 :                                      e);
    6451          24 :               resultf.push_front(temp);
    6452             :             }
    6453             :           }
    6454             :         }
    6455         411 :         a=multiActionList[0].begin();
    6456         411 :         for (std::size_t i=1 ; i<multiactioncount ; ++i,++a) {}
    6457         411 :         resultmultiactionlist.push_front(action(a->label(),resultf));
    6458             :       }
    6459             : 
    6460             :       /* Construct resulttime, the time of the action ... */
    6461             : 
    6462         422 :       equaluptillnow=true;
    6463         422 :       equalterm=data_expression();
    6464         422 :       bool some_summand_has_time=false;
    6465         422 :       bool all_summands_have_time=true;
    6466             : 
    6467             :       // first find out whether there is a summand with explicit time.
    6468        1383 :       for (const stochastic_action_summand& smmnd: action_summands)
    6469             :       {
    6470         961 :         if (smmnd.has_time())
    6471             :         {
    6472          25 :           some_summand_has_time=true;
    6473             :         }
    6474             :         else
    6475             :         {
    6476         936 :           all_summands_have_time=false;
    6477             :         }
    6478             :       }
    6479             : 
    6480         422 :       if (some_summand_has_time)
    6481             :       {
    6482          10 :         variable dummy_time_variable;
    6483           5 :         if (!all_summands_have_time)
    6484             :         {
    6485             :           // Generate a fresh dummy variable, and add it to the summand variables
    6486           0 :           dummy_time_variable=get_fresh_variable("dt",sort_real::real_());
    6487           0 :           resultsum.push_front(dummy_time_variable);
    6488             :         }
    6489           5 :         std::vector < variable_list >::const_iterator auxrename_list_pars=rename_list_pars.begin();
    6490           5 :         std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    6491          10 :         data_expression_list auxresult;
    6492          30 :         for (const stochastic_action_summand& smmnd: action_summands)
    6493             :         {
    6494          25 :           if (smmnd.has_time())
    6495             :           {
    6496          50 :             const data_expression actiontime=smmnd.multi_action().time();
    6497             : 
    6498          25 :             assert(auxrename_list_pars!=rename_list_pars.end());
    6499          25 :             assert(auxrename_list_args!=rename_list_args.end());
    6500          50 :             const variable_list auxpars= *auxrename_list_pars;
    6501          25 :             ++auxrename_list_pars;
    6502          50 :             const data_expression_list auxargs= *auxrename_list_args;
    6503          25 :             ++auxrename_list_args;
    6504             : 
    6505          50 :             maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    6506          25 :             data_expression_list::const_iterator j=auxargs.begin();
    6507          25 :             for (variable_list::const_iterator i=auxpars.begin();
    6508          25 :                  i!=auxpars.end(); ++i, ++j)
    6509             :             {
    6510             :               /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6511           0 :               if (sigma(*i)==*i)   // sigma is not defined for *i.
    6512             :               {
    6513           0 :                 sigma[*i]=*j;
    6514           0 :                 std::set<variable> varset=find_free_variables(*j);
    6515             :               }
    6516             :             }
    6517             : 
    6518          50 :             maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    6519          50 :             const data_expression auxresult1=replace_variables_capture_avoiding_alt(actiontime, mutable_sigma);
    6520          25 :             if (equalterm==data_expression()||is_global_variable(equalterm))
    6521             :             {
    6522           5 :               equalterm=auxresult1;
    6523             :             }
    6524             :             else
    6525             :             {
    6526          20 :               if (equaluptillnow)
    6527             :               {
    6528           5 :                 equaluptillnow=((auxresult1==equalterm)||is_global_variable(auxresult1));
    6529             :               }
    6530             :             }
    6531          25 :             auxresult.push_front(auxresult1);
    6532             :           }
    6533             :           else
    6534             :           {
    6535             :             // this summand does not have time. But some summands have.
    6536           0 :             auxresult.push_front(data_expression(dummy_time_variable));
    6537           0 :             equaluptillnow=false;
    6538             :           }
    6539             :         }
    6540           5 :         if (options.binary==1)
    6541             :         {
    6542           2 :           resulttime=construct_binary_case_tree(n,
    6543           2 :                                                 resultsum,auxresult,sort_real::real_(),e);
    6544             :         }
    6545             :         else
    6546             :         {
    6547           3 :           if (equaluptillnow)
    6548             :           {
    6549           0 :             resulttime=equalterm;
    6550             :           }
    6551             :           else
    6552             :           {
    6553           6 :             data_expression_list tempauxresult=auxresult;
    6554           3 :             tempauxresult.push_front(data_expression(e.var));
    6555           3 :             resulttime=application(
    6556           6 :                          find_case_function(e.enumeratedtype_index,sort_real::real_()),
    6557             :                          tempauxresult);
    6558             :           }
    6559             :         }
    6560             :       }
    6561             : 
    6562             :       /* we construct the resulting distribution --------------------------------------------------------- */
    6563             : 
    6564             : 
    6565         844 :       variable_list resulting_stochastic_variables;
    6566         844 :       std::vector < variable_list > stochastic_rename_list_pars;
    6567         844 :       std::vector < data_expression_list > stochastic_rename_list_args;
    6568         844 :       data_expression resulting_distribution=real_one();
    6569             :       {
    6570         844 :         data_expression_list stochastic_conditionlist;
    6571        1383 :         for (const stochastic_action_summand& smmnd: action_summands)
    6572             :         {
    6573        1922 :           const variable_list stochastic_vars=smmnd.distribution().variables();
    6574         961 :           resulting_stochastic_variables=merge_var(stochastic_vars,resulting_stochastic_variables,
    6575             :                               stochastic_rename_list_pars,stochastic_rename_list_args,stochastic_conditionlist,parameters);
    6576             :         }
    6577             : 
    6578         422 :         std::vector < variable_list >::const_iterator auxrename_list_pars=rename_list_pars.begin();
    6579         422 :         std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    6580             : 
    6581         422 :         std::vector < variable_list >::const_iterator stochastic_auxrename_list_pars=stochastic_rename_list_pars.begin();
    6582         422 :         std::vector < data_expression_list >::const_iterator stochastic_auxrename_list_args=stochastic_rename_list_args.begin();
    6583             : 
    6584         844 :         data_expression_list aux_result;
    6585         844 :         data_expression equalterm;
    6586         422 :         equaluptillnow=1;
    6587        1383 :         for (const stochastic_action_summand& smmnd: action_summands)
    6588             :         {
    6589        1922 :           const data_expression dist=smmnd.distribution().distribution();
    6590        1922 :           const variable_list stochastic_variables=smmnd.distribution().variables();
    6591         961 :           assert(auxrename_list_pars!=rename_list_pars.end());
    6592         961 :           assert(auxrename_list_args!=rename_list_args.end());
    6593         961 :           assert(stochastic_auxrename_list_pars!=stochastic_rename_list_pars.end());
    6594         961 :           assert(stochastic_auxrename_list_args!=stochastic_rename_list_args.end());
    6595             : 
    6596        1922 :           const variable_list auxpars= *auxrename_list_pars;
    6597         961 :           ++auxrename_list_pars;
    6598        1922 :           const data_expression_list auxargs= *auxrename_list_args;
    6599         961 :           ++auxrename_list_args;
    6600        1922 :           const variable_list stochastic_auxpars= *stochastic_auxrename_list_pars;
    6601         961 :           ++stochastic_auxrename_list_pars;
    6602        1922 :           const data_expression_list stochastic_auxargs= *stochastic_auxrename_list_args;
    6603         961 :           ++stochastic_auxrename_list_args;
    6604        1922 :           maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    6605         961 :           data_expression_list::const_iterator j=stochastic_auxargs.begin();
    6606        1262 :           for (variable_list::const_iterator i=stochastic_auxpars.begin();
    6607        1262 :                i!=stochastic_auxpars.end(); ++i, ++j)
    6608             :           {
    6609             :             /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6610         301 :             if (sigma(*i)==*i)  // sigma is not defined for *i.
    6611             :             {
    6612         301 :               sigma[*i]=*j;
    6613         301 :               const std::set<variable> varset=find_free_variables(*j);
    6614             :             }
    6615             :           }
    6616         961 :           j=auxargs.begin();
    6617        1045 :           for (variable_list::const_iterator i=auxpars.begin();
    6618        1045 :                i!=auxpars.end(); ++i, ++j)
    6619             :           {
    6620             :             /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6621          84 :             if (sigma(*i)==*i) // sigma is not defined for *i.
    6622             :             {
    6623          84 :               sigma[*i]=*j;
    6624          84 :               const std::set<variable> varset=find_free_variables(*j);
    6625             :             }
    6626             :           }
    6627        1922 :           maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    6628             : 
    6629        1922 :           const data_expression auxresult1=replace_variables_capture_avoiding_alt(dist,mutable_sigma);
    6630         961 :           if (equalterm==data_expression()||is_global_variable(equalterm))
    6631             :           {
    6632         422 :             equalterm=auxresult1;
    6633             :           }
    6634             :           else
    6635             :           {
    6636         539 :             if (equaluptillnow)
    6637             :             {
    6638         539 :               equaluptillnow=((auxresult1==equalterm)||is_global_variable(auxresult1));
    6639             :             }
    6640             :           }
    6641         961 :           aux_result.push_front(auxresult1);
    6642             :         }
    6643         422 :         if (options.binary)
    6644             :         {
    6645          62 :           resulting_distribution=construct_binary_case_tree(n,
    6646          62 :                           resultsum,aux_result,sort_real::real_(),e);
    6647          62 :           resulting_distribution=lazy::and_(
    6648         124 :                             construct_binary_case_tree(n,
    6649          62 :                                 resultsum,stochastic_conditionlist,sort_bool::bool_(),e),
    6650             :                             resulting_distribution);
    6651             :         }
    6652             :         else
    6653             :         {
    6654         360 :           if (equaluptillnow)
    6655             :           {
    6656         359 :             if (all_equal(stochastic_conditionlist))
    6657             :             {
    6658         359 :               if (stochastic_conditionlist.front()==sort_bool::true_())
    6659             :               {
    6660         359 :                 resulting_distribution=equalterm;
    6661             :               }
    6662             :               else
    6663             :               {
    6664           0 :                 resulting_distribution=real_times_optimized(
    6665           0 :                                                   if_(stochastic_conditionlist.front(),real_one(),real_zero()),
    6666             :                                                   equalterm);
    6667             :               }
    6668             :             }
    6669             :             else
    6670             :             {
    6671           0 :               data_expression_list temp_stochastic_conditionlist=stochastic_conditionlist;
    6672           0 :               temp_stochastic_conditionlist.push_front(data_expression(e.var));
    6673           0 :               resulting_distribution=real_times_optimized(
    6674           0 :                                 if_(application(
    6675           0 :                                       find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6676             :                                       temp_stochastic_conditionlist),
    6677           0 :                                       real_one(),
    6678           0 :                                       real_zero()),
    6679             :                                 equalterm);
    6680             :             }
    6681             :           }
    6682             :           else
    6683             :           {
    6684           2 :             data_expression_list tempauxresult=aux_result;
    6685           1 :             tempauxresult.push_front(data_expression(e.var));
    6686           1 :             resulting_distribution=application(
    6687           2 :                               find_case_function(e.enumeratedtype_index,sort_real::real_()),
    6688             :                               tempauxresult);
    6689           1 :             if (all_equal(stochastic_conditionlist))
    6690             :             {
    6691           0 :               if (stochastic_conditionlist.front()==sort_bool::true_())
    6692             :               {
    6693           0 :                resulting_distribution=real_times_optimized(
    6694           0 :                                                  if_(stochastic_conditionlist.front(),real_one(),real_zero()),
    6695             :                                                  resulting_distribution);
    6696             :               }
    6697             :               else
    6698             :               {
    6699           0 :                resulting_distribution=real_times_optimized(
    6700           0 :                                                  if_(stochastic_conditionlist.front(),real_one(),real_zero()),
    6701             :                                                  resulting_distribution);
    6702             :               }
    6703             :             }
    6704             :             else
    6705             :             {
    6706           2 :              data_expression_list temp_stochastic_conditionlist=stochastic_conditionlist;
    6707           1 :              temp_stochastic_conditionlist.push_front(data_expression(e.var));
    6708           1 :              resulting_distribution=real_times_optimized(
    6709           2 :                               if_(application(
    6710           2 :                                      find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6711             :                                      temp_stochastic_conditionlist),
    6712           2 :                                   real_one(),
    6713           2 :                                   real_zero()),
    6714             :                               resulting_distribution);
    6715             :             }
    6716             :           }
    6717             :         }
    6718             :       }
    6719             :       /* now we construct the arguments of the invoked -----------------------------------------------------
    6720             :          process, i.e. the new function g */
    6721         422 :       std::size_t fcnt=0;
    6722         844 :       data_expression_list resultnextstate;
    6723             : 
    6724        1438 :       for (variable_list::const_iterator var_it=parameters.begin(); var_it!=parameters.end(); ++var_it)
    6725             :       {
    6726        1016 :         equalterm=data_expression();
    6727        1016 :         equaluptillnow=1;
    6728        1016 :         std::vector < variable_list >::const_iterator auxrename_list_pars=rename_list_pars.begin();
    6729        1016 :         std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    6730        1016 :         std::vector < variable_list >::const_iterator stochastic_auxrename_list_pars=stochastic_rename_list_pars.begin();
    6731        1016 :         std::vector < data_expression_list >::const_iterator stochastic_auxrename_list_args=stochastic_rename_list_args.begin();
    6732        2032 :         data_expression_list auxresult;
    6733        3467 :         for (const stochastic_action_summand& smmnd: action_summands)
    6734             :         {
    6735        4902 :           const assignment_list nextstate=smmnd.assignments();
    6736        2451 :           assert(auxrename_list_pars!=rename_list_pars.end());
    6737        2451 :           assert(auxrename_list_args!=rename_list_args.end());
    6738        2451 :           assert(stochastic_auxrename_list_pars!=stochastic_rename_list_pars.end());
    6739        2451 :           assert(stochastic_auxrename_list_args!=stochastic_rename_list_args.end());
    6740        4902 :           const variable_list auxpars= *auxrename_list_pars;
    6741        2451 :           ++auxrename_list_pars;
    6742        4902 :           const data_expression_list auxargs= *auxrename_list_args;
    6743        2451 :           ++auxrename_list_args;
    6744        4902 :           const variable_list stochastic_auxpars= *stochastic_auxrename_list_pars;
    6745        2451 :           ++stochastic_auxrename_list_pars;
    6746        4902 :           const data_expression_list stochastic_auxargs= *stochastic_auxrename_list_args;
    6747        2451 :           ++stochastic_auxrename_list_args;
    6748             : 
    6749        4902 :           data_expression nextstateparameter;
    6750        2451 :           nextstateparameter=getRHSassignment(*var_it,nextstate);
    6751             : 
    6752        4902 :           maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    6753        2451 :           data_expression_list::const_iterator j=stochastic_auxargs.begin();
    6754        5136 :           for (variable_list::const_iterator i=stochastic_auxpars.begin();
    6755        5136 :                  i!=stochastic_auxpars.end(); ++i, ++j)
    6756             :           {
    6757             :             /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6758        2685 :             if (sigma(*i)==*i)  // sigma is not defined for *i.
    6759             :             {
    6760        2685 :               sigma[*i]=*j;
    6761        2685 :               std::set<variable> varset=find_free_variables(*j);
    6762             :             }
    6763             :           }
    6764        2451 :           j=auxargs.begin();
    6765        2655 :           for (variable_list::const_iterator i=auxpars.begin();
    6766        2655 :                  i!=auxpars.end(); ++i, ++j)
    6767             :           {
    6768             :             /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6769         204 :             if (sigma(*i)==*i)  // sigma is not defined for *i. 
    6770             :             {
    6771         204 :               sigma[*i]=*j;
    6772         204 :               std::set<variable> varset=find_free_variables(*j);
    6773             :             }
    6774             :           }
    6775             : 
    6776        4902 :           maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    6777        4902 :           data_expression auxresult1=replace_variables_capture_avoiding_alt(nextstateparameter, mutable_sigma);
    6778        2451 :           if (equalterm==data_expression()) // ||is_global_variable(equalterm)) Adding this last part leads to smaller case functions,
    6779             :                                             // but bigger and less structured state spaces, as parameters are less often put to default
    6780             :                                             // values. Constant elimination can less often be applied as constant eliminiation does not
    6781             :                                             // have subtle knowledge of case functions.
    6782             :           {
    6783        1016 :             equalterm=auxresult1;
    6784             :           }
    6785        1435 :           else if (equaluptillnow)
    6786             :           {
    6787             :             // set equaluptillnow if the arguments of this case function are all equal,
    6788             :             // or are all equal to global variables. Setting a case function
    6789             :             // C(e,v,dc1) to the value v, where dc1 is a global variable can result in
    6790             :             // the growth of the state space, as dc1 is not set to a default value, but
    6791             :             // keeps the value v.
    6792        3583 :             equaluptillnow=((equalterm==auxresult1)||
    6793        3945 :                                ((equalterm==data_expression()||is_global_variable(equalterm)) &&
    6794         201 :                                                     is_global_variable(auxresult1)));
    6795             :           }
    6796             : 
    6797        2451 :           auxresult.push_front(auxresult1);
    6798             :         }
    6799        1016 :         if (equaluptillnow)
    6800             :         {
    6801         347 :           resultnextstate.push_front(equalterm);
    6802             :         }
    6803             :         else
    6804             :         {
    6805         669 :           if (!options.binary)
    6806             :           {
    6807        1260 :             data_expression_list tempauxresult=auxresult;
    6808         630 :             tempauxresult.push_front(data_expression(e.var));
    6809         630 :             resultnextstate.push_front(
    6810        1260 :                          data_expression(application(
    6811        1890 :                                            find_case_function(
    6812         630 :                                              e.enumeratedtype_index,
    6813             :                                              var_it->sort()),
    6814             :                                            tempauxresult)));
    6815             :           }
    6816             :           else
    6817             :           {
    6818             :             data_expression temp=construct_binary_case_tree(
    6819             :                                    n,
    6820             :                                    resultsum,
    6821             :                                    auxresult,
    6822             :                                    var_it->sort(),
    6823          78 :                                    e);
    6824          39 :             resultnextstate.push_front(temp);
    6825             :           }
    6826             :         }
    6827        1016 :         fcnt++;
    6828             :       }
    6829             :       /* Now turn *resultg around */
    6830         422 :       resultnextstate=reverse(resultnextstate);
    6831             :       /* The list of arguments in nextstate are now in a sequential form, and
    6832             :            must be transformed back to a list of assignments */
    6833         844 :       const assignment_list final_resultnextstate=make_assignment_list(parameters,resultnextstate);
    6834             :       return stochastic_action_summand(
    6835             :                             resultsum,
    6836             :                             resultcondition,
    6837         844 :                             some_summand_has_time?multi_action(resultmultiactionlist,resulttime):multi_action(resultmultiactionlist),
    6838             :                             final_resultnextstate,
    6839        1688 :                             stochastic_distribution(resulting_stochastic_variables,resulting_distribution));
    6840             :     }
    6841             : 
    6842           1 :     deadlock_summand collect_sum_arg_arg_cond(
    6843             :       const enumtype& e,
    6844             :       std::size_t n,
    6845             :       const deadlock_summand_vector& deadlock_summands,
    6846             :       const variable_list& parameters)
    6847             :     {
    6848             :       /* This function gets a list of summands, with
    6849             :          the same multiaction and time
    6850             :          status. It yields a single clustered summand
    6851             :          by introducing an auxiliary sum operator, with
    6852             :          a variable of enumtype. In case binary is used,
    6853             :          a sequence of variables are introduced of sort Bool */
    6854             : 
    6855           2 :       variable_list resultsum;
    6856           2 :       data_expression resultcondition;
    6857           2 :       action_list resultmultiaction;
    6858           2 :       data_expression resulttime;
    6859             : 
    6860           2 :       std::vector < variable_list > rename_list_pars;
    6861           2 :       std::vector < data_expression_list > rename_list_args;
    6862             :       /* rename list is a list of pairs of variable and term lists */
    6863           2 :       data_expression_list conditionlist;
    6864           2 :       data_expression binarysumcondition;
    6865           1 :       int equaluptillnow=1;
    6866             : 
    6867           7 :       for (const deadlock_summand& smmnd: deadlock_summands)
    6868             :       {
    6869          12 :         const variable_list sumvars=smmnd.summation_variables();
    6870           6 :         resultsum=merge_var(sumvars,resultsum,rename_list_pars,rename_list_args,conditionlist,parameters);
    6871             :       }
    6872             : 
    6873           1 :       if (options.binary)
    6874             :       {
    6875           0 :         resultsum=make_binary_sums(
    6876             :                     n,
    6877           0 :                     enumeratedtypes[e.enumeratedtype_index].sortId,
    6878             :                     binarysumcondition,
    6879             :                     resultsum);
    6880             :       }
    6881             :       else
    6882             :       {
    6883           1 :         resultsum.push_front(e.var);
    6884             :       }
    6885             : 
    6886             :       /* we construct the resulting condition */
    6887           2 :       data_expression_list auxresult;
    6888           1 :       std::vector < variable_list >::const_iterator auxrename_list_pars=rename_list_pars.begin();
    6889           1 :       std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    6890             : 
    6891           2 :       data_expression equalterm;
    6892           1 :       equaluptillnow=1;
    6893           7 :       for (const deadlock_summand& smmnd: deadlock_summands)
    6894             :       {
    6895           6 :         const data_expression& condition=smmnd.condition();
    6896           6 :         assert(auxrename_list_pars!=rename_list_pars.end());
    6897           6 :         assert(auxrename_list_args!=rename_list_args.end());
    6898          12 :         const variable_list auxpars= *auxrename_list_pars;
    6899           6 :         ++auxrename_list_pars;
    6900          12 :         const data_expression_list auxargs= *auxrename_list_args;
    6901           6 :         ++auxrename_list_args;
    6902          12 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    6903           6 :         data_expression_list::const_iterator j=auxargs.begin();
    6904          12 :         for (variable_list::const_iterator i=auxpars.begin();
    6905          12 :              i!=auxpars.end(); ++i, ++j)
    6906             :         {
    6907             :           /* Substitutions are carried out from left to right. The first applicable substitution counts */
    6908           6 :           if (sigma(*i)== *i) // sigma is not defined for *i. 
    6909             :           {
    6910           6 :             sigma[*i]=*j;
    6911           6 :             std::set<variable> varset=find_free_variables(*j);
    6912             :           }
    6913             :         }
    6914             : 
    6915          12 :         maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    6916          12 :         const data_expression auxresult1=replace_variables_capture_avoiding_alt(condition, mutable_sigma);
    6917           6 :         if (equalterm==data_expression()||is_global_variable(equalterm))
    6918             :         {
    6919           1 :           equalterm=auxresult1;
    6920             :         }
    6921             :         else
    6922             :         {
    6923           5 :           if (equaluptillnow)
    6924             :           {
    6925           1 :             equaluptillnow=((auxresult1==equalterm)||is_global_variable(auxresult1));
    6926             :           }
    6927             :         }
    6928           6 :         auxresult.push_front(auxresult1);
    6929             :       }
    6930           1 :       if (options.binary)
    6931             :       {
    6932           0 :         resultcondition=construct_binary_case_tree(n,
    6933           0 :                         resultsum,auxresult,sort_bool::bool_(),e);
    6934           0 :         resultcondition=lazy::and_(binarysumcondition,resultcondition);
    6935           0 :         resultcondition=lazy::and_(
    6936           0 :                           construct_binary_case_tree(n,
    6937           0 :                               resultsum,conditionlist,sort_bool::bool_(),e),
    6938             :                           resultcondition);
    6939             :       }
    6940             :       else
    6941             :       {
    6942           1 :         if (equaluptillnow)
    6943             :         {
    6944           0 :           if (all_equal(conditionlist))
    6945             :           {
    6946           0 :             resultcondition=lazy::and_(conditionlist.front(),equalterm);
    6947             :           }
    6948             :           else
    6949             :           {
    6950           0 :             data_expression_list tempconditionlist=conditionlist;
    6951           0 :             tempconditionlist.push_front(data_expression(e.var));
    6952           0 :             resultcondition=lazy::and_(
    6953           0 :                             application(
    6954           0 :                               find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6955             :                               tempconditionlist),
    6956             :                             equalterm);
    6957             :           }
    6958             :         }
    6959             :         else
    6960             :         {
    6961           2 :           data_expression_list tempauxresult=auxresult;
    6962           1 :           tempauxresult.push_front(data_expression(e.var));
    6963           1 :           resultcondition=application(
    6964           2 :                             find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6965             :                             tempauxresult);
    6966           1 :           if (all_equal(conditionlist))
    6967             :           {
    6968           0 :             resultcondition=lazy::and_(conditionlist.front(),resultcondition);
    6969             :           }
    6970             :           else
    6971             :           {
    6972           2 :             data_expression_list tempconditionlist=conditionlist;
    6973           1 :             tempconditionlist.push_front(data_expression(e.var));
    6974           1 :             resultcondition=lazy::and_(
    6975           2 :                             application(
    6976           2 :                               find_case_function(e.enumeratedtype_index,sort_bool::bool_()),
    6977             :                               tempconditionlist),
    6978             :                             resultcondition);
    6979             :           }
    6980             :         }
    6981             :       }
    6982             : 
    6983             :       /* now we construct the arguments of the action */
    6984             :       /* First we collect all multi-actions in a separate vector
    6985             :          of multiactions */
    6986           2 :       std::vector < action_list > multiActionList;
    6987             : 
    6988           2 :       action_list resultmultiactionlist;
    6989             : 
    6990             :       /* Construct resulttime, the time of the action ... */
    6991             : 
    6992           1 :       equaluptillnow=true;
    6993           1 :       equalterm=data_expression();
    6994           1 :       bool some_summand_has_time=false;
    6995           1 :       bool all_summands_have_time=true;
    6996             : 
    6997             :       // first find out whether there is a summand with explicit time.
    6998           7 :       for (const deadlock_summand& smmnd: deadlock_summands)
    6999             :       {
    7000           6 :         if (smmnd.deadlock().has_time())
    7001             :         {
    7002           0 :           some_summand_has_time=true;
    7003             :         }
    7004             :         else
    7005             :         {
    7006           6 :           all_summands_have_time=false;
    7007             :         }
    7008             :       }
    7009             : 
    7010           1 :       if ((some_summand_has_time))
    7011             :       {
    7012           0 :         variable dummy_time_variable;
    7013           0 :         if (!all_summands_have_time)
    7014             :         {
    7015             :           // Generate a fresh dummy variable, and add it to the summand variables
    7016           0 :           dummy_time_variable=get_fresh_variable("dt",sort_real::real_());
    7017           0 :           resultsum.push_front(dummy_time_variable);
    7018             :         }
    7019           0 :         std::vector < variable_list >::const_iterator auxrename_list_pars=rename_list_pars.begin();
    7020           0 :         std::vector < data_expression_list >::const_iterator auxrename_list_args=rename_list_args.begin();
    7021           0 :         data_expression_list auxresult;
    7022           0 :         for (const deadlock_summand& smmnd: deadlock_summands)
    7023             :         {
    7024           0 :           if (smmnd.deadlock().has_time())
    7025             :           {
    7026           0 :             const data_expression actiontime=smmnd.deadlock().time();
    7027             : 
    7028           0 :             assert(auxrename_list_pars!=rename_list_pars.end());
    7029           0 :             assert(auxrename_list_args!=rename_list_args.end());
    7030           0 :             const variable_list auxpars= *auxrename_list_pars;
    7031           0 :             ++auxrename_list_pars;
    7032           0 :             const data_expression_list auxargs= *auxrename_list_args;
    7033           0 :             ++auxrename_list_args;
    7034             : 
    7035           0 :             maintain_variables_in_rhs< mutable_map_substitution<> > sigma; 
    7036           0 :             data_expression_list::const_iterator j=auxargs.begin();
    7037           0 :             for (variable_list::const_iterator i=auxpars.begin();
    7038           0 :                  i!=auxpars.end(); ++i, ++j)
    7039             :             {
    7040             :               /* Substitutions are carried out from left to right. The first applicable substitution counts */
    7041           0 :               if (sigma(*i)==*i)  // sigma is not defined for *i.
    7042             :               {
    7043           0 :                 sigma[*i]=*j;
    7044           0 :                 std::set<variable> varset=find_free_variables(*j);
    7045             :               }
    7046             :             }
    7047             : 
    7048           0 :             maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    7049           0 :             const data_expression auxresult1=replace_variables_capture_avoiding_alt(actiontime, mutable_sigma);
    7050           0 :             if (equalterm==data_expression()||is_global_variable(equalterm))
    7051             :             {
    7052           0 :               equalterm=auxresult1;
    7053             :             }
    7054             :             else
    7055             :             {
    7056           0 :               if (equaluptillnow)
    7057             :               {
    7058           0 :                 equaluptillnow=((auxresult1==equalterm)||is_global_variable(auxresult1));
    7059             :               }
    7060             :             }
    7061           0 :             auxresult.push_front(auxresult1);
    7062             :           }
    7063             :           else
    7064             :           {
    7065             :             // this summand does not have time. But some summands have.
    7066           0 :             auxresult.push_front(data_expression(dummy_time_variable));
    7067           0 :             equaluptillnow=false;
    7068             :           }
    7069             :         }
    7070           0 :         if (options.binary==1)
    7071             :         {
    7072           0 :           resulttime=construct_binary_case_tree(n,
    7073           0 :                                                 resultsum,auxresult,sort_real::real_(),e);
    7074             :         }
    7075             :         else
    7076             :         {
    7077           0 :           if (equaluptillnow)
    7078             :           {
    7079           0 :             resulttime=equalterm;
    7080             :           }
    7081             :           else
    7082             :           {
    7083           0 :             data_expression_list tempauxresult=auxresult;
    7084           0 :             tempauxresult.push_front(data_expression(e.var));
    7085           0 :             resulttime=application(
    7086           0 :                          find_case_function(e.enumeratedtype_index,sort_real::real_()),
    7087             :                          tempauxresult);
    7088             :           }
    7089             :         }
    7090             :       }
    7091             : 
    7092             :       return deadlock_summand(resultsum,
    7093             :                               resultcondition,
    7094           2 :                               some_summand_has_time?deadlock(resulttime):deadlock());
    7095             :     }
    7096             : 
    7097         422 :     sort_expression_list getActionSorts(const action_list& actionlist)
    7098             :     {
    7099         422 :       sort_expression_list resultsorts;
    7100             : 
    7101         833 :       for (action_list::const_iterator i=actionlist.begin(); i!=actionlist.end(); ++i)
    7102             :       {
    7103         411 :         resultsorts=i->label().sorts()+resultsorts;
    7104             :       }
    7105         422 :       return resultsorts;
    7106             :     }
    7107             : 
    7108         900 :     void cluster_actions(
    7109             :       stochastic_action_summand_vector& action_summands,
    7110             :       deadlock_summand_vector& deadlock_summands,
    7111             :       const variable_list& pars)
    7112             :     {
    7113             :       {
    7114             :         /* We cluster first the action summands with the action
    7115             :             occurring in the first summand of sums.
    7116             :             These summands are first stored in w1. */
    7117             : 
    7118        1800 :         stochastic_action_summand_vector result;
    7119        1800 :         stochastic_action_summand_vector reducible_sumlist=action_summands;
    7120             : 
    7121        3275 :         for (stochastic_action_summand_vector::const_iterator i=action_summands.begin() ; i!=action_summands.end() ; ++i)
    7122             :         {
    7123        4750 :           const stochastic_action_summand summand1=*i;
    7124             : 
    7125        4750 :           stochastic_action_summand_vector w1;
    7126        4750 :           stochastic_action_summand_vector w2;
    7127        7674 :           for (stochastic_action_summand_vector::const_iterator w3=reducible_sumlist.begin(); w3!=reducible_sumlist.end(); ++w3)
    7128             :           {
    7129       10598 :             const stochastic_action_summand summand2=*w3;
    7130        5299 :             if (summandsCanBeClustered(summand1,summand2))
    7131             :             {
    7132        2375 :               w1.push_back(summand2);
    7133             :             }
    7134             :             else
    7135             :             {
    7136        2924 :               w2.push_back(summand2);
    7137             :             }
    7138             :           }
    7139        2375 :           reducible_sumlist.swap(w2);
    7140             : 
    7141             :           /* In w1 we now find all the summands labelled with
    7142             :              similar multiactions, actiontime and terminationstatus.
    7143             :              We must now construct its clustered form. */
    7144        2375 :           std::size_t n=w1.size();
    7145             : 
    7146        2375 :           if (n>0)
    7147             :           {
    7148        1836 :             if (n>1)
    7149             :             {
    7150         844 :               const action_list multiaction=w1.front().multi_action().actions();
    7151         844 :               sort_expression_list actionsorts;
    7152         422 :               actionsorts=getActionSorts(multiaction);
    7153             : 
    7154         844 :               const enumtype enumeratedtype_(options.binary?2:n,actionsorts,get_sorts(pars),*this);
    7155             : 
    7156         422 :               result.push_back(collect_sum_arg_arg_cond(enumeratedtype_,n,w1,pars));
    7157             :             }
    7158             :             else
    7159             :             {
    7160             :               // result=w1 + result;
    7161        2829 :               for(stochastic_action_summand_vector::const_iterator i=result.begin(); i!=result.end(); ++i)
    7162             :               {
    7163        1415 :                 w1.push_back(*i);
    7164             :               }
    7165        1414 :               w1.swap(result);
    7166             :             }
    7167             :           }
    7168             :         }
    7169         900 :         action_summands=result;
    7170             :       }
    7171             : 
    7172             :       // Now the delta summands are clustered.
    7173        1800 :       deadlock_summand_vector result;
    7174        1800 :       deadlock_summand_vector reducible_sumlist=deadlock_summands;
    7175             : 
    7176        1286 :       for (const deadlock_summand& summand1: deadlock_summands)
    7177             :       {
    7178         772 :         deadlock_summand_vector w1;
    7179         772 :         deadlock_summand_vector w2;
    7180         772 :         for (const deadlock_summand& summand2: reducible_sumlist)
    7181             :         {
    7182         386 :           if (summand1.deadlock().has_time()==summand2.deadlock().has_time())
    7183             :           {
    7184         386 :             w1.push_back(summand2);
    7185             :           }
    7186             :           else
    7187             :           {
    7188           0 :             w2.push_back(summand2);
    7189             :           }
    7190             :         }
    7191         386 :         reducible_sumlist.swap(w2);
    7192             : 
    7193             :         /* In w1 we now find all the summands labelled with
    7194             :            either no or an action time.
    7195             :            We must now construct its clustered form. */
    7196         386 :         const std::size_t n=w1.size();
    7197             : 
    7198         386 :         if (n>0)
    7199             :         {
    7200         381 :           if (n>1)
    7201             :           {
    7202           2 :             sort_expression_list actionsorts;
    7203             : 
    7204           2 :             const enumtype enumeratedtype_(options.binary?2:n,actionsorts,get_sorts(pars),*this);
    7205             : 
    7206           1 :             result.push_back(collect_sum_arg_arg_cond(enumeratedtype_,n,w1,pars));
    7207             :           }
    7208             :           else
    7209             :           {
    7210         380 :             assert(w1.size()==1);
    7211         380 :             result.push_back(w1.front());
    7212             :           }
    7213             :         }
    7214             :       }
    7215         900 :       assert(reducible_sumlist.empty());
    7216         900 :       deadlock_summands.swap(result);
    7217         900 :     }
    7218             : 
    7219             : 
    7220             :     /**************** GENERaTE LPEpCRL **********************************/
    7221             : 
    7222             : 
    7223             :     /* The variable regular indicates that we are interested in generating
    7224             :        a LPE assuming the pCRL term under consideration is regular */
    7225             : 
    7226        1016 :     void generateLPEpCRL(stochastic_action_summand_vector& action_summands,
    7227             :                          deadlock_summand_vector& deadlock_summands,
    7228             :                          const process_identifier& procId,
    7229             :                          const bool containstime,
    7230             :                          const bool regular,
    7231             :                          variable_list& parameters,
    7232             :                          data_expression_list& init,
    7233             :                          stochastic_distribution& initial_stochastic_distribution)
    7234             :     /* A pair of initial state and linear process must be extracted
    7235             :        from the underlying GNF */
    7236             :     {
    7237             :       // We use action_summands and deadlock_summands as an output.
    7238        1016 :       assert(action_summands.size()==0);
    7239        1016 :       assert(deadlock_summands.size()==0);
    7240             : 
    7241        1016 :       bool singlecontrolstate=false;
    7242        2032 :       std::set< process_identifier > reachable_process_identifiers;
    7243        1016 :       make_pCRL_procs(procId, reachable_process_identifiers);
    7244             : 
    7245             :       /* now reachable process identifiers contains a list of all process id's in this pCRL process.
    7246             :          Some of these processes have equal parameter lists and right hand sides. A typical example is
    7247             :          P1 = a.P2, P3=a.P4, P2=b.Q, P4=b.Q. This reduces to P1 = a.P2, P2 = b.Q.
    7248             :          We reduce the set of process_identifiers in reachable_process_identifiers and perform the
    7249             :          appropriate substitution in the right hand side.
    7250             :          The result is a map from process_identifiers to adapted process bodies.
    7251             :       */
    7252             :       const std::set< process_identifier > reduced_set_of_process_identifiers =
    7253        2032 :           minimize_set_of_reachable_process_identifiers(reachable_process_identifiers,procId);
    7254             : 
    7255             :       /* The equations can still contain stochastic operators that occur before the first action.
    7256             :          We translate the equations such that the stochastic operators do not occur in front anymore.
    7257             :          Moving the stochastic operators to the front means that the number of parameters of each
    7258             :          process can increase. In this case we introduce a new process identifiers. The resulting
    7259             :          ids of processes occur in stochastic_normalized_process_identifiers. */
    7260             : 
    7261        2032 :       process_identifier initial_proc_id=procId;  // the initial process id may be renamed.
    7262             :       const std::set< process_identifier > stochastic_normalized_process_identifiers =
    7263        2032 :                   remove_stochastic_operators_from_front(reduced_set_of_process_identifiers, initial_proc_id, initial_stochastic_distribution);
    7264             : 
    7265             :       /* collect the parameters, but assume that variables
    7266             :          have a unique sort */
    7267        1016 :       if (stochastic_normalized_process_identifiers.size()==1)
    7268             :       {
    7269         387 :         singlecontrolstate=true;
    7270             :       }
    7271        1016 :       parameters=collectparameterlist(stochastic_normalized_process_identifiers);
    7272             : 
    7273        1016 :       if ((!regular)||((!singlecontrolstate) && (options.newstate) && (!options.binary)))
    7274             :       {
    7275         232 :         declare_control_state(stochastic_normalized_process_identifiers);
    7276             :       }
    7277        2032 :       stacklisttype stack(parameters,*this,regular,stochastic_normalized_process_identifiers,singlecontrolstate);
    7278             : 
    7279        1016 :       if (regular)
    7280             :       {
    7281         784 :         if ((options.binary) && (options.newstate))
    7282             :         {
    7283           0 :           parameters=stack.parameters;
    7284           0 :           if (!singlecontrolstate)
    7285             :           {
    7286           0 :             parameters=reverse(stack.booleanStateVariables) + parameters;
    7287             :           }
    7288             :         }
    7289             :         else  /* !binary or oldstate */
    7290             :         {
    7291        1568 :           variable_list tempparameters=stack.parameters;
    7292         784 :           tempparameters.push_front(stack.stackvar);
    7293         784 :           parameters=
    7294         784 :             ((!singlecontrolstate)?tempparameters:stack.parameters);
    7295             :         }
    7296             :       }
    7297             :       else /* not regular, use a stack */
    7298             :       {
    7299         232 :         parameters = variable_list({ stack.stackvar });
    7300             :       }
    7301        1016 :       init=make_initialstate(initial_proc_id,stack,stochastic_normalized_process_identifiers,regular,singlecontrolstate,initial_stochastic_distribution);
    7302        1016 :       assert(init.size()==parameters.size());
    7303        1016 :       collectsumlist(action_summands,deadlock_summands,stochastic_normalized_process_identifiers,parameters,stack,regular,singlecontrolstate);
    7304             : 
    7305        1016 :       if (!options.no_intermediate_cluster)
    7306             :       {
    7307         900 :         cluster_actions(action_summands,deadlock_summands,parameters);
    7308             :       }
    7309             : 
    7310        1016 :       if ((!containstime) || options.ignore_time)
    7311             :       {
    7312             :         /* We add a delta summand to each process, if the flag
    7313             :            ignore_time is set, or if the process does not contain any
    7314             :            explicit reference to time. This affects the behaviour of each
    7315             :            process in the sense that each process can idle
    7316             :            indefinitely. It has the advantage that large numbers
    7317             :            numbers of timed delta summands are subsumed by
    7318             :            this delta. As the removal of timed delta's
    7319             :            is time consuming in the linearisation, the use
    7320             :            of this flag, can speed up linearisation considerably */
    7321         694 :         deadlock_summands.push_back(deadlock_summand(variable_list(),sort_bool::true_(),deadlock()));
    7322             :       }
    7323        1016 :     }
    7324             : 
    7325             : 
    7326             :     /**************** hiding *****************************************/
    7327             : 
    7328         299 :     action_list hide_(const identifier_string_list& hidelist, const action_list& multiaction)
    7329             :     {
    7330         598 :       action_list resultactionlist;
    7331             : 
    7332        1177 :       for (const action& a: multiaction)
    7333             :       {
    7334         878 :         if (std::find(hidelist.begin(),hidelist.end(),a.label().name())==hidelist.end())
    7335             :         {
    7336         686 :           resultactionlist.push_front(a);
    7337             :         }
    7338             :       }
    7339             : 
    7340             :       /* reverse the actionlist to maintain the ordering */
    7341         598 :       return reverse(resultactionlist);
    7342             :     }
    7343             : 
    7344          18 :     void hidecomposition(const identifier_string_list& hidelist, stochastic_action_summand_vector& action_summands)
    7345             :     {
    7346         317 :       for (stochastic_action_summand_vector::iterator i=action_summands.begin(); i!=action_summands.end() ; ++i)
    7347             :       {
    7348         598 :         const action_list acts=hide_(hidelist,i->multi_action().actions());
    7349         299 :         *i=stochastic_action_summand(i->summation_variables(),
    7350         299 :                           i->condition(),
    7351         598 :                           i->has_time()?multi_action(acts,i->multi_action().time()):multi_action(acts),
    7352         299 :                           i->assignments(),
    7353         299 :                           i->distribution());
    7354             :       }
    7355          18 :     }
    7356             : 
    7357             :     /**************** allow/block *************************************/
    7358             : 
    7359     1944282 :     bool implies_condition(const data_expression& c1, const data_expression& c2)
    7360             :     {
    7361     1944282 :       if (c2==sort_bool::true_())
    7362             :       {
    7363        9542 :         return true;
    7364             :       }
    7365             : 
    7366     1934740 :       if (c1==sort_bool::false_())
    7367             :       {
    7368           0 :         return true;
    7369             :       }
    7370             : 
    7371     1934740 :       if (c1==sort_bool::true_())
    7372             :       {
    7373       79196 :         return false;
    7374             :       }
    7375             : 
    7376     1855544 :       if (c2==sort_bool::false_())
    7377             :       {
    7378           0 :         return false;
    7379             :       }
    7380             : 
    7381     1855544 :       if (c1==c2)
    7382             :       {
    7383      101600 :         return true;
    7384             :       }
    7385             : 
    7386             :       /* Dealing with the conjunctions (&&) first and then the disjunctions (||)
    7387             :          yields a 10-fold speed increase compared to the case where first the
    7388             :          || occur, and then the &&. This result was measured on the alternating
    7389             :          bit protocol, with --regular. */
    7390             : 
    7391     1753944 :       if (sort_bool::is_and_application(c2))
    7392             :       {
    7393      290052 :         return implies_condition(c1,data::binary_left(application(c2))) &&
    7394      177125 :                implies_condition(c1,data::binary_right(application(c2)));
    7395             :       }
    7396             : 
    7397     1641017 :       if (sort_bool::is_or_application(c1))
    7398             :       {
    7399       26878 :         return implies_condition(data::binary_left(application(c1)),c2) &&
    7400       13600 :                implies_condition(data::binary_right(application(c1)),c2);
    7401             :       }
    7402             : 
    7403     1627739 :       if (sort_bool::is_and_application(c1))
    7404             :       {
    7405     2697776 :         return implies_condition(data::binary_left(application(c1)),c2) ||
    7406     1955070 :                implies_condition(data::binary_right(application(c1)),c2);
    7407             :       }
    7408             : 
    7409      885033 :       if (sort_bool::is_or_application(c2))
    7410             :       {
    7411        4382 :         return implies_condition(c1,data::binary_left(application(c2))) ||
    7412        3230 :                implies_condition(c1,data::binary_right(application(c2)));
    7413             :       }
    7414             : 
    7415      883881 :       return false;
    7416             :     }
    7417             : 
    7418       80636 :     void insert_timed_delta_summand(
    7419             :       const stochastic_action_summand_vector& action_summands,
    7420             :       deadlock_summand_vector& deadlock_summands,
    7421             :       const deadlock_summand& s)
    7422             :     {
    7423       82625 :       deadlock_summand_vector result;
    7424             : 
    7425             :       // const variable_list sumvars=s.summation_variables();
    7426       80636 :       const data_expression& cond=s.condition();
    7427       82625 :       const data_expression actiontime=s.deadlock().time();
    7428             : 
    7429             :       // First check whether the delta summand is subsumed by an action summands.
    7430      438633 :       for (const stochastic_action_summand& as: action_summands)
    7431             :       {
    7432      785447 :         const data_expression cond1=as.condition();
    7433     1282350 :         if ((!options.ignore_time) &&
    7434      856320 :             ((actiontime==as.multi_action().time()) || (!as.multi_action().has_time())) &&
    7435      422296 :             (implies_condition(cond,cond1)))
    7436             :         {
    7437             :           /* De delta summand is subsumed by action summand as. So, it does not
    7438             :              have to be added. */
    7439             : 
    7440       69453 :           return;
    7441             :         }
    7442             :       }
    7443             : 
    7444       13430 :       for (deadlock_summand_vector::iterator i=deadlock_summands.begin(); i!=deadlock_summands.end(); ++i)
    7445             :       {
    7446       13688 :         const deadlock_summand smmnd=*i;
    7447       13688 :         const data_expression cond1=i->condition();
    7448       34323 :         if ((!options.ignore_time) &&
    7449       23033 :             ((actiontime==i->deadlock().time()) || (!i->deadlock().has_time())) &&
    7450       10523 :             (implies_condition(cond,cond1)))
    7451             :         {
    7452             :           /* put the summand that was effective in removing
    7453             :              this delta summand to the front, such that it
    7454             :              is encountered early later on, removing a next
    7455             :              delta summand */
    7456             : 
    7457        9194 :           copy(i,deadlock_summands.end(),back_inserter(result));
    7458        9194 :           deadlock_summands.swap(result);
    7459        9194 :           return;
    7460             :         }
    7461        4729 :         if (((options.ignore_time)||
    7462        5234 :              (((actiontime==smmnd.deadlock().time())|| (!s.deadlock().has_time())) &&
    7463        1919 :               (implies_condition(cond1,cond)))))
    7464             :         {
    7465             :           /* do not add summand to result, as it is superseded by s */
    7466             :         }
    7467             :         else
    7468             :         {
    7469        2012 :           result.push_back(smmnd);
    7470             :         }
    7471             :       }
    7472             : 
    7473        1989 :       result.push_back(s);
    7474        1989 :       deadlock_summands.swap(result);
    7475             :     }
    7476             : 
    7477          89 :     static action_name_multiset_list sort_multi_action_labels(const action_name_multiset_list& l)
    7478             :     {
    7479         487 :       return action_name_multiset_list(l.begin(),l.end(),[](const action_name_multiset& al){ return sort_action_labels(al); });
    7480             :     }
    7481             : 
    7482             :     /// \brief determine whether the multiaction has the same labels as the allow action,
    7483             :     //         in which case true is delivered. If multiaction is the action Terminate,
    7484             :     //         then true is also returned.
    7485             : 
    7486      258256 :     bool allowsingleaction(const action_name_multiset& allowaction,
    7487             :                            const action_list& multiaction)
    7488             :     {
    7489             :       /* The special cases where multiaction==tau and multiaction=={ Terminated } must have been
    7490             :          dealt with separately. */
    7491      258256 :       assert(multiaction.size()!=0 && multiaction != action_list({ terminationAction }));
    7492             : 
    7493      258256 :       const identifier_string_list& names=allowaction.names();
    7494      258256 :       identifier_string_list::const_iterator i=names.begin();
    7495             : 
    7496      281131 :       for (action_list::const_iterator walker=multiaction.begin();
    7497      281131 :            walker!=multiaction.end(); ++walker,++i)
    7498             :       {
    7499      280570 :         if (i==names.end())
    7500             :         {
    7501      279895 :           return false;
    7502             :         }
    7503      258370 :         if (*i!=walker->label().name())
    7504             :         {
    7505      235495 :           return false;
    7506             :         }
    7507             :       }
    7508        1122 :       return i==names.end();
    7509             :     }
    7510             : 
    7511       37290 :     bool allow_(const action_name_multiset_list& allowlist,
    7512             :                 const action_list& multiaction)
    7513             :     {
    7514             :       /* The empty multiaction, i.e. tau, is never blocked by allow */
    7515       37290 :       if (multiaction.empty())
    7516             :       {
    7517           0 :         return true;
    7518             :       }
    7519             : 
    7520             :       /* The multiaction is equal to the special Terminate action. This action cannot be blocked. */
    7521       37290 :       if (multiaction == action_list({ terminationAction }))
    7522             :       {
    7523          18 :         return true;
    7524             :       }
    7525             : 
    7526      294967 :       for (action_name_multiset_list::const_iterator i=allowlist.begin();
    7527      294967 :            i!=allowlist.end(); ++i)
    7528             :       {
    7529      258256 :         if (allowsingleaction(*i,multiaction))
    7530             :         {
    7531         561 :           return true;
    7532             :         }
    7533             :       }
    7534       36711 :       return false;
    7535             :     }
    7536             : 
    7537        1898 :     bool encap(const action_name_multiset_list& encaplist, const action_list& multiaction)
    7538             :     {
    7539        4011 :       for (const action& a: multiaction)
    7540             :       {
    7541        2113 :         assert(encaplist.size()==1);
    7542        4226 :         for (const identifier_string& s1: encaplist.front().names())
    7543             :         {
    7544        4226 :           const identifier_string s2=a.label().name();
    7545        2113 :           if (s1==s2)
    7546             :           {
    7547           0 :             return true;
    7548             :           }
    7549             :         }
    7550             :       }
    7551        1898 :       return false;
    7552             :     }
    7553             : 
    7554         763 :     void allowblockcomposition(
    7555             :       const action_name_multiset_list& allowlist1,  // This is a list of list of identifierstring.
    7556             :       const bool is_allow,
    7557             :       stochastic_action_summand_vector& action_summands,
    7558             :       deadlock_summand_vector& deadlock_summands)
    7559             :     {
    7560             :       /* This function calculates the allow or the block operator,
    7561             :          depending on whether is_allow is true */
    7562             : 
    7563        1526 :       stochastic_action_summand_vector sourcesumlist;
    7564         763 :       action_summands.swap(sourcesumlist);
    7565             : 
    7566        1526 :       deadlock_summand_vector resultdeltasumlist;
    7567        1526 :       deadlock_summand_vector resultsimpledeltasumlist;
    7568         763 :       deadlock_summands.swap(resultdeltasumlist);
    7569             : 
    7570        1526 :       action_name_multiset_list allowlist((is_allow)?sort_multi_action_labels(allowlist1):allowlist1);
    7571             : 
    7572         763 :       std::size_t sourcesumlist_length=sourcesumlist.size();
    7573         763 :       if (sourcesumlist_length>2 || is_allow) // This condition prevents this message to be printed
    7574             :         // when performing data elimination. In this case the
    7575             :         // term delta is linearised, to determine which data
    7576             :         // is essential for all processes. In these cases a
    7577             :         // message about the block operator is very confusing.
    7578             :       {
    7579         288 :         mCRL2log(mcrl2::log::verbose) << "- calculating the " << (is_allow?"allow":"block") <<
    7580           0 :               " operator on " << sourcesumlist.size() << " action summands and " << resultdeltasumlist.size() << " delta summands";
    7581             :       }
    7582             : 
    7583             :       /* First add the resulting sums in two separate lists
    7584             :          one for actions, and one for delta's. The delta's
    7585             :          are added at the end to the actions, where for
    7586             :          each delta summand it is determined whether it ought
    7587             :          to be added, or is superseded by an action or another
    7588             :          delta summand */
    7589       39951 :       for (stochastic_action_summand_vector::const_iterator i=sourcesumlist.begin(); i!=sourcesumlist.end(); ++i)
    7590             :       {
    7591       78376 :         const stochastic_action_summand smmnd= *i;
    7592       39188 :         const variable_list& sumvars=smmnd.summation_variables();
    7593       78376 :         const action_list multiaction=smmnd.multi_action().actions();
    7594       78376 :         const data_expression actiontime=smmnd.multi_action().time();
    7595       39188 :         const data_expression& condition=smmnd.condition();
    7596             : 
    7597             :         // Explicitly allow the termination action in any allow.
    7598       80274 :         if ((is_allow && allow_(allowlist,multiaction)) ||
    7599       40507 :             (!is_allow && !encap(allowlist,multiaction)))
    7600             :         {
    7601        2477 :           action_summands.push_back(smmnd);
    7602             :         }
    7603             :         else
    7604             :         {
    7605       36711 :           if (smmnd.has_time())
    7606             :           {
    7607          44 :             resultdeltasumlist.push_back(deadlock_summand(sumvars, condition, deadlock(actiontime)));
    7608             :           }
    7609             :           else
    7610             :           {
    7611             :             // summand has no time.
    7612       36667 :             if (condition==sort_bool::true_())
    7613             :             {
    7614          33 :               resultsimpledeltasumlist.push_back(deadlock_summand(sumvars, condition, deadlock()));
    7615             :             }
    7616             :             else
    7617             :             {
    7618       36634 :               resultdeltasumlist.push_back(deadlock_summand(sumvars, condition, deadlock()));
    7619             :             }
    7620             :           }
    7621             :         }
    7622             :       }
    7623             : 
    7624         763 :       if (options.nodeltaelimination)
    7625             :       {
    7626           0 :         deadlock_summands.swap(resultsimpledeltasumlist);
    7627           0 :         copy(resultdeltasumlist.begin(),resultdeltasumlist.end(),back_inserter(deadlock_summands));
    7628             :       }
    7629             :       else
    7630             :       {
    7631         763 :         if (!options.ignore_time) /* if a delta summand is added, conditional, timed
    7632             :                                    delta's are subsumed and do not need to be added */
    7633             :         {
    7634         796 :           for (deadlock_summand_vector::const_iterator j=resultsimpledeltasumlist.begin();
    7635         796 :                j!=resultsimpledeltasumlist.end(); ++j)
    7636             :           {
    7637          33 :             insert_timed_delta_summand(action_summands,deadlock_summands,*j);
    7638             :           }
    7639       38410 :           for (deadlock_summand_vector::const_iterator j=resultdeltasumlist.begin();
    7640       38410 :                j!=resultdeltasumlist.end(); ++j)
    7641             :           {
    7642       37647 :             insert_timed_delta_summand(action_summands,deadlock_summands,*j);
    7643             :           }
    7644             :         }
    7645             :         else
    7646             :         {
    7647             :           // Add a true -> delta
    7648           0 :           insert_timed_delta_summand(action_summands,deadlock_summands,deadlock_summand(variable_list(),sort_bool::true_(),deadlock()));
    7649             :         }
    7650             :       }
    7651         763 :       if (mCRL2logEnabled(mcrl2::log::verbose) && (sourcesumlist_length>2 || is_allow))
    7652             :       {
    7653           0 :         mCRL2log(mcrl2::log::verbose) << ", resulting in " << action_summands.size() << " action summands and " << deadlock_summands.size() << " delta summands\n";
    7654             :       }
    7655         763 :     }
    7656             : 
    7657             :     /**************** renaming ******************************************/
    7658             : 
    7659           0 :     action rename_action(const rename_expression_list& renamings, const action& act)
    7660             :     {
    7661           0 :       const action_label& actionId=act.label();
    7662           0 :       const identifier_string& s=actionId.name();
    7663           0 :       for (rename_expression_list::const_iterator i=renamings.begin(); i!=renamings.end(); ++i)
    7664             :       {
    7665           0 :         if (s==i->source())
    7666             :         {
    7667           0 :           return action(action_label(i->target(),actionId.sorts()),
    7668           0 :                         act.arguments());
    7669             :         }
    7670             :       }
    7671           0 :       return act;
    7672             :     }
    7673             : 
    7674           0 :     action_list rename_actions(const rename_expression_list& renamings,
    7675             :                                const action_list& multiaction)
    7676             :     {
    7677           0 :       action_list resultactionlist;
    7678             : 
    7679           0 :       for (const action& a: multiaction)
    7680             :       {
    7681           0 :         resultactionlist=linInsertActionInMultiActionList(
    7682           0 :                            rename_action(renamings,a),
    7683             :                            resultactionlist);
    7684             :       }
    7685           0 :       return resultactionlist;
    7686             :     }
    7687             : 
    7688           0 :     void renamecomposition(
    7689             :       const rename_expression_list& renamings,
    7690             :       stochastic_action_summand_vector& action_summands)
    7691             :     {
    7692           0 :       for (stochastic_action_summand_vector::iterator i=action_summands.begin(); i!=action_summands.end(); ++i)
    7693             :       {
    7694           0 :         const action_list actions=rename_actions(renamings,i->multi_action().actions());
    7695             : 
    7696           0 :         *i= stochastic_action_summand(i->summation_variables(),
    7697           0 :                            i->condition(),
    7698           0 :                            i->multi_action().has_time()?multi_action(actions,i->multi_action().time()):multi_action(actions),
    7699           0 :                            i->assignments(),
    7700           0 :                            i->distribution());
    7701             : 
    7702             :       }
    7703           0 :     }
    7704             : 
    7705             :     /**************** equalargs ****************************************/
    7706             : 
    7707             :     bool occursinvarandremove(const variable& var, variable_list& vl)
    7708             :     {
    7709             :       bool result=false;
    7710             : 
    7711             :       if (vl.empty())
    7712             :       {
    7713             :         return 0;
    7714             :       }
    7715             :       vl.pop_front();
    7716             :       const variable var1=vl.front();
    7717             :       if (var==var1)
    7718             :       {
    7719             :         return true;
    7720             :       }
    7721             : 
    7722             :       // Names of variables cannot be the same, even if they have different types.
    7723             :       if (var.name()==var1.name())
    7724             :       {
    7725             :         throw mcrl2::runtime_error("variable conflict " + data::pp(var) + ":" + data::pp(var.sort()) + " versus " +
    7726             :                                    data::pp(var1) + ":" + data::pp(var1.sort()) + ".");
    7727             :       }
    7728             : 
    7729             :       result=occursinvarandremove(var,vl);
    7730             :       vl.push_front(var1);
    7731             :       return result;
    7732             :     }
    7733             : 
    7734             :     /********************** construct renaming **************************/
    7735             : 
    7736          32 :     variable_list construct_renaming(
    7737             :       const variable_list& pars1,
    7738             :       const variable_list& pars2,
    7739             :       variable_list& pars3,
    7740             :       variable_list& pars4,
    7741             :       const bool unique=true)
    7742             :     {
    7743             :       /* check whether the variables in pars2 are unique,
    7744             :          wrt to those in pars1, and deliver:
    7745             :          - in pars3 a list of renamed parameters pars2, such that
    7746             :            pars3 is unique with respect to pars1;
    7747             :          - in pars4 a list of parameters that need to be renamed;
    7748             :          - as a return result, new values for the parameters in pars4.
    7749             :            This allows using substitute_data(list) to rename
    7750             :            action and process arguments and conditions to adapt
    7751             :            to the new parameter names.
    7752             :          The variable unique indicates whether the generated variables
    7753             :          are unique, and not occurring elsewhere. If unique is false,
    7754             :          it is attempted to reuse previously generated variable names,
    7755             :          as long as they do not occur in pars1. The default value for
    7756             :          unique is true.
    7757             :        */
    7758             : 
    7759          64 :       variable_list t, t1, t2;
    7760             : 
    7761          32 :       if (pars2.empty())
    7762             :       {
    7763          21 :         pars3=variable_list();
    7764          21 :         pars4=variable_list();
    7765             :       }
    7766             :       else
    7767             :       {
    7768          11 :         const variable& var2=pars2.front();
    7769          22 :         variable var3=var2;
    7770          11 :         for (int i=0 ; occursin(var3,pars1) ; ++i)
    7771             :         {
    7772           0 :           var3=get_fresh_variable(var2.name(),var2.sort(),(unique?-1:i));
    7773             :         }
    7774          11 :         if (var3!=var2)
    7775             :         {
    7776           0 :           t1=construct_renaming(pars1,pars2.tail(),t,t2,unique);
    7777           0 :           t1.push_front(var3);
    7778             : 
    7779           0 :           pars4=t2;
    7780           0 :           pars4.push_front(var2);
    7781           0 :           pars3=t;
    7782           0 :           pars3.push_front(var3);
    7783             :         }
    7784             :         else
    7785             :         {
    7786          11 :           t1=construct_renaming(pars1,pars2.tail(),t,pars4,unique);
    7787          11 :           pars3=t;
    7788          11 :           pars3.push_front(var2);
    7789             :         }
    7790             : 
    7791             :       }
    7792          64 :       return t1;
    7793             :     }
    7794             : 
    7795             :     /**************** communication operator composition ****************/
    7796             : 
    7797         682 :     static action_name_multiset sort_action_labels(const action_name_multiset& actionlabels)
    7798             :     {
    7799        2046 :       return action_name_multiset(atermpp::sort_list<identifier_string>(
    7800         682 :                                                actionlabels.names(),
    7801         591 :                                                [](const identifier_string& a1, const identifier_string& a2)
    7802        1955 :                                                                 { return std::string(a1)<std::string(a2); }));
    7803             :     }
    7804             : 
    7805             :     template <typename List>
    7806         423 :     sort_expression_list get_sorts(const List& l)
    7807             :     {
    7808        1441 :       return sort_expression_list(l.begin(), l.end(), [](const typename List::value_type& d) -> sort_expression {return d.sort();});
    7809             :     }
    7810             : 
    7811             :     // Check that the sorts of both termlists match.
    7812       39655 :     data_expression pairwiseMatch(const data_expression_list& l1, const data_expression_list& l2)
    7813             :     {
    7814       39655 :       if (l1.size()!=l2.size())
    7815             :       {
    7816       10914 :         return sort_bool::false_();
    7817             :       }
    7818       28741 :       data_expression_list::const_iterator i2=l2.begin();
    7819       57482 :       data_expression result=sort_bool::true_();
    7820       54113 :       for(const data_expression& t1: l1)
    7821             :       {
    7822       34707 :         if (t1.sort()!=i2->sort())
    7823             :         {
    7824        9335 :           return sort_bool::false_();
    7825             :         }
    7826       25372 :         result=lazy::and_(result,RewriteTerm(equal_to(t1,*i2)));
    7827       25372 :         ++i2;
    7828             :       }
    7829       19406 :       return result;
    7830             :     }
    7831             : 
    7832             :     // a tuple_list contains pairs of actions (multi-action) and the condition under which this action
    7833             :     // can occur.
    7834      886896 :     struct tuple_list
    7835             :     {
    7836             :       std::vector < action_list > actions;
    7837             :       std::vector < data_expression > conditions;
    7838             :     };
    7839             : 
    7840      130095 :     tuple_list addActionCondition(
    7841             :       const action& firstaction,
    7842             :       const data_expression& condition,
    7843             :       const tuple_list& L,
    7844             :       tuple_list S)
    7845             :     {
    7846             :       /* if firstaction==action(), it should not be added */
    7847      130095 :       assert(condition!=sort_bool::false_()); // It makes no sense to add an action with condition false,
    7848             :       // as it cannot happen anyhow.
    7849      262007 :       for (std::size_t i=0; i<L.actions.size(); ++i)
    7850             :       {
    7851      263824 :         S.actions.push_back((firstaction!=action())?
    7852      123566 :                             linInsertActionInMultiActionList(firstaction,L.actions[i]):
    7853        8346 :                             L.actions[i]);
    7854      131912 :         S.conditions.push_back(lazy::and_(L.conditions[i],condition));
    7855             :       }
    7856      130095 :       return S;
    7857             :     }
    7858             : 
    7859             : 
    7860             :     // Type and variables for a somewhat more efficient storage of the
    7861             :     // communication function
    7862             : 
    7863             :     class comm_entry
    7864             :     {
    7865             :       public:
    7866             :         // comm_entries are not copyable.
    7867             :         comm_entry(const comm_entry& )=delete;
    7868             :         comm_entry& operator=(const comm_entry& )=delete;
    7869             : 
    7870             :         std::vector <identifier_string_list> lhs;
    7871             :         std::vector <identifier_string> rhs;
    7872             :         std::vector <identifier_string_list> tmp;
    7873             :         std::vector< bool > match_failed;
    7874             : 
    7875       32102 :         comm_entry(const communication_expression_list& communications)
    7876       32102 :         {
    7877      159810 :           for (const communication_expression& l: communications)
    7878             :           {
    7879      127708 :             lhs.push_back(l.action_name().names());
    7880      127708 :             rhs.push_back(l.name());
    7881      127708 :             tmp.push_back(identifier_string_list());
    7882      127708 :             match_failed.push_back(false);
    7883             :           }
    7884       32102 :         }
    7885             : 
    7886       32102 :         ~comm_entry()
    7887       32102 :         {}
    7888             : 
    7889     4115444 :         std::size_t size() const
    7890             :         {
    7891     4115444 :           assert(lhs.size()==rhs.size() && rhs.size()==tmp.size() && tmp.size()==match_failed.size());
    7892     4115444 :           return lhs.size();
    7893             :         }
    7894             :     };
    7895             : 
    7896       25152 :     process::action_label can_communicate(const action_list& m, comm_entry& comm_table)
    7897             :     {
    7898             :       /* this function indicates whether the actions in m
    7899             :          consisting of actions and data occur in C, such that
    7900             :          a communication can take place. If not action_label() is delivered,
    7901             :          otherwise the resulting action is the result. */
    7902             :       // first copy the left-hand sides of communications for use
    7903      124830 :       for (std::size_t i=0; i<comm_table.size(); ++i)
    7904             :       {
    7905       99678 :         comm_table.tmp[i] = comm_table.lhs[i];
    7906       99678 :         comm_table.match_failed[i]=false;
    7907             :       }
    7908             : 
    7909             :       // m must match a lhs; check every action
    7910       75456 :       for (const action& a: m)
    7911             :       {
    7912      103833 :         identifier_string actionname=a.label().name();
    7913             : 
    7914             :         // check every lhs for actionname
    7915       53529 :         bool comm_ok = false;
    7916      265569 :         for (std::size_t i=0; i<comm_table.size(); ++i)
    7917             :         {
    7918      212040 :           if (comm_table.match_failed[i]) // lhs i does not match
    7919             :           {
    7920       83985 :             continue;
    7921             :           }
    7922      131280 :           if (comm_table.tmp[i].empty()) // lhs cannot match actionname
    7923             :           {
    7924        3225 :             comm_table.match_failed[i]=true;
    7925        3225 :             continue;
    7926             :           }
    7927      124830 :           if (actionname != comm_table.tmp[i].front())
    7928             :           {
    7929             :             // no match
    7930       74526 :             comm_table.match_failed[i] = true;
    7931             :           }
    7932             :           else
    7933             :           {
    7934             :             // possible match; on to next action
    7935       50304 :             comm_table.tmp[i].pop_front();
    7936       50304 :             comm_ok = true;
    7937             :           }
    7938             :         }
    7939       53529 :         if (!comm_ok)   // no (possibly) matching lhs
    7940             :         {
    7941        3225 :           return action_label();
    7942             :         }
    7943             :       }
    7944             : 
    7945             :       // there is a lhs containing m; find it
    7946       48660 :       for (std::size_t i=0; i<comm_table.size(); ++i)
    7947             :       {
    7948             :         // lhs i matches only if comm_table[i] is empty
    7949       48660 :         if ((!comm_table.match_failed[i]) && comm_table.tmp[i].empty())
    7950             :         {
    7951       21927 :           if (comm_table.rhs[i] == tau())
    7952             :           {
    7953           0 :             throw mcrl2::runtime_error("Cannot linearise a process with a communication operator, containing a communication that results in tau or that has an empty right hand side");
    7954             :             return action_label();
    7955             :           }
    7956       21927 :           return action_label(comm_table.rhs[i],m.front().label().sorts());
    7957             :         }
    7958             :       }
    7959             :       // no match
    7960           0 :       return action_label();
    7961             :     }
    7962             : 
    7963      279598 :     static bool might_communicate(const action_list& m,
    7964             :                                   comm_entry& comm_table,
    7965             :                                   const action_list& n)
    7966             :     {
    7967             :       /* this function indicates whether the actions in m
    7968             :          consisting of actions and data occur in C, such that
    7969             :          a communication might take place (i.e. m is a subbag
    7970             :          of the lhs of a communication in C).
    7971             :          if n is not empty, then all actions of a matching communication
    7972             :          that are not in m should be in n (i.e. there must be a
    7973             :          subbag o of n such that m+o can communicate. */
    7974             : 
    7975             :       // first copy the left-hand sides of communications for use
    7976     1393062 :       for (std::size_t i=0; i<comm_table.size(); ++i)
    7977             :       {
    7978     1113464 :         comm_table.match_failed[i]=false;
    7979     1113464 :         comm_table.tmp[i] = comm_table.lhs[i];
    7980             :       }
    7981             : 
    7982             :       // m must be contained in a lhs; check every action
    7983      448916 :       for (const action& a: m)
    7984             :       {
    7985      529189 :         const identifier_string actionname=a.label().name();
    7986             :         // check every lhs for actionname
    7987      359871 :         bool comm_ok = false;
    7988     1792287 :         for (std::size_t i=0; i<comm_table.size(); ++i)
    7989             :         {
    7990     1432416 :           if (comm_table.match_failed[i])
    7991             :           {
    7992      480947 :             continue;
    7993             :           }
    7994     1197326 :           if (comm_table.tmp[i].empty()) // actionname not in here; ignore lhs
    7995             :           {
    7996        3589 :             comm_table.match_failed[i]=true;
    7997        3589 :             continue;
    7998             :           }
    7999             : 
    8000     2380296 :           identifier_string commname;
    8001     1190148 :           while (actionname != (commname = comm_table.tmp[i].front()))
    8002             :           {
    8003             :             // action is not in m, so it should be in n
    8004             :             // but all actions in m come before n
    8005     1020830 :             comm_table.match_failed[i]=true;
    8006     1020830 :             comm_table.tmp[i]=identifier_string_list();
    8007     1020830 :             break;
    8008             :           }
    8009     1190148 :           if (actionname==commname) // actionname found
    8010             :           {
    8011      169318 :             comm_table.tmp[i].pop_front();
    8012      169318 :             comm_ok = true;
    8013             :           }
    8014             :         }
    8015      359871 :         if (!comm_ok)
    8016             :         {
    8017      190553 :           return false;
    8018             :         }
    8019             :       }
    8020             : 
    8021             :       // the rest of actions of lhs that are not in m should be in n
    8022             :       // rest[i] contains the part of n in which lhs i has to find matching actions
    8023             :       // rest_is_null[i] contains indications whether rest[i] is NULL.
    8024      178090 :       std::vector < action_list > rest(comm_table.size(),n);
    8025      178090 :       std::vector < bool > rest_is_null(comm_table.size(),false);
    8026             : 
    8027             :       // check every lhs
    8028      312946 :       for (std::size_t i=0; i<comm_table.size(); ++i)
    8029             :       {
    8030      271617 :         if (comm_table.match_failed[i]) // lhs i did not contain m
    8031             :         {
    8032      182572 :           continue;
    8033             :         }
    8034             :         // as long as there are still unmatch actions in lhs i...
    8035      136321 :         while (!comm_table.tmp[i].empty())
    8036             :         {
    8037             :           // .. find them in rest[i]
    8038       64967 :           if (rest[i].empty()) // no luck
    8039             :           {
    8040       17051 :             rest_is_null[i] = true;
    8041       58380 :             break;
    8042             :           }
    8043             :           // get first action in lhs i
    8044       71554 :           const identifier_string commname = comm_table.tmp[i].front();
    8045       71554 :           identifier_string restname;
    8046             :           // find it in rest[i]
    8047       94706 :           while (commname!=(restname = rest[i].front().label().name()))
    8048             :           {
    8049       47673 :             rest[i].pop_front();
    8050       47673 :             if (rest[i].empty()) // no more
    8051             :             {
    8052       24278 :               rest_is_null[i] = true;
    8053       24278 :               break;
    8054             :             }
    8055             :           }
    8056       47916 :           if (commname!=restname) // action was not found
    8057             :           {
    8058       24278 :             break;
    8059             :           }
    8060             :           // action found; try next
    8061       23638 :           rest[i].pop_front();
    8062       23638 :           comm_table.tmp[i].pop_front();
    8063             :         }
    8064             : 
    8065       89045 :         if (!rest_is_null[i]) // lhs was found in rest[i]
    8066             :         {
    8067       47716 :           return true;
    8068             :         }
    8069             :       }
    8070             : 
    8071             :       // no lhs completely matches
    8072       41329 :       return false;
    8073             :     }
    8074             : 
    8075      147823 :     tuple_list phi(const action_list& m,
    8076             :                    const data_expression_list& d,
    8077             :                    const action_list& w,
    8078             :                    const action_list& n,
    8079             :                    const action_list& r,
    8080             :                    const bool r_is_null,
    8081             :                    comm_entry& comm_table)
    8082             :     {
    8083             :       /* phi is a function that yields a list of pairs
    8084             :          indicating how the actions in m|w|n can communicate.
    8085             :          The pairs contain the resulting multi action and
    8086             :          a condition on data indicating when communication
    8087             :          can take place. In the communication all actions of
    8088             :          m, none of w and a subset of n can take part in the
    8089             :          communication. d is the data parameter of the communication
    8090             :          and C contains a list of multiaction action pairs indicating
    8091             :          possible communications */
    8092             : 
    8093      147823 :       if (!might_communicate(m,comm_table,n))
    8094             :       {
    8095      113973 :         return tuple_list();
    8096             :       }
    8097       33850 :       if (n.empty())
    8098             :       {
    8099       16122 :         process::action_label c=can_communicate(m,comm_table); /* returns action_label() if no communication
    8100             :                                                                   is possible */
    8101        8061 :         if (c!=action_label())
    8102             :         {
    8103       16122 :           const tuple_list T=makeMultiActionConditionList_aux(w,comm_table,r,r_is_null);
    8104             :           return addActionCondition(
    8105       16122 :                    (c==action_label()?action():action(c,d)),  //Check. Nil kan niet geleverd worden.
    8106        8061 :                    sort_bool::true_(),
    8107             :                    T,
    8108       32244 :                    tuple_list());
    8109             :         }
    8110             :         /* c==NULL, actions in m cannot communicate */
    8111           0 :         return tuple_list();
    8112             :       }
    8113             :       /* if n=[a(f)] \oplus o */
    8114       25789 :       const action& firstaction=n.front();
    8115       25789 :       const action_list& o=n.tail();
    8116       51578 :       const data_expression condition=pairwiseMatch(d,firstaction.arguments());
    8117       25789 :       if (condition==sort_bool::false_())
    8118             :       {
    8119       29496 :         action_list tempw=w;
    8120       14748 :         tempw=push_back(tempw,firstaction);
    8121       14748 :         return phi(m,d,tempw,o,r,r_is_null,comm_table);
    8122             :       }
    8123             :       else
    8124             :       {
    8125       22082 :         action_list tempm=m;
    8126       11041 :         tempm=push_back(tempm,firstaction);
    8127       22082 :         const tuple_list T=phi(tempm,d,w,o,r,r_is_null,comm_table);
    8128       22082 :         action_list tempw=w;
    8129       11041 :         tempw=push_back(tempw,firstaction);
    8130             :         return addActionCondition(
    8131       22082 :                  action(),
    8132             :                  condition,
    8133             :                  T,
    8134       33123 :                  phi(m,d,tempw,o,r,r_is_null,comm_table));
    8135             :       }
    8136             :     }
    8137             : 
    8138       17091 :     bool xi(const action_list& alpha, const action_list& beta, comm_entry& comm_table)
    8139             :     {
    8140       17091 :       if (beta.empty())
    8141             :       {
    8142       13866 :         return can_communicate(alpha,comm_table)!=action_label();
    8143             :       }
    8144             :       else
    8145             :       {
    8146        3225 :         const action& a = beta.front();
    8147        6450 :         action_list l=alpha;
    8148        3225 :         l=push_back(l,a);
    8149        3225 :         const action_list& beta_next = beta.tail();
    8150             : 
    8151        3225 :         if (can_communicate(l,comm_table)!=action_label())
    8152             :         {
    8153           0 :           return true;
    8154             :         }
    8155        3225 :         else if (might_communicate(l,comm_table,beta_next))
    8156             :         {
    8157           0 :           return xi(l,beta_next,comm_table) || xi(alpha,beta_next,comm_table);
    8158             :         }
    8159             :         else
    8160             :         {
    8161        3225 :           return xi(alpha,beta_next,comm_table);
    8162             :         }
    8163             :       }
    8164             :     }
    8165             : 
    8166       39556 :     data_expression psi(const action_list& alpha_in, comm_entry& comm_table)
    8167             :     {
    8168       79112 :       action_list alpha=reverse(alpha_in);
    8169       79112 :       data_expression cond = sort_bool::false_();
    8170      269996 :       while (!alpha.empty())
    8171             :       {
    8172      230440 :         const action a = alpha.front();
    8173      230440 :         action_list beta = alpha.tail();
    8174             : 
    8175      372320 :         while (!beta.empty())
    8176             :         {
    8177      257100 :           const action_list actl({ a, beta.front() });
    8178      128550 :           if (might_communicate(actl,comm_table,beta.tail()) && xi(actl,beta.tail(),comm_table))
    8179             :           {
    8180             :             // sort and remove duplicates??
    8181       13866 :             cond = lazy::or_(cond,pairwiseMatch(a.arguments(),beta.front().arguments()));
    8182             :           }
    8183      128550 :           beta.pop_front();
    8184             :         }
    8185             : 
    8186      115220 :         alpha.pop_front();
    8187             :       }
    8188       79112 :       return lazy::not_(cond);
    8189             :     }
    8190             : 
    8191             :     // returns a list of tuples.
    8192      151156 :     tuple_list makeMultiActionConditionList_aux(
    8193             :       const action_list& multiaction,
    8194             :       comm_entry& comm_table,
    8195             :       const action_list& r,
    8196             :       const bool r_is_null)
    8197             :     {
    8198             :       /* This is the function gamma(m,C,r) provided
    8199             :          by Muck van Weerdenburg in Calculation of
    8200             :          Communication with open terms [1]. */
    8201      151156 :       if (multiaction.empty())
    8202             :       {
    8203       80326 :         tuple_list t;
    8204       40163 :         t.conditions.push_back((r_is_null)?static_cast<const data_expression&>(sort_bool::true_()):psi(r,comm_table));
    8205       40163 :         t.actions.push_back(action_list());
    8206       40163 :         return t;
    8207             :       }
    8208             : 
    8209      110993 :       const action& firstaction=multiaction.front();
    8210      110993 :       const action_list& remainingmultiaction=multiaction.tail(); /* This is m in [1] */
    8211             : 
    8212      221986 :       const tuple_list S=phi(action_list({ firstaction }),
    8213             :                              firstaction.arguments(),
    8214      221986 :                              action_list(),
    8215             :                              remainingmultiaction,
    8216      443972 :                              r,r_is_null,comm_table);
    8217      221986 :       action_list tempr=r;
    8218      110993 :       tempr.push_front(firstaction);
    8219             :       const tuple_list T=makeMultiActionConditionList_aux(
    8220             :                            remainingmultiaction,comm_table,
    8221      221986 :                            (r_is_null) ? action_list({ firstaction }) : tempr, false);
    8222      110993 :       return addActionCondition(firstaction,sort_bool::true_(),T,S);
    8223             :     }
    8224             : 
    8225       32102 :     tuple_list makeMultiActionConditionList(
    8226             :       const action_list& multiaction,
    8227             :       const communication_expression_list& communications)
    8228             :     {
    8229       64204 :       comm_entry comm_table(communications);
    8230       64204 :       return makeMultiActionConditionList_aux(multiaction,comm_table,action_list(),true);
    8231             :     }
    8232             : 
    8233         112 :     void communicationcomposition(
    8234             :       const communication_expression_list& communications,
    8235             :       const action_name_multiset_list& allowlist1,  // This is a list of list of identifierstring.
    8236             :       const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    8237             :       const bool is_block,
    8238             :       stochastic_action_summand_vector& action_summands,
    8239             :       deadlock_summand_vector& deadlock_summands)
    8240             : 
    8241             :     {
    8242             :       /* We follow the implementation of Muck van Weerdenburg, described in
    8243             :          a note: Calculation of communication with open terms. */
    8244             : 
    8245         112 :       mCRL2log(mcrl2::log::verbose) <<
    8246             :             (is_allow ? "- calculating the communication operator modulo the allow operator on " :
    8247           0 :              is_block ? "- calculating the communication operator modulo the block operator on " :
    8248           0 :                         "- calculating the communication operator on ") << action_summands.size() << " action summands";
    8249             : 
    8250             :       /* first we sort the multiactions in communications */
    8251         224 :       communication_expression_list resultingCommunications;
    8252             : 
    8253         396 :       for (communication_expression_list::const_iterator i=communications.begin();
    8254         396 :            i!=communications.end(); ++i)
    8255             :       {
    8256         568 :         const action_name_multiset source=i->action_name();
    8257         568 :         const identifier_string target=i->name();
    8258         284 :         resultingCommunications.push_front(communication_expression(sort_action_labels(source),target));
    8259             :       }
    8260         224 :       communication_expression_list communications1=resultingCommunications;
    8261             : 
    8262         224 :       stochastic_action_summand_vector resultsumlist;
    8263         224 :       deadlock_summand_vector resultingDeltaSummands;
    8264         112 :       deadlock_summands.swap(resultingDeltaSummands);
    8265             : 
    8266         112 :       bool inline_allow = is_allow || is_block;
    8267         112 :       if (inline_allow)
    8268             :       {
    8269             :         // Inline allow is only supported for ignore_time,
    8270             :         // for in other cases generation of delta summands cannot be inlined in any simple way.
    8271           0 :         assert(!options.nodeltaelimination && options.ignore_time);
    8272           0 :         deadlock_summands.push_back(deadlock_summand(variable_list(),sort_bool::true_(),deadlock()));
    8273             :       }
    8274         224 :       action_name_multiset_list allowlist((is_allow)?sort_multi_action_labels(allowlist1):allowlist1);
    8275             : 
    8276       32214 :       for (stochastic_action_summand_vector::const_iterator sourcesumlist=action_summands.begin();
    8277       32214 :            sourcesumlist!=action_summands.end(); ++sourcesumlist)
    8278             :       {
    8279       64204 :         const stochastic_action_summand smmnd=*sourcesumlist;
    8280       32102 :         const variable_list& sumvars=smmnd.summation_variables();
    8281       64204 :         const action_list multiaction=smmnd.multi_action().actions();
    8282       32102 :         const data_expression& condition=smmnd.condition();
    8283       32102 :         const assignment_list& nextstate=smmnd.assignments();
    8284       32102 :         const stochastic_distribution& dist=smmnd.distribution();
    8285             : 
    8286       32102 :         if (!inline_allow)
    8287             :         {
    8288             :           /* Recall a delta summand for every non delta summand.
    8289             :            * The reason for this is that with communication, the
    8290             :            * conditions for summands can become much more complex.
    8291             :            * Many of the actions in these summands are replaced by
    8292             :            * delta's later on. Due to the more complex conditions it
    8293             :            * will be hard to remove them. By adding a default delta
    8294             :            * with a simple condition, makes this job much easier
    8295             :            * later on, and will in general reduce the number of delta
    8296             :            * summands in the whole system */
    8297             : 
    8298             :           /* But first remove free variables from sumvars */
    8299             : 
    8300       64204 :           variable_list newsumvars;
    8301       96180 :           for (variable_list::const_iterator i=sumvars.begin(); i!=sumvars.end(); ++i)
    8302             :           {
    8303      128156 :             const variable sumvar=*i;
    8304      128200 :             if (occursinterm(sumvar,condition) ||
    8305       57667 :                 (smmnd.has_time() && occursinterm(sumvar,smmnd.multi_action().time())))
    8306             :             {
    8307        6529 :               newsumvars.push_front(sumvar);
    8308             :             }
    8309             :           }
    8310       32102 :           newsumvars=reverse(newsumvars);
    8311             : 
    8312       32102 :           resultingDeltaSummands.push_back(deadlock_summand(newsumvars,
    8313             :                                                             condition,
    8314       64204 :                                                             smmnd.multi_action().has_time()?deadlock(smmnd.multi_action().time()):deadlock()));
    8315             :         }
    8316             : 
    8317             :         /* the multiactionconditionlist is a list containing
    8318             :            tuples, with a multiaction and the condition,
    8319             :            expressing whether the multiaction can happen. All
    8320             :            conditions exclude each other. Furthermore, the list
    8321             :            is not empty. If no communications can take place,
    8322             :            the original multiaction is delivered, with condition
    8323             :            true. */
    8324             : 
    8325             :         const tuple_list multiactionconditionlist=
    8326             :           makeMultiActionConditionList(
    8327             :             multiaction,
    8328       64204 :             communications1);
    8329             : 
    8330       32102 :         assert(multiactionconditionlist.actions.size()==
    8331             :                multiactionconditionlist.conditions.size());
    8332       72265 :         for (std::size_t i=0 ; i<multiactionconditionlist.actions.size(); ++i)
    8333             :         {
    8334       80326 :           const action_list multiaction=multiactionconditionlist.actions[i];
    8335             : 
    8336       40163 :           if (is_allow && !allow_(allowlist,multiaction))
    8337             :           {
    8338           0 :             continue;
    8339             :           }
    8340       40163 :           if (is_block && encap(allowlist,multiaction))
    8341             :           {
    8342           0 :             continue;
    8343             :           }
    8344             : 
    8345             :           const data_expression communicationcondition=
    8346       80326 :             RewriteTerm(multiactionconditionlist.conditions[i]);
    8347             : 
    8348             :           const data_expression newcondition=RewriteTerm(
    8349       80326 :                                                lazy::and_(condition,communicationcondition));
    8350             :           stochastic_action_summand new_summand(sumvars,
    8351             :                                      newcondition,
    8352       80326 :                                      smmnd.multi_action().has_time()?multi_action(multiaction, smmnd.multi_action().time()):multi_action(multiaction),
    8353             :                                      nextstate,
    8354       80326 :                                      dist);
    8355       40163 :           if (!options.nosumelm)
    8356             :           {
    8357       40163 :             if (sumelm(new_summand))
    8358             :             {
    8359        4023 :               new_summand.condition() = RewriteTerm(new_summand.condition());
    8360             :             }
    8361             :           }
    8362             : 
    8363       40163 :           if (new_summand.condition()!=sort_bool::false_())
    8364             :           {
    8365       37406 :             resultsumlist.push_back(new_summand);
    8366             :           }
    8367             :         }
    8368             : 
    8369             :       }
    8370             : 
    8371             :       /* Now the resulting delta summands must be added again */
    8372             : 
    8373         112 :       action_summands.swap(resultsumlist);
    8374             : 
    8375         112 :       if (!inline_allow && !options.nodeltaelimination)
    8376             :       {
    8377       32344 :         for (deadlock_summand_vector::const_iterator w=resultingDeltaSummands.begin();
    8378       32344 :              w!=resultingDeltaSummands.end(); ++w)
    8379             :         {
    8380       32232 :           insert_timed_delta_summand(action_summands,deadlock_summands,*w);
    8381             :         }
    8382             :       }
    8383             : 
    8384         112 :       mCRL2log(mcrl2::log::verbose) << " resulting in " << action_summands.size() << " action summands and " << deadlock_summands.size() << " delta summands\n";
    8385         112 :     }
    8386             : 
    8387         277 :     bool check_real_variable_occurrence(
    8388             :       const variable_list& sumvars,
    8389             :       const data_expression& actiontime,
    8390             :       const data_expression& condition)
    8391             :     {
    8392             :       /* Check whether actiontime is an expression
    8393             :          of the form t1 +...+ tn, where one of the
    8394             :          ti is a variable in sumvars that does not occur in condition */
    8395             : 
    8396         277 :       if (is_variable(actiontime))
    8397             :       {
    8398           0 :         const variable& t = atermpp::down_cast<variable>(actiontime);
    8399           0 :         if (occursintermlist(t, variable_list_to_data_expression_list(sumvars)) && !occursinterm(t, condition))
    8400             :         {
    8401           0 :           return true;
    8402             :         }
    8403             :       }
    8404             : 
    8405         277 :       if (sort_real::is_plus_application(actiontime))
    8406             :       {
    8407          12 :         return (check_real_variable_occurrence(sumvars,data::binary_left(application(actiontime)),condition) ||
    8408           9 :                 check_real_variable_occurrence(sumvars,data::binary_right(application(actiontime)),condition));
    8409             :       }
    8410             : 
    8411         274 :       return false;
    8412             :     }
    8413             : 
    8414         574 :     data_expression makesingleultimatedelaycondition(
    8415             :       const variable_list& sumvars,
    8416             :       const variable_list& freevars,
    8417             :       const data_expression& condition,
    8418             :       const bool has_time,
    8419             :       const variable& timevariable,
    8420             :       const data_expression& actiontime,
    8421             :       variable_list& used_sumvars)
    8422             :     {
    8423             :       /* Generate a condition of the form:
    8424             : 
    8425             :            exists sumvars. condition && timevariable<actiontime
    8426             : 
    8427             :          where the sumvars are added to the existentially quantified
    8428             :          variables, and the resulting expression is
    8429             : 
    8430             :            condition && timevariable<actiontime
    8431             : 
    8432             :          The comments below refer to old code, where an explicit
    8433             :          existential quantor was generated.
    8434             : 
    8435             :          OLD:
    8436             :          Currently, the existential quantifier must use an equation,
    8437             :          which represents a higher order function. The existential
    8438             :          quantifier is namely of type exists:sorts1->Bool, where sorts1
    8439             :          are the sorts of the quantified variables.
    8440             : 
    8441             :          If the sum variables do not occur in the expression, they
    8442             :          are not quantified.
    8443             : 
    8444             :          If the actiontime is of the form t1+t2+...+tn where one
    8445             :          of the ti is a quantified real variable in sumvars, and this
    8446             :          variable does not occur in the condition, then the expression
    8447             :          of the form timevariable < actiontime is omitted.
    8448             :       */
    8449             : 
    8450         574 :       assert(used_sumvars.empty());
    8451         574 :       data_expression result;
    8452        1148 :       variable_list variables;
    8453         574 :       if (!has_time || (check_real_variable_occurrence(sumvars,actiontime,condition)))
    8454             :       {
    8455         303 :         result=condition;
    8456             :       }
    8457             :       else
    8458             :       {
    8459         271 :         result=RewriteTerm(
    8460         542 :                  lazy::and_(
    8461             :                    condition,
    8462         542 :                    data::less(timevariable,actiontime)));
    8463         271 :         variables.push_front(timevariable);
    8464             :       }
    8465        1365 :       for (variable_list::const_iterator i=freevars.begin(); i!=freevars.end(); ++i)
    8466             :       {
    8467         791 :         if (occursinterm(*i,result))
    8468             :         {
    8469         590 :           variables.push_front(*i);
    8470             :         }
    8471             :       }
    8472             : 
    8473         819 :       for (std::set<variable>::const_iterator p=global_variables.begin();
    8474         819 :            p!=global_variables.end() ; ++p)
    8475             :       {
    8476         245 :         if (occursinterm(*p,result))
    8477             :         {
    8478           0 :           variables.push_front(*p);
    8479             :         }
    8480             :       }
    8481             : 
    8482         776 :       for (variable_list::const_iterator s=sumvars.begin(); s!=sumvars.end(); ++s)
    8483             :       {
    8484         202 :         if (occursinterm(*s,result))
    8485             :         {
    8486         126 :           used_sumvars.push_front(*s);
    8487             :         }
    8488             :       }
    8489         574 :       used_sumvars = reverse(used_sumvars);
    8490             : 
    8491        1148 :       return result;
    8492             :     }
    8493             : 
    8494        1016 :     lps::detail::ultimate_delay getUltimateDelayCondition(
    8495             :       const stochastic_action_summand_vector& action_summands,
    8496             :       const deadlock_summand_vector& deadlock_summands,
    8497             :       const variable_list& freevars)
    8498             :     {
    8499             :       /* First walk through the summands to see whether
    8500             :          a summand with condition true that does not refer
    8501             :          to time exists. In that case the ultimate delay
    8502             :          condition is true */
    8503             : 
    8504        2032 :       variable time_variable=get_fresh_variable("timevar",sort_real::real_());
    8505        1441 :       for (deadlock_summand_vector::const_iterator i=deadlock_summands.begin();
    8506        1441 :            i!=deadlock_summands.end(); ++i)
    8507             :       {
    8508        1125 :         if ((!i->deadlock().has_time()) && (i->condition()==sort_bool::true_()))
    8509             :         {
    8510         700 :           return lps::detail::ultimate_delay(time_variable);
    8511             :         }
    8512             :       }
    8513             : 
    8514         770 :       for (stochastic_action_summand_vector::const_iterator i=action_summands.begin();
    8515         770 :            i!=action_summands.end(); ++i)
    8516             :       {
    8517         477 :         if ((!i->multi_action().has_time()) && (i->condition()==sort_bool::true_()))
    8518             :         {
    8519          23 :           return lps::detail::ultimate_delay(time_variable);
    8520             :         }
    8521             :       }
    8522             : 
    8523             :       /* Unfortunately, no ultimate delay condition true can
    8524             :          be generated. So, we must now traverse all conditions
    8525             :          to generate a non trivial ultimate delay condition */
    8526             : 
    8527         586 :       data_expression_list results;
    8528         586 :       data_expression_list condition_list;
    8529         586 :       std::vector < variable_list> renamings_pars;
    8530         586 :       std::vector < data_expression_list> renamings_args;
    8531         586 :       variable_list existentially_quantified_variables;
    8532         491 :       for (const deadlock_summand& s: deadlock_summands)
    8533             :       {
    8534         396 :         variable_list new_existentially_quantified_variables;
    8535             :         const data_expression ult_del_condition=
    8536             :              makesingleultimatedelaycondition(
    8537             :                              s.summation_variables(),
    8538             :                              freevars,
    8539             :                              s.condition(),
    8540         198 :                              s.deadlock().has_time(),
    8541             :                              time_variable,
    8542         198 :                              s.deadlock().time(),
    8543         594 :                              new_existentially_quantified_variables);
    8544         198 :         existentially_quantified_variables=merge_var(
    8545             :                                              new_existentially_quantified_variables,
    8546             :                                              existentially_quantified_variables,
    8547             :                                              renamings_pars,
    8548             :                                              renamings_args,
    8549             :                                              condition_list,
    8550         396 :                                              variable_list());
    8551         198 :         results.push_front(ult_del_condition);
    8552             :       }
    8553             : 
    8554         669 :       for (const stochastic_action_summand& s: action_summands)
    8555             :       {
    8556         752 :         variable_list new_existentially_quantified_variables;
    8557             :         const data_expression ult_del_condition=
    8558             :              makesingleultimatedelaycondition(
    8559             :                              s.summation_variables(),
    8560             :                              freevars,
    8561             :                              s.condition(),
    8562         376 :                              s.multi_action().has_time(),
    8563             :                              time_variable,
    8564         376 :                              s.multi_action().time(),
    8565        1128 :                              new_existentially_quantified_variables);
    8566         376 :         existentially_quantified_variables=merge_var(
    8567             :                                              new_existentially_quantified_variables,
    8568             :                                              existentially_quantified_variables,
    8569             :                                              renamings_pars,
    8570             :                                              renamings_args,
    8571             :                                              condition_list,
    8572         752 :                                              variable_list());
    8573         376 :         results.push_front(ult_del_condition);
    8574             :       }
    8575             : 
    8576         586 :       data_expression result=sort_bool::false_();
    8577             : 
    8578         293 :       assert(results.size()==condition_list.size());
    8579         293 :       assert(results.size()==renamings_pars.size());
    8580         293 :       assert(results.size()==renamings_args.size());
    8581             : 
    8582         293 :       std::vector < variable_list>::const_iterator renamings_par=renamings_pars.begin();
    8583         293 :       std::vector < data_expression_list>::const_iterator renamings_arg=renamings_args.begin();
    8584         293 :       condition_list=reverse(condition_list);
    8585         293 :       results=reverse(results);
    8586         293 :       data_expression_list::const_iterator j=condition_list.begin();
    8587         867 :       for(data_expression_list::const_iterator i=results.begin();
    8588         867 :               i!=results.end(); ++i,++j,++renamings_par,++renamings_arg)
    8589             :       {
    8590         574 :         const variable_list& auxpars=*renamings_par;
    8591         574 :         const data_expression_list& auxargs=*renamings_arg;
    8592             : 
    8593        1148 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma; 
    8594         574 :         data_expression_list::const_iterator j1=auxargs.begin();
    8595         586 :         for (variable_list::const_iterator i1=auxpars.begin();
    8596         586 :              i1!=auxpars.end(); ++i1, ++j1)
    8597             :         {
    8598             :           /* Substitutions are carried out from left to right. The first applicable substitution counts */
    8599          12 :           if (sigma(*i1)==*i1)
    8600             :           {
    8601          12 :             sigma[*i1]=*j1;
    8602          12 :             std::set<variable> varset=find_free_variables(*j);
    8603             : 
    8604             :           }
    8605             :         }
    8606             : 
    8607        1148 :         maintain_variables_in_rhs< mutable_map_substitution<> > mutable_sigma(sigma);
    8608         574 :         result=lazy::or_(result,replace_variables_capture_avoiding_alt(lazy::and_(*i,*j), mutable_sigma));
    8609             :       }
    8610         293 :       return lps::detail::ultimate_delay(time_variable, existentially_quantified_variables, RewriteTerm(result));
    8611             :     }
    8612             : 
    8613             : 
    8614             :     /******** make_unique_variables **********************/
    8615             : 
    8616        5395 :     data::maintain_variables_in_rhs< data::mutable_map_substitution<> >  make_unique_variables(
    8617             :       const variable_list& var_list,
    8618             :       const std::string& hint)
    8619             :     {
    8620             :       /* This function generates a list of variables with the same sorts
    8621             :          as in variable_list, where all names are unique */
    8622             : 
    8623        5395 :       data::maintain_variables_in_rhs< data::mutable_map_substitution<> >  sigma;
    8624             : 
    8625        7881 :       for(variable_list::const_iterator i=var_list.begin(); i!=var_list.end(); ++i)
    8626             :       {
    8627        4972 :         const data::variable v = get_fresh_variable(std::string(i->name()) + ((hint.empty())?"":"_") + hint, i->sort());
    8628        2486 :         sigma[*i] = v;
    8629             :       }
    8630        5395 :       return sigma;
    8631             :     }
    8632             : 
    8633             :     /******** make_parameters_and_variables_unique **********************/
    8634             : 
    8635         881 :     void make_parameters_and_sum_variables_unique(
    8636             :       stochastic_action_summand_vector& action_summands,
    8637             :       deadlock_summand_vector& deadlock_summands,
    8638             :       variable_list& pars,
    8639             :       lps::detail::ultimate_delay& ultimate_delay_condition,
    8640             :       const std::string& hint="")
    8641             :     {
    8642        1762 :       stochastic_action_summand_vector result_action_summands;
    8643             : 
    8644        1762 :       data::maintain_variables_in_rhs<data::mutable_map_substitution<> > sigma=make_unique_variables(pars, hint);
    8645        1762 :       const variable_list unique_pars=data::replace_variables(pars, sigma);
    8646             : 
    8647         881 :       if (!options.ignore_time)
    8648             :       {
    8649             :         // Remove variables locally bound in the ultimate_delay_condition
    8650        1762 :         maintain_variables_in_rhs< data::mutable_map_substitution<> > local_sigma=sigma;
    8651         982 :         for(const variable& v: ultimate_delay_condition.variables())
    8652             :         {
    8653         101 :           local_sigma[v]=v;
    8654             :         }
    8655         881 :         ultimate_delay_condition.constraint()=replace_variables_capture_avoiding_alt(
    8656         881 :                                                        ultimate_delay_condition.constraint(),
    8657             :                                                        local_sigma);  // Only substitute the variables in the lhs.
    8658             :       }
    8659        2686 :       for (stochastic_action_summand_vector::const_iterator s=action_summands.begin(); s!=action_summands.end(); ++s)
    8660             :       {
    8661        3610 :         const stochastic_action_summand smmnd= *s;
    8662             : 
    8663        1805 :         const variable_list& sumvars=smmnd.summation_variables();
    8664        3610 :         data::maintain_variables_in_rhs<data::mutable_map_substitution<> > sigma_sumvars=make_unique_variables(sumvars,hint);
    8665        3610 :         const variable_list unique_sumvars=data::replace_variables(sumvars, sigma_sumvars);
    8666             : 
    8667        3610 :         stochastic_distribution distribution=smmnd.distribution();
    8668        3610 :         const variable_list stochastic_vars=distribution.variables();
    8669             :         data::maintain_variables_in_rhs<data::mutable_map_substitution<> > sigma_stochastic_vars=
    8670        3610 :                                           make_unique_variables(stochastic_vars,hint);
    8671        3610 :         const variable_list unique_stochastic_vars=data::replace_variables(stochastic_vars, sigma_stochastic_vars);
    8672             : 
    8673        3610 :         data_expression condition=smmnd.condition();
    8674        3610 :         action_list multiaction=smmnd.multi_action().actions();
    8675        3610 :         data_expression actiontime=smmnd.multi_action().time();
    8676        3610 :         assignment_list nextstate=smmnd.assignments();
    8677             : 
    8678        1805 :         condition=replace_variables_capture_avoiding_alt(condition, sigma_sumvars);
    8679        1805 :         condition=replace_variables_capture_avoiding_alt(condition, sigma);
    8680             : 
    8681        1805 :         actiontime=replace_variables_capture_avoiding_alt(actiontime, sigma_sumvars);
    8682        1805 :         actiontime=replace_variables_capture_avoiding_alt(actiontime, sigma);
    8683        1805 :         multiaction=lps::replace_variables_capture_avoiding_with_an_identifier_generator(multiaction, sigma_sumvars, fresh_identifier_generator);
    8684        1805 :         multiaction=lps::replace_variables_capture_avoiding_with_an_identifier_generator(multiaction, sigma, fresh_identifier_generator);
    8685             : 
    8686        1805 :         distribution=stochastic_distribution(
    8687             :                        unique_stochastic_vars,
    8688        3610 :                        replace_variables_capture_avoiding_alt(distribution.distribution(), sigma_sumvars));
    8689        1805 :         distribution=stochastic_distribution(
    8690             :                        unique_stochastic_vars,
    8691        3610 :                        replace_variables_capture_avoiding_alt(distribution.distribution(), sigma_stochastic_vars));
    8692        1805 :         distribution=stochastic_distribution(
    8693             :                        distribution.variables(),
    8694        3610 :                        replace_variables_capture_avoiding_alt(distribution.distribution(), sigma));
    8695             : 
    8696        1805 :         nextstate=substitute_assignmentlist(nextstate,pars,false,true,sigma_sumvars);
    8697        1805 :         nextstate=substitute_assignmentlist(nextstate,pars,false,true,sigma_stochastic_vars);
    8698        1805 :         nextstate=substitute_assignmentlist(nextstate,pars,true,true,sigma);
    8699             : 
    8700        1805 :         result_action_summands.push_back(stochastic_action_summand(
    8701             :                                                         unique_sumvars,
    8702             :                                                         condition,
    8703        3610 :                                                         s->multi_action().has_time()?multi_action(multiaction,actiontime):multi_action(multiaction),
    8704             :                                                         nextstate,
    8705             :                                                         distribution));
    8706             :       }
    8707         881 :       pars=unique_pars;
    8708         881 :       action_summands.swap(result_action_summands);
    8709             : 
    8710        1762 :       deadlock_summand_vector result_deadlock_summands;
    8711             : 
    8712         881 :       assert(unique_pars.size()==pars.size());
    8713             : 
    8714        1785 :       for (deadlock_summand_vector::const_iterator s=deadlock_summands.begin(); s!=deadlock_summands.end(); ++s)
    8715             :       {
    8716        1808 :         const deadlock_summand smmnd= *s;
    8717         904 :         const variable_list& sumvars=smmnd.summation_variables();
    8718        1808 :         maintain_variables_in_rhs<data::mutable_map_substitution<> > sigma_sumvars=make_unique_variables(sumvars,hint);
    8719        1808 :         const variable_list unique_sumvars=data::replace_variables(sumvars, sigma_sumvars);
    8720             : 
    8721         904 :         assert(unique_sumvars.size()==sumvars.size());
    8722        1808 :         data_expression condition=smmnd.condition();
    8723        1808 :         data_expression actiontime=smmnd.deadlock().time();
    8724             : 
    8725         904 :         condition=replace_variables_capture_avoiding_alt(condition, sigma_sumvars);
    8726         904 :         condition=replace_variables_capture_avoiding_alt(condition, sigma);
    8727             : 
    8728         904 :         actiontime=replace_variables_capture_avoiding_alt(actiontime, sigma_sumvars);
    8729         904 :         actiontime=replace_variables_capture_avoiding_alt(actiontime, sigma);
    8730             : 
    8731         904 :         result_deadlock_summands.push_back(deadlock_summand(unique_sumvars,
    8732             :                                                             condition,
    8733        1808 :                                                             s->deadlock().has_time()?deadlock(actiontime):deadlock()));
    8734             :       }
    8735         881 :       pars=unique_pars;
    8736         881 :       result_deadlock_summands.swap(deadlock_summands);
    8737         881 :     }
    8738             : 
    8739             : 
    8740             : 
    8741             : 
    8742             : 
    8743             :     /**************** parallel composition ******************************/
    8744             : 
    8745             : 
    8746             : 
    8747             :     /// \brief Returns the conjunction of the two delay conditions and the join of the variables, where
    8748             :     ///        the variables in delay2 are renamed to avoid conflict with those in delay1.
    8749         342 :     lps::detail::ultimate_delay combine_ultimate_delays(
    8750             :                            const lps::detail::ultimate_delay& delay1,
    8751             :                            const lps::detail::ultimate_delay& delay2)
    8752             :     {
    8753             :       // Make the bound variables of the second ultimate delay different from those in the first.
    8754         684 :       variable_list renameable_variables=delay2.variables();
    8755         684 :       maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    8756         342 :       alphaconvert(renameable_variables, sigma, delay1.variables(), data_expression_list());
    8757             :       // Additionally map the time variable of the second ultimate delay to that of the first.
    8758         342 :       sigma[delay2.time_var()]=delay1.time_var();
    8759             :       data_expression new_constraint = optimized_and(delay1.constraint(),
    8760         684 :                                                      replace_variables_capture_avoiding_alt(delay2.constraint(),sigma));
    8761         684 :       variable_list new_existential_variables = delay1.variables()+renameable_variables;
    8762             : 
    8763             :       // TODO: The new constraint can be simplified, as two conditions sharing the timed variable have been merged.
    8764             :       return lps::detail::ultimate_delay(
    8765             :                             delay1.time_var(),
    8766             :                             new_existential_variables,
    8767         684 :                             new_constraint);
    8768             :     }
    8769             : 
    8770         684 :     void calculate_left_merge_action(
    8771             :       const lps::detail::ultimate_delay& ultimate_delay_condition,
    8772             :       const stochastic_action_summand_vector& action_summands1,
    8773             :       const action_name_multiset_list& allowlist,  // This is a list of list of identifierstring.
    8774             :       const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    8775             :       const bool is_block,
    8776             :       stochastic_action_summand_vector& action_summands)
    8777             :     {
    8778        9645 :       for (const stochastic_action_summand& summand1: action_summands1)
    8779             :       {
    8780       17922 :         variable_list sumvars=ultimate_delay_condition.variables();
    8781       17922 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    8782        8961 :         alphaconvert(sumvars,sigma,summand1.summation_variables(),data_expression_list());
    8783             : 
    8784       17922 :         variable_list sumvars1=summand1.summation_variables() + sumvars;
    8785       17922 :         action_list multiaction1=summand1.multi_action().actions();
    8786       17922 :         data_expression actiontime1=summand1.multi_action().time();
    8787       17922 :         data_expression condition1=summand1.condition();
    8788        8961 :         const assignment_list& nextstate1=summand1.assignments();
    8789        8961 :         const stochastic_distribution& distribution1=summand1.distribution();
    8790        8961 :         bool has_time=summand1.has_time();
    8791             : 
    8792        8961 :         if (multiaction1 != action_list({ terminationAction }))
    8793             :         {
    8794        8865 :           if (is_allow && !allow_(allowlist,multiaction1))
    8795             :           {
    8796           0 :             continue;
    8797             :           }
    8798        8865 :           if (is_block && encap(allowlist,multiaction1))
    8799             :           {
    8800           0 :             continue;
    8801             :           }
    8802             : 
    8803        8865 :           if (!options.ignore_time)
    8804             :           {
    8805        8865 :             if (!has_time)
    8806             :             {
    8807        8698 :               if (ultimate_delay_condition.constraint()!=sort_bool::true_())
    8808             :               {
    8809         104 :                 actiontime1=ultimate_delay_condition.time_var();
    8810         104 :                 sumvars1.push_front(ultimate_delay_condition.time_var());
    8811         104 :                 condition1=lazy::and_(condition1,
    8812         208 :                                       replace_variables_capture_avoiding_alt(ultimate_delay_condition.constraint(), sigma));
    8813         104 :                 has_time=true;
    8814             :               }
    8815             :             }
    8816             :             else
    8817             :             {
    8818             :               /* Summand1 has time. Substitute the time expression for
    8819             :                  timevar in ultimate_delay_condition, and extend the condition */
    8820         334 :               const std::set<variable> variables_in_actiontime1=find_free_variables(actiontime1);
    8821         167 :               sigma[ultimate_delay_condition.time_var()]=actiontime1;
    8822             :               const data_expression intermediateultimatedelaycondition=
    8823         334 :                          replace_variables_capture_avoiding_alt(ultimate_delay_condition.constraint(),sigma);
    8824         167 :               condition1=optimized_and(condition1, intermediateultimatedelaycondition);
    8825             :             }
    8826             : 
    8827        8865 :             condition1=RewriteTerm(condition1);
    8828             :           }
    8829             : 
    8830        8865 :           if (condition1!=sort_bool::false_())
    8831             :           {
    8832        8841 :             action_summands.push_back(stochastic_action_summand(
    8833             :                                              sumvars1,
    8834             :                                              condition1,
    8835       17682 :                                              has_time?multi_action(multiaction1, actiontime1):multi_action(multiaction1),
    8836             :                                              nextstate1,
    8837             :                                              distribution1));
    8838             :           }
    8839             :         }
    8840             :       }
    8841         684 :     }
    8842             : 
    8843         684 :     void calculate_left_merge_deadlock(
    8844             :       const lps::detail::ultimate_delay& ultimate_delay_condition,
    8845             :       const deadlock_summand_vector& deadlock_summands1,
    8846             :       const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    8847             :       const bool is_block,
    8848             :       const stochastic_action_summand_vector& action_summands,
    8849             :       deadlock_summand_vector& deadlock_summands)
    8850             :     {
    8851         684 :       bool inline_allow = is_allow || is_block;
    8852             : 
    8853         684 :       if (!inline_allow)
    8854             :       {
    8855        1404 :         for (const deadlock_summand& summand1: deadlock_summands1)
    8856             :         {
    8857        1440 :           variable_list sumvars=ultimate_delay_condition.variables();
    8858        1440 :           maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    8859         720 :           alphaconvert(sumvars,sigma,summand1.summation_variables(),data_expression_list());
    8860             : 
    8861        1440 :           variable_list sumvars1=summand1.summation_variables() + sumvars;
    8862        1440 :           data_expression actiontime1=summand1.deadlock().time();
    8863        1440 :           data_expression condition1=summand1.condition();
    8864         720 :           bool has_time=summand1.deadlock().has_time();
    8865             : 
    8866         720 :           if (!options.ignore_time)
    8867             :           {
    8868         720 :             if (!has_time)
    8869             :             {
    8870         594 :               if (ultimate_delay_condition.constraint()!=sort_bool::true_())
    8871             :               {
    8872          79 :                 actiontime1=ultimate_delay_condition.time_var();
    8873          79 :                 sumvars1.push_front(ultimate_delay_condition.time_var());
    8874          79 :                 condition1=optimized_and(condition1,
    8875         158 :                                          replace_variables_capture_avoiding_alt(ultimate_delay_condition.constraint(),
    8876             :                                                                                   sigma));
    8877          79 :                 has_time=true;
    8878             :               }
    8879             :             }
    8880             :             else
    8881             :             {
    8882             :               /* Summand1 has time. Substitute the time expression for
    8883             :                  timevar in ultimate_delay_condition, and extend the condition */
    8884         252 :               const std::set<variable> variables_in_actiontime1=find_free_variables(actiontime1);
    8885         126 :               sigma[ultimate_delay_condition.time_var()]=actiontime1;
    8886             :               const data_expression intermediateultimatedelaycondition=
    8887         252 :                          replace_variables_capture_avoiding_alt(ultimate_delay_condition.constraint(),sigma);
    8888         126 :               condition1=optimized_and(condition1, intermediateultimatedelaycondition);
    8889             :             }
    8890             : 
    8891         720 :             condition1=RewriteTerm(condition1);
    8892             :           }
    8893             : 
    8894         720 :           if (condition1!=sort_bool::false_() && !options.ignore_time)
    8895             :           {
    8896         648 :             insert_timed_delta_summand(action_summands,
    8897             :                                        deadlock_summands,
    8898        1296 :                                        deadlock_summand(sumvars1,condition1, has_time?deadlock(actiontime1):deadlock()));
    8899             :           }
    8900             :         }
    8901             :       }
    8902         684 :     }
    8903             : 
    8904         684 :     void calculate_left_merge(
    8905             :       const stochastic_action_summand_vector& action_summands1,
    8906             :       const deadlock_summand_vector& deadlock_summands1,
    8907             :       const lps::detail::ultimate_delay& ultimate_delay_condition2,
    8908             :       const action_name_multiset_list& allowlist,  // This is a list of list of identifierstring.
    8909             :       const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    8910             :       const bool is_block,
    8911             :       stochastic_action_summand_vector& action_summands,
    8912             :       deadlock_summand_vector& deadlock_summands)
    8913             :     {
    8914         684 :       calculate_left_merge_deadlock(ultimate_delay_condition2, deadlock_summands1,
    8915             :                                     is_allow, is_block, action_summands, deadlock_summands);
    8916         684 :       calculate_left_merge_action(ultimate_delay_condition2, action_summands1,
    8917             :                                     allowlist, is_allow, is_block, action_summands);
    8918         684 :     }
    8919             : 
    8920             : 
    8921             : 
    8922         342 :     void calculate_communication_merge_action_summands(
    8923             :           const stochastic_action_summand_vector& action_summands1,
    8924             :           const stochastic_action_summand_vector& action_summands2,
    8925             :           const action_name_multiset_list& allowlist,   // This is a list of list of identifierstring.
    8926             :           const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    8927             :           const bool is_block,
    8928             :           stochastic_action_summand_vector& action_summands)
    8929             :     {
    8930             :       // First combine the action summands.
    8931        1290 :       for (const stochastic_action_summand& summand1: action_summands1)
    8932             :       {
    8933         948 :         const variable_list& sumvars1=summand1.summation_variables();
    8934        1896 :         const action_list multiaction1=summand1.multi_action().actions();
    8935        1896 :         const data_expression actiontime1=summand1.multi_action().time();
    8936         948 :         const data_expression& condition1=summand1.condition();
    8937         948 :         const assignment_list& nextstate1=summand1.assignments();
    8938         948 :         const stochastic_distribution& distribution1=summand1.distribution();
    8939             : 
    8940       32540 :         for (const stochastic_action_summand& summand2: action_summands2)
    8941             :         {
    8942       31592 :           const variable_list& sumvars2=summand2.summation_variables();
    8943       63184 :           const action_list multiaction2=summand2.multi_action().actions();
    8944       63184 :           const data_expression actiontime2=summand2.multi_action().time();
    8945       31592 :           const data_expression& condition2=summand2.condition();
    8946       31592 :           const assignment_list& nextstate2=summand2.assignments();
    8947       31592 :           const stochastic_distribution& distribution2=summand2.distribution();
    8948             : 
    8949       31592 :           if ((multiaction1 == action_list({ terminationAction })) == (multiaction2 == action_list({ terminationAction })))
    8950             :           {
    8951       62804 :             action_list multiaction3;
    8952       31402 :             if ((multiaction1 == action_list({ terminationAction })) && (multiaction2 == action_list({ terminationAction })))
    8953             :             {
    8954          36 :               multiaction3.push_front(terminationAction);
    8955             :             }
    8956             :             else
    8957             :             {
    8958       31366 :               multiaction3=linMergeMultiActionList(multiaction1,multiaction2);
    8959             :             }
    8960             : 
    8961       31402 :             if (is_allow && !allow_(allowlist,multiaction3))
    8962             :             {
    8963           0 :               continue;
    8964             :             }
    8965       31402 :             if (is_block && encap(allowlist,multiaction3))
    8966             :             {
    8967           0 :               continue;
    8968             :             }
    8969             : 
    8970       62804 :             const variable_list allsums=sumvars1+sumvars2;
    8971       62804 :             data_expression condition3= lazy::and_(condition1,condition2);
    8972       62804 :             data_expression action_time3;
    8973       31402 :             bool has_time3=summand1.has_time()||summand2.has_time();
    8974             : 
    8975       31402 :             if (!summand1.has_time())
    8976             :             {
    8977       31323 :               if (summand2.has_time())
    8978             :               {
    8979             :                 /* summand 2 has time*/
    8980          24 :                 action_time3=actiontime2;
    8981             :               }
    8982             :             }
    8983             :             else
    8984             :             {
    8985             :               /* summand 1 has time */
    8986          79 :               if (!summand2.has_time())
    8987             :               {
    8988          49 :                 action_time3=actiontime1;
    8989             :               }
    8990             :               else
    8991             :               {
    8992             :                 /* both summand 1 and 2 have time */
    8993          30 :                 action_time3=actiontime1;
    8994          30 :                 condition3=lazy::and_(
    8995             :                              condition3,
    8996          60 :                              equal_to(actiontime1,actiontime2));
    8997             :               }
    8998             :             }
    8999             : 
    9000       62804 :             const assignment_list nextstate3=nextstate1+nextstate2;
    9001             :             const stochastic_distribution distribution3(
    9002       62804 :                                               distribution1.variables()+distribution2.variables(),
    9003      125608 :                                               real_times_optimized(distribution1.distribution(),distribution2.distribution()));
    9004             : 
    9005       31402 :             condition3=RewriteTerm(condition3);
    9006       31402 :             if (condition3!=sort_bool::false_())
    9007             :             {
    9008       31384 :               action_summands.push_back(stochastic_action_summand(
    9009             :                                            allsums,
    9010             :                                            condition3,
    9011       62768 :                                            has_time3?multi_action(multiaction3,action_time3):multi_action(multiaction3),
    9012             :                                            nextstate3,
    9013             :                                            distribution3));
    9014             :             }
    9015             :           }
    9016             :         }
    9017             :       }
    9018         342 :     }
    9019             : 
    9020         684 :     void calculate_communication_merge_action_deadlock_summands(
    9021             :           const stochastic_action_summand_vector& action_summands1,
    9022             :           const deadlock_summand_vector& deadlock_summands1,
    9023             :           const stochastic_action_summand_vector& action_summands,
    9024             :           deadlock_summand_vector& deadlock_summands)
    9025             :     {
    9026        9645 :       for (const stochastic_action_summand& summand1: action_summands1)
    9027             :       {
    9028        8961 :         const variable_list& sumvars1=summand1.summation_variables();
    9029       17922 :         const data_expression actiontime1=summand1.multi_action().time();
    9030        8961 :         const data_expression& condition1=summand1.condition();
    9031             : 
    9032       18089 :         for (const deadlock_summand& summand2: deadlock_summands1)
    9033             :         {
    9034        9128 :           const variable_list& sumvars2=summand2.summation_variables();
    9035       18256 :           const data_expression actiontime2=summand2.deadlock().time();
    9036        9128 :           const data_expression& condition2=summand2.condition();
    9037             : 
    9038       18256 :           const variable_list allsums=sumvars1+sumvars2;
    9039       18256 :           const data_expression condition3= lazy::and_(condition1,condition2);
    9040       18256 :           data_expression action_time3;
    9041        9128 :           bool has_time3=summand1.has_time()||summand2.has_time();
    9042             : 
    9043        9128 :           if (!summand1.has_time())
    9044             :           {
    9045        8938 :             if (summand2.has_time())
    9046             :             {
    9047             :               /* summand 2 has time*/
    9048          42 :               action_time3=actiontime2;
    9049             :             }
    9050             :           }
    9051             :           else
    9052             :           {
    9053             :             /* summand 1 has time */
    9054         190 :             if (!summand2.has_time())
    9055             :             {
    9056         118 :               action_time3=actiontime1;
    9057             :             }
    9058             :             else
    9059             :             {
    9060             :               /* both summand 1 and 2 have time */
    9061          72 :               action_time3=RewriteTerm(sort_real::minimum(actiontime1,actiontime2));
    9062             :             }
    9063             :           }
    9064             : 
    9065        9128 :           if (condition3!=sort_bool::false_() && !options.ignore_time)
    9066             :           {
    9067        9128 :             insert_timed_delta_summand(action_summands,
    9068             :                                        deadlock_summands,
    9069       18256 :                                        deadlock_summand(allsums,
    9070             :                                                         condition3,
    9071       18256 :                                                         has_time3?deadlock(action_time3):deadlock()));
    9072             :           }
    9073             : 
    9074             :         }
    9075             :       }
    9076         684 :     }
    9077             : 
    9078         342 :     void calculate_communication_merge_deadlock_summands(
    9079             :           const deadlock_summand_vector& deadlock_summands1,
    9080             :           const deadlock_summand_vector& deadlock_summands2,
    9081             :           const stochastic_action_summand_vector& action_summands,
    9082             :           deadlock_summand_vector& deadlock_summands)
    9083             :     {
    9084         714 :       for (const deadlock_summand& summand1: deadlock_summands1)
    9085             :       {
    9086         372 :         const variable_list& sumvars1=summand1.summation_variables();
    9087         744 :         const data_expression actiontime1=summand1.deadlock().time();
    9088         372 :         const data_expression& condition1=summand1.condition();
    9089             : 
    9090         829 :         for (const deadlock_summand& summand2: deadlock_summands2)
    9091             :         {
    9092         457 :           const variable_list& sumvars2=summand2.summation_variables();
    9093         914 :           const data_expression actiontime2=summand2.deadlock().time();
    9094         457 :           const data_expression& condition2=summand2.condition();
    9095             : 
    9096         914 :           const variable_list allsums=sumvars1+sumvars2;
    9097         914 :           const data_expression condition3= lazy::and_(condition1,condition2);
    9098         914 :           data_expression action_time3;
    9099         457 :           bool has_time3=summand1.has_time()||summand2.has_time();
    9100             : 
    9101         457 :           if (!summand1.has_time())
    9102             :           {
    9103         385 :             if (summand2.has_time())
    9104             :             {
    9105             :               /* summand 2 has time*/
    9106          18 :               action_time3=actiontime2;
    9107             :             }
    9108             :           }
    9109             :           else
    9110             :           {
    9111             :             /* summand 1 has time */
    9112          72 :             if (!summand2.has_time())
    9113             :             {
    9114          24 :               action_time3=actiontime1;
    9115             :             }
    9116             :             else
    9117             :             {
    9118             :               /* both summand 1 and 2 have time */
    9119          48 :               action_time3=RewriteTerm(sort_real::minimum(actiontime1,actiontime2));
    9120             :             }
    9121             :           }
    9122             : 
    9123         457 :           if (condition3!=sort_bool::false_() && !options.ignore_time)
    9124             :           {
    9125         457 :             insert_timed_delta_summand(action_summands,
    9126             :                                        deadlock_summands,
    9127         914 :                                        deadlock_summand(allsums,
    9128             :                                                         condition3,
    9129         914 :                                                         has_time3?deadlock(action_time3):deadlock()));
    9130             :           }
    9131             : 
    9132             :         }
    9133             :       }
    9134         342 :     }
    9135             : 
    9136         342 :     void calculate_communication_merge(
    9137             :           const stochastic_action_summand_vector& action_summands1,
    9138             :           const deadlock_summand_vector& deadlock_summands1,
    9139             :           const stochastic_action_summand_vector& action_summands2,
    9140             :           const deadlock_summand_vector& deadlock_summands2,
    9141             :           const action_name_multiset_list& allowlist,   // This is a list of list of identifierstring.
    9142             :           const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    9143             :           const bool is_block,
    9144             :           stochastic_action_summand_vector& action_summands,
    9145             :           deadlock_summand_vector& deadlock_summands)
    9146             :     {
    9147         342 :       calculate_communication_merge_action_summands(action_summands1, action_summands2, allowlist, is_allow, is_block, action_summands);
    9148         342 :       calculate_communication_merge_action_deadlock_summands(action_summands1, deadlock_summands2, action_summands, deadlock_summands);
    9149         342 :       calculate_communication_merge_action_deadlock_summands(action_summands2, deadlock_summands1, action_summands, deadlock_summands);
    9150         342 :       calculate_communication_merge_deadlock_summands(deadlock_summands1, deadlock_summands2, action_summands, deadlock_summands);
    9151         342 :     }
    9152             : 
    9153             : 
    9154         342 :     void combine_summand_lists(
    9155             :       const stochastic_action_summand_vector& action_summands1,
    9156             :       const deadlock_summand_vector& deadlock_summands1,
    9157             :       const lps::detail::ultimate_delay& ultimate_delay_condition1,
    9158             :       const stochastic_action_summand_vector& action_summands2,
    9159             :       const deadlock_summand_vector& deadlock_summands2,
    9160             :       const lps::detail::ultimate_delay& ultimate_delay_condition2,
    9161             :       const variable_list& par1,
    9162             :       const variable_list& par3,
    9163             :       const action_name_multiset_list& allowlist1,  // This is a list of list of identifierstring.
    9164             :       const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    9165             :       const bool is_block,
    9166             :       stochastic_action_summand_vector& action_summands,
    9167             :       deadlock_summand_vector& deadlock_summands)
    9168             :     {
    9169         342 :       assert(action_summands.size()==0);
    9170         342 :       assert(deadlock_summands.size()==0);
    9171             : 
    9172         684 :       variable_list allpars;
    9173         342 :       allpars=par1 + par3;
    9174             : 
    9175         342 :       bool inline_allow = is_allow || is_block;
    9176         342 :       if (inline_allow)
    9177             :       {
    9178             :         // Inline allow is only supported for ignore_time,
    9179             :         // for in other cases generation of delta summands cannot be inlined in any simple way.
    9180           0 :         assert(!options.nodeltaelimination && options.ignore_time);
    9181           0 :         deadlock_summands.push_back(deadlock_summand(variable_list(),sort_bool::true_(),deadlock()));
    9182             :       }
    9183             : 
    9184             :       /* first we enumerate the summands of t1 */
    9185             : 
    9186         684 :       action_name_multiset_list allowlist((is_allow)?sort_multi_action_labels(allowlist1):allowlist1);
    9187         342 :       calculate_left_merge(action_summands1, deadlock_summands1,
    9188             :                            ultimate_delay_condition2, allowlist, is_allow, is_block,
    9189             :                            action_summands, deadlock_summands);
    9190             : 
    9191             :       /* second we enumerate the summands of sumlist2 */
    9192         342 :       calculate_left_merge(action_summands2, deadlock_summands2,
    9193             :                            ultimate_delay_condition1, allowlist, is_allow, is_block,
    9194             :                            action_summands, deadlock_summands);
    9195             : 
    9196             :       /* thirdly we enumerate all multi actions*/
    9197             : 
    9198         342 :       calculate_communication_merge(action_summands1, deadlock_summands1, action_summands2, deadlock_summands2,
    9199             :                                     allowlist, is_allow, is_block, action_summands, deadlock_summands);
    9200         342 :     }
    9201             : 
    9202             : 
    9203         342 :     void parallelcomposition(
    9204             :       const stochastic_action_summand_vector& action_summands1,
    9205             :       const deadlock_summand_vector& deadlock_summands1,
    9206             :       const variable_list& pars1,
    9207             :       const data_expression_list& init1,
    9208             :       const stochastic_distribution& initial_stochastic_distribution1,
    9209             :       const lps::detail::ultimate_delay& ultimate_delay_condition1,
    9210             :       const stochastic_action_summand_vector& action_summands2,
    9211             :       const deadlock_summand_vector& deadlock_summands2,
    9212             :       const variable_list& pars2,
    9213             :       const data_expression_list& init2,
    9214             :       const stochastic_distribution& initial_stochastic_distribution2,
    9215             :       const lps::detail::ultimate_delay& ultimate_delay_condition2,
    9216             :       const action_name_multiset_list& allowlist1,  // This is a list of list of identifierstring.
    9217             :       const bool is_allow,                          // If is_allow or is_block is set, perform inline allow/block filtering.
    9218             :       const bool is_block,
    9219             :       stochastic_action_summand_vector& action_summands,
    9220             :       deadlock_summand_vector& deadlock_summands,
    9221             :       variable_list& pars_result,
    9222             :       data_expression_list& init_result,
    9223             :       stochastic_distribution& initial_stochastic_distribution,
    9224             :       lps::detail::ultimate_delay& ultimate_delay_condition)
    9225             :     {
    9226         342 :       mCRL2log(mcrl2::log::verbose) <<
    9227             :             (is_allow ? "- calculating the parallel composition modulo the allow operator: " :
    9228           0 :              is_block ? "- calculating the parallel composition modulo the block operator: " :
    9229           0 :                         "- calculating the parallel composition: ") <<
    9230           0 :             action_summands1.size() <<
    9231           0 :             " action summands + " << deadlock_summands1.size() <<
    9232           0 :             " deadlock summands || " << action_summands2.size() <<
    9233           0 :             " action summands + " << deadlock_summands2.size() << " deadlock summands = ";
    9234             : 
    9235             :       // At this point the parameters of pars1 and pars2 are unique, except for
    9236             :       // those that are constant in both processes.
    9237             : 
    9238         684 :       variable_list pars3;
    9239        1295 :       for (const variable& v: pars2)
    9240             :       {
    9241         953 :         if (std::find(pars1.begin(),pars1.end(),v)==pars1.end())
    9242             :         {
    9243             :           // *i does not occur in pars1.
    9244         953 :           pars3.push_front(v);
    9245             :         }
    9246             :       }
    9247             : 
    9248         342 :       pars3=reverse(pars3);
    9249         342 :       assert(action_summands.size()==0);
    9250         342 :       assert(deadlock_summands.size()==0);
    9251         342 :       combine_summand_lists(action_summands1,deadlock_summands1,ultimate_delay_condition1,
    9252             :                             action_summands2,deadlock_summands2,ultimate_delay_condition2,
    9253             :                             pars1,pars3,allowlist1,is_allow,is_block,action_summands,deadlock_summands);
    9254             : 
    9255         342 :       mCRL2log(mcrl2::log::verbose) << action_summands.size() << " actions and " << deadlock_summands.size() << " delta summands.\n";
    9256         342 :       pars_result=pars1+pars3;
    9257         342 :       init_result=init1 + init2;
    9258         342 :       initial_stochastic_distribution=stochastic_distribution(
    9259         684 :                                           initial_stochastic_distribution1.variables()+initial_stochastic_distribution2.variables(),
    9260         684 :                                           data::sort_real::times(initial_stochastic_distribution1.distribution(),
    9261             :                                                                  initial_stochastic_distribution2.distribution()));
    9262         342 :       if (!options.ignore_time)
    9263             :       {
    9264         342 :         ultimate_delay_condition=combine_ultimate_delays(ultimate_delay_condition1, ultimate_delay_condition2);
    9265             :       }
    9266         342 :     }
    9267             : 
    9268             :     /**************** GENERaTE LPEmCRL **********************************/
    9269             : 
    9270             : 
    9271             :     /// \brief Linearise a process indicated by procIdDecl.
    9272             :     /// \details Returns actions_summands, deadlock_summands, the process parameters
    9273             :     ///              and the initial assignment list.
    9274             : 
    9275        1479 :     void generateLPEmCRLterm(
    9276             :       stochastic_action_summand_vector& action_summands,
    9277             :       deadlock_summand_vector& deadlock_summands,
    9278             :       const process_expression& t,    
    9279             :       const bool regular,
    9280             :       const bool rename_variables,
    9281             :       variable_list& pars,
    9282             :       data_expression_list& init,
    9283             :       stochastic_distribution& initial_stochastic_distribution,
    9284             :       lps::detail::ultimate_delay& ultimate_delay_condition)
    9285             :     {
    9286        1479 :       if (is_process_instance_assignment(t))
    9287             :       {
    9288         911 :         generateLPEmCRL(action_summands,deadlock_summands,process_instance_assignment(t).identifier(),
    9289             :                         regular,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9290         911 :         objectdatatype& object=objectIndex(process_instance_assignment(t).identifier());
    9291        1822 :         const assignment_list ass=process_instance_assignment(t).assignments();
    9292             : 
    9293        1822 :         maintain_variables_in_rhs<mutable_map_substitution<> > sigma;
    9294        1386 :         for (assignment_list::const_iterator i=ass.begin();  i!=ass.end(); ++i)
    9295             :         {
    9296         475 :           sigma[i->lhs()]=i->rhs();
    9297         475 :           const std::set<variable> varset=find_free_variables(i->rhs());
    9298             :         }
    9299             : 
    9300             :         // init=substitute_assignmentlist(init,pars,false,true,sigma);   ZZZ
    9301         911 :         init=replace_variables_capture_avoiding_alt(init,sigma);
    9302             : 
    9303             :         // Make the bound variables and parameters in this process unique.
    9304             : 
    9305         941 :         if ((object.processstatus==GNF)||
    9306          60 :             (object.processstatus==pCRL)||
    9307          30 :             (object.processstatus==GNFalpha))
    9308             :         {
    9309         881 :           make_parameters_and_sum_variables_unique(action_summands,deadlock_summands,pars,ultimate_delay_condition,std::string(object.objectname));
    9310             :         }
    9311             :         else
    9312             :         {
    9313          30 :           if (rename_variables)
    9314             :           {
    9315           0 :             make_parameters_and_sum_variables_unique(action_summands,deadlock_summands,pars,ultimate_delay_condition);
    9316             :           }
    9317             :         }
    9318             : 
    9319         911 :         if (regular && !options.do_not_apply_constelm)
    9320             :         {
    9321             :           // We apply constant elimination on the obtained linear process.
    9322             :           // In order to do so, we have to create a complete process specification first, as
    9323             :           // this is what the interface of constelm requires.
    9324             :           // Note that this is only useful, in regular mode. This does not make sense if
    9325             :           // stacks are being used.
    9326             : 
    9327        1402 :           stochastic_linear_process lps(pars,deadlock_summands,action_summands);
    9328             :           // stochastic_process_initializer initializer(init,stochastic_distribution(variable_list(),real_one())); // Default distribution.
    9329        1402 :           stochastic_process_initializer initializer(init,initial_stochastic_distribution); 
    9330             : 
    9331        1402 :           stochastic_specification temporary_spec(data,acts,global_variables,lps,initializer);
    9332        1402 :           constelm_algorithm < rewriter, stochastic_specification > alg(temporary_spec,rewr);
    9333             : 
    9334             :           // Remove constants from the specification, where global variables are
    9335             :           // also instantiated if they exist.
    9336        1402 :           data::mutable_map_substitution<> sigma = alg.compute_constant_parameters(true);
    9337         701 :           alg.remove_parameters(sigma);
    9338             : 
    9339         701 :           if (!options.ignore_time)
    9340             :           {
    9341         701 :             ultimate_delay_condition.constraint()=data::replace_variables(ultimate_delay_condition.constraint(),sigma);
    9342             :           }
    9343             : 
    9344             :           // Reconstruct the variables from the temporary specification
    9345         701 :           init=temporary_spec.initial_process().expressions();     
    9346         701 :           pars=temporary_spec.process().process_parameters();
    9347         701 :           assert(init.size()==pars.size());
    9348             : 
    9349             :           // Add all free variables in object.parameters that are not already in the parameter list
    9350             :           // and are not global variables to pars. This can occur when a parameter of the process is replaced
    9351             :           // by a constant, which by itself is a parameter.
    9352             : 
    9353        1402 :           std::set <variable> variable_list = lps::find_free_variables(temporary_spec.process().action_summands());
    9354        1402 :           const std::set <variable> variable_list1 = lps::find_free_variables(temporary_spec.process().deadlock_summands());
    9355         701 :           variable_list.insert(variable_list1.begin(),variable_list1.end());
    9356        2522 :           for (std::set <variable>::const_iterator i=variable_list.begin();
    9357        2522 :                i!=variable_list.end(); ++i)
    9358             :           {
    9359        4460 :             if (std::find(pars.begin(),pars.end(),*i)==pars.end() && // The free variable is not in pars,
    9360        2639 :                 global_variables.find(*i)==global_variables.end() // it is neither a global variable
    9361             :                 // (lps::search_free_variable(temporary_spec.process().action_summands(),*i) || lps::search_free_variable(temporary_spec.process().deadlock_summands(),*i))
    9362             :                )          // and it occurs in the summands.
    9363             :             {
    9364           0 :               pars.push_front(*i);
    9365             :             }
    9366             :           }
    9367             : 
    9368         701 :           action_summands=temporary_spec.process().action_summands();
    9369         701 :           deadlock_summands=temporary_spec.process().deadlock_summands();
    9370             :         }
    9371             :         // Now constelm has been applied.
    9372         911 :         return;
    9373             :       } // End process assignment. 
    9374             : 
    9375         568 :       if (is_merge(t))
    9376             :       {
    9377         684 :         variable_list pars1,pars2;
    9378         684 :         data_expression_list init1,init2;
    9379         684 :         stochastic_distribution initial_stochastic_distribution1, initial_stochastic_distribution2;
    9380         684 :         stochastic_action_summand_vector action_summands1, action_summands2;
    9381         684 :         deadlock_summand_vector deadlock_summands1, deadlock_summands2;
    9382         684 :         lps::detail::ultimate_delay ultimate_delay_condition1, ultimate_delay_condition2;
    9383         342 :         generateLPEmCRLterm(action_summands1,deadlock_summands1,process::merge(t).left(),
    9384             :                               regular,rename_variables,pars1,init1,initial_stochastic_distribution1,ultimate_delay_condition1);
    9385         342 :         generateLPEmCRLterm(action_summands2,deadlock_summands2,process::merge(t).right(),
    9386             :                               regular,true,pars2,init2,initial_stochastic_distribution2,ultimate_delay_condition2);
    9387         342 :         parallelcomposition(action_summands1,deadlock_summands1,pars1,init1,initial_stochastic_distribution1,ultimate_delay_condition1,
    9388             :                               action_summands2,deadlock_summands2,pars2,init2,initial_stochastic_distribution2,ultimate_delay_condition2,
    9389         684 :                               action_name_multiset_list(),false,false,
    9390             :                               action_summands,deadlock_summands,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9391         342 :         return;
    9392             :       }
    9393             : 
    9394         226 :       if (is_hide(t))
    9395             :       {
    9396          18 :         generateLPEmCRLterm(action_summands,deadlock_summands,hide(t).operand(),
    9397             :                               regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9398          18 :         hidecomposition(hide(t).hide_set(),action_summands);
    9399          18 :         return;
    9400             :       }
    9401             : 
    9402         208 :       if (is_allow(t))
    9403             :       {
    9404         178 :         process_expression par = allow(t).operand();
    9405          89 :         if (!options.nodeltaelimination && options.ignore_time && is_merge(par))
    9406             :         {
    9407             :           // Perform parallel composition with inline allow.
    9408           0 :           variable_list pars1,pars2;
    9409           0 :           data_expression_list init1,init2;
    9410           0 :           stochastic_distribution initial_stochastic_distribution1, initial_stochastic_distribution2;
    9411           0 :           stochastic_action_summand_vector action_summands1, action_summands2;
    9412           0 :           deadlock_summand_vector deadlock_summands1, deadlock_summands2;
    9413           0 :           lps::detail::ultimate_delay ultimate_delay_condition1, ultimate_delay_condition2;
    9414           0 :           generateLPEmCRLterm(action_summands1,deadlock_summands1,process::merge(par).left(),
    9415             :                                 regular,rename_variables,pars1,init1,initial_stochastic_distribution1,ultimate_delay_condition1);
    9416           0 :           generateLPEmCRLterm(action_summands2,deadlock_summands2,process::merge(par).right(),
    9417             :                                 regular,true,pars2,init2,initial_stochastic_distribution2,ultimate_delay_condition2);
    9418           0 :           parallelcomposition(action_summands1,deadlock_summands1,pars1,init1,initial_stochastic_distribution1,ultimate_delay_condition1,
    9419             :                                 action_summands2,deadlock_summands2,pars2,init2,initial_stochastic_distribution2,ultimate_delay_condition2,
    9420           0 :                                 allow(t).allow_set(),true,false,
    9421             :                                 action_summands,deadlock_summands,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9422           0 :           return;
    9423             :         }
    9424          89 :         else if (!options.nodeltaelimination && options.ignore_time && is_comm(par))
    9425             :         {
    9426           0 :           generateLPEmCRLterm(action_summands,deadlock_summands,comm(par).operand(),
    9427             :                                 regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9428           0 :           communicationcomposition(comm(par).comm_set(),allow(t).allow_set(),true,false,action_summands,deadlock_summands);
    9429           0 :           return;
    9430             :         }
    9431             : 
    9432          89 :         generateLPEmCRLterm(action_summands,deadlock_summands,par,regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9433          89 :         allowblockcomposition(allow(t).allow_set(),true,action_summands,deadlock_summands);
    9434          89 :         return;
    9435             :       }
    9436             : 
    9437         119 :       if (is_block(t))
    9438             :       {
    9439           0 :         process_expression par = block(t).operand();
    9440           0 :         if (!options.nodeltaelimination && options.ignore_time && is_merge(par))
    9441             :         {
    9442             :           // Perform parallel composition with inline block.
    9443           0 :           variable_list pars1,pars2;
    9444           0 :           data_expression_list init1,init2;
    9445           0 :           stochastic_distribution initial_stochastic_distribution1, initial_stochastic_distribution2;
    9446           0 :           stochastic_action_summand_vector action_summands1, action_summands2;
    9447           0 :           deadlock_summand_vector deadlock_summands1, deadlock_summands2;
    9448           0 :           lps::detail::ultimate_delay ultimate_delay_condition1, ultimate_delay_condition2;
    9449           0 :           generateLPEmCRLterm(action_summands1,deadlock_summands1,process::merge(par).left(),
    9450             :                                 regular,rename_variables,pars1,init1,initial_stochastic_distribution1,ultimate_delay_condition1);
    9451           0 :           generateLPEmCRLterm(action_summands2,deadlock_summands2,process::merge(par).right(),
    9452             :                                 regular,true,pars2,init2,initial_stochastic_distribution2,ultimate_delay_condition2);
    9453             :           // Encode the actions of the block list in one multi action.
    9454           0 :           parallelcomposition(action_summands1,deadlock_summands1,pars1,init1,initial_stochastic_distribution1,ultimate_delay_condition1,
    9455             :                                 action_summands2,deadlock_summands2,pars2,init2,initial_stochastic_distribution2,ultimate_delay_condition2,
    9456           0 :                                 action_name_multiset_list({action_name_multiset(block(t).block_set())}),false,true,
    9457             :                                 action_summands,deadlock_summands,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9458           0 :           return;
    9459             :         }
    9460           0 :         else if (!options.nodeltaelimination && options.ignore_time && is_comm(par))
    9461             :         {
    9462           0 :           generateLPEmCRLterm(action_summands,deadlock_summands,comm(par).operand(),
    9463             :                                 regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9464             :           // Encode the actions of the block list in one multi action.
    9465           0 :           communicationcomposition(comm(par).comm_set(),action_name_multiset_list( { action_name_multiset(block(t).block_set())} ),
    9466             :                                                      false,true,action_summands,deadlock_summands);
    9467           0 :           return;
    9468             :         }
    9469             : 
    9470           0 :         generateLPEmCRLterm(action_summands,deadlock_summands,par,regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9471             :         // Encode the actions of the block list in one multi action.
    9472           0 :         allowblockcomposition(action_name_multiset_list({action_name_multiset(block(t).block_set())}),false,action_summands,deadlock_summands);
    9473           0 :         return;
    9474             :       }
    9475             : 
    9476         119 :       if (is_rename(t))
    9477             :       {
    9478           0 :         generateLPEmCRLterm(action_summands,deadlock_summands,process::rename(t).operand(),
    9479             :                               regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9480           0 :         renamecomposition(process::rename(t).rename_set(),action_summands);
    9481           0 :         return;
    9482             :       }
    9483             : 
    9484         119 :       if (is_comm(t))
    9485             :       {
    9486         112 :         generateLPEmCRLterm(action_summands,deadlock_summands,comm(t).operand(),
    9487             :                               regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9488         112 :         communicationcomposition(comm(t).comm_set(),action_name_multiset_list(),false,false,action_summands,deadlock_summands);
    9489         112 :         return;
    9490             :       }
    9491             : 
    9492           7 :       if (is_stochastic_operator(t))
    9493             :       {
    9494             :         /* YYYYYYYYYY */
    9495           7 :         const stochastic_operator& sto=atermpp::down_cast<stochastic_operator>(t);
    9496           7 :         generateLPEmCRLterm(action_summands,deadlock_summands,sto.operand(),
    9497             :                               regular,rename_variables,pars,init,initial_stochastic_distribution,ultimate_delay_condition);
    9498          14 :         variable_list stochvars=sto.variables();
    9499          14 :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    9500           7 :         alphaconvert(stochvars,sigma,pars + initial_stochastic_distribution.variables(), data_expression_list());
    9501           7 :         initial_stochastic_distribution=stochastic_distribution(
    9502          14 :                                           stochvars+initial_stochastic_distribution.variables(),
    9503          14 :                                           data::sort_real::times(replace_variables_capture_avoiding_alt(
    9504             :                                                                                     sto.distribution(), sigma),
    9505             :                                                                  initial_stochastic_distribution.distribution()));
    9506             :         /* Reset the bound variables in the initial_stochastic_distribution, to avoid erroneous renaming in the body of the process */
    9507          14 :         for(const variable& v: initial_stochastic_distribution.variables())
    9508             :         {
    9509           7 :           sigma[v]=v;
    9510             :         }
    9511           7 :         init=replace_variables_capture_avoiding_alt(init,sigma);
    9512           7 :         return;
    9513             :       }
    9514             : 
    9515           0 :       throw mcrl2::runtime_error("Internal error. Expect an mCRL term " + process::pp(t) +".");
    9516             :     }
    9517             : 
    9518             :     /**************** GENERaTE LPEmCRL **********************************/
    9519             : 
    9520             :     /* The result are a list of action summands, deadlock summand, the parameters of this
    9521             :        linear process and its initial values. A initial stochastic distribution that must
    9522             :        precede the initial linear process and the ultimate delay condition of this
    9523             :        linear process that can be used or be ignored. */
    9524             : 
    9525        1585 :     void generateLPEmCRL(
    9526             :       stochastic_action_summand_vector& action_summands,
    9527             :       deadlock_summand_vector& deadlock_summands,
    9528             :       const process_identifier& procIdDecl,
    9529             :       const bool regular,
    9530             :       variable_list& pars,
    9531             :       data_expression_list& init,
    9532             :       stochastic_distribution& initial_stochastic_distribution,
    9533             :       lps::detail::ultimate_delay& ultimate_delay_condition)
    9534             :     {
    9535             :       /* If regular=1, then a regular version of the pCRL processes
    9536             :          must be generated */
    9537             : 
    9538        1585 :       objectdatatype& object=objectIndex(procIdDecl);
    9539             : 
    9540        2154 :       if ((object.processstatus==GNF)||
    9541        1138 :           (object.processstatus==pCRL)||
    9542        1138 :           (object.processstatus==GNFalpha)||
    9543         569 :           (object.processstatus==multiAction))
    9544             :       {
    9545        2032 :         generateLPEpCRL(action_summands,deadlock_summands,procIdDecl,
    9546        1016 :                                object.containstime,regular,pars,init,initial_stochastic_distribution);
    9547        1016 :         if (options.ignore_time)
    9548             :         {
    9549           0 :           ultimate_delay_condition=lps::detail::ultimate_delay();
    9550             :         }
    9551             :         else
    9552             :         {
    9553        1016 :           ultimate_delay_condition=getUltimateDelayCondition(action_summands,deadlock_summands,pars);
    9554             : 
    9555             :           // The ultimate_delay_condition can be complex. Try to simplify it with a fourier_motzkin reduction.
    9556        2032 :           data_expression simplified_ultimate_delay_condition;
    9557        2032 :           variable_list reduced_sumvars;
    9558             :           try
    9559             :           {
    9560        2032 :             fourier_motzkin(ultimate_delay_condition.constraint(),
    9561        1016 :                             ultimate_delay_condition.variables(),
    9562             :                             simplified_ultimate_delay_condition,
    9563             :                             reduced_sumvars,
    9564             :                             rewr);
    9565        1016 :             std::swap(ultimate_delay_condition.constraint(), simplified_ultimate_delay_condition);
    9566        1016 :             std::swap(ultimate_delay_condition.variables(), reduced_sumvars);
    9567             :           }
    9568           0 :           catch (mcrl2::runtime_error& e)
    9569             :           {
    9570             :             // Applying Fourier Motzkin failed. Continue working with the old ultimate delay condition.
    9571           0 :             mCRL2log(mcrl2::log::debug) << "Simplifying a condition using Fourier-Motzkin reduction failed (I). \n" << e.what() << std::endl;
    9572             :           }
    9573             :         }
    9574             : 
    9575        1016 :         return;
    9576             :       }
    9577             :       /* process is a mCRLdone */
    9578         569 :       if ((object.processstatus==mCRLdone)||
    9579           0 :           (object.processstatus==mCRLlin)||
    9580           0 :           (object.processstatus==mCRL))
    9581             :       {
    9582         569 :         object.processstatus=mCRLlin;
    9583         569 :         generateLPEmCRLterm(action_summands, deadlock_summands, object.processbody,
    9584             :                                    regular, false, pars, init, initial_stochastic_distribution, ultimate_delay_condition);
    9585         569 :         return;
    9586             :       }
    9587             : 
    9588           0 :       throw mcrl2::runtime_error("laststatus: " + std::to_string(object.processstatus));
    9589             :     }
    9590             : 
    9591             :     /**************** alphaconversion ********************************/
    9592             : 
    9593             :     process_expression alphaconversionterm(
    9594             :       const process_expression& t,
    9595             :       const variable_list& parameters,
    9596             :       maintain_variables_in_rhs<mutable_map_substitution<> > sigma)
    9597             :     {
    9598             :       if (is_choice(t))
    9599             :       {
    9600             :         return choice(
    9601             :                  alphaconversionterm(choice(t).left(),parameters,sigma),
    9602             :                  alphaconversionterm(choice(t).right(),parameters,sigma));
    9603             :       }
    9604             : 
    9605             :       if (is_seq(t))
    9606             :       {
    9607             :         return seq(
    9608             :                  alphaconversionterm(seq(t).left(),parameters,sigma),
    9609             :                  alphaconversionterm(seq(t).right(),parameters,sigma));
    9610             :       }
    9611             : 
    9612             :       if (is_sync(t))
    9613             :       {
    9614             :         return process::sync(
    9615             :                  alphaconversionterm(process::sync(t).left(),parameters,sigma),
    9616             :                  alphaconversionterm(process::sync(t).right(),parameters,sigma));
    9617             :       }
    9618             : 
    9619             :       if (is_bounded_init(t))
    9620             :       {
    9621             :         return bounded_init(
    9622             :                  alphaconversionterm(bounded_init(t).left(),parameters,sigma),
    9623             :                  alphaconversionterm(bounded_init(t).right(),parameters,sigma));
    9624             :       }
    9625             : 
    9626             :       if (is_merge(t))
    9627             :       {
    9628             :         return process::merge(
    9629             :                  alphaconversionterm(process::merge(t).left(),parameters,sigma),
    9630             :                  alphaconversionterm(process::merge(t).right(),parameters,sigma));
    9631             :       }
    9632             : 
    9633             :       if (is_left_merge(t))
    9634             :       {
    9635             :         return left_merge(
    9636             :                  alphaconversionterm(left_merge(t).left(),parameters,sigma),
    9637             :                  alphaconversionterm(left_merge(t).right(),parameters,sigma));
    9638             :       }
    9639             : 
    9640             :       if (is_at(t))
    9641             :       {
    9642             :         return at(alphaconversionterm(at(t).operand(),parameters,sigma),
    9643             :                   replace_variables_capture_avoiding_alt(at(t).time_stamp(),sigma));
    9644             :       }
    9645             : 
    9646             :       if (is_if_then(t))
    9647             :       {
    9648             :         return if_then(
    9649             :                  replace_variables_capture_avoiding_alt(if_then(t).condition(), sigma),
    9650             :                  alphaconversionterm(if_then(t).then_case(),parameters,sigma));
    9651             :       }
    9652             : 
    9653             :       if (is_sum(t))
    9654             :       {
    9655             :         variable_list sumvars=sum(t).variables();
    9656             :         maintain_variables_in_rhs<mutable_map_substitution<> > local_sigma=sigma;
    9657             : 
    9658             :         alphaconvert(sumvars,local_sigma,variable_list(),variable_list_to_data_expression_list(parameters));
    9659             :         return sum(sumvars,alphaconversionterm(sum(t).operand(), sumvars+parameters, local_sigma));
    9660             :       }
    9661             : 
    9662             :       if (is_stochastic_operator(t))
    9663             :       {
    9664             :         const stochastic_operator& sto=down_cast<const stochastic_operator>(t);
    9665             :         variable_list sumvars=sto.variables();
    9666             :         maintain_variables_in_rhs<mutable_map_substitution<> > local_sigma=sigma;
    9667             : 
    9668             :         alphaconvert(sumvars,local_sigma,variable_list(),variable_list_to_data_expression_list(parameters));
    9669             :         return stochastic_operator(
    9670             :                        sumvars,
    9671             :                        replace_variables_capture_avoiding_alt(sto.distribution(), sigma),
    9672             :                        alphaconversionterm(sto.operand(), sumvars+parameters, local_sigma));
    9673             :       }
    9674             : 
    9675             :       if (is_process_instance_assignment(t))
    9676             :       {
    9677             :         const process_identifier procId=process_instance_assignment(t).identifier();
    9678             :         objectdatatype& object=objectIndex(procId);
    9679             : 
    9680             :         const variable_list instance_parameters=object.parameters;
    9681             :         alphaconversion(procId,instance_parameters);
    9682             : 
    9683             :         const process_instance_assignment result(procId,
    9684             :                                                  substitute_assignmentlist(process_instance_assignment(t).assignments(),
    9685             :                                                                            instance_parameters,false, true,sigma));
    9686             :         assert(check_valid_process_instance_assignment(result.identifier(),result.assignments()));
    9687             :         return result;
    9688             :       }
    9689             : 
    9690             :       if (is_action(t))
    9691             :       {
    9692             :         return action(action(t).label(), replace_variables_capture_avoiding_alt(action(t).arguments(), sigma));
    9693             :       }
    9694             : 
    9695             :       if (is_delta(t)||
    9696             :           is_tau(t))
    9697             :       {
    9698             :         return t;
    9699             :       }
    9700             : 
    9701             :       if (is_hide(t))
    9702             :       {
    9703             :         return alphaconversionterm(hide(t).operand(),parameters,sigma);
    9704             :       }
    9705             : 
    9706             :       if (is_rename(t))
    9707             :       {
    9708             :         return alphaconversionterm(process::rename(t).operand(),parameters,sigma);
    9709             :       }
    9710             : 
    9711             :       if (is_comm(t))
    9712             :       {
    9713             :         return alphaconversionterm(comm(t).operand(),parameters,sigma);
    9714             :       }
    9715             : 
    9716             :       if (is_allow(t))
    9717             :       {
    9718             :         return alphaconversionterm(allow(t).operand(),parameters,sigma);
    9719             :       }
    9720             : 
    9721             :       if (is_block(t))
    9722             :       {
    9723             :         return alphaconversionterm(block(t).operand(),parameters,sigma);
    9724             :       }
    9725             : 
    9726             :       throw mcrl2::runtime_error("unexpected process format in alphaconversionterm " + process::pp(t) +".");
    9727             :       return process_expression();
    9728             :     }
    9729             : 
    9730             :     void alphaconversion(const process_identifier& procId, const variable_list& parameters)
    9731             :     {
    9732             :       objectdatatype& object=objectIndex(procId);
    9733             : 
    9734             :       if ((object.processstatus==GNF)||
    9735             :           (object.processstatus==multiAction))
    9736             :       {
    9737             :         object.processstatus=GNFalpha;
    9738             :         // tempvar below is needed as objectdata may be reallocated
    9739             :         // during a call to alphaconversionterm.
    9740             :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    9741             :         const process_expression tempvar=alphaconversionterm(object.processbody,parameters,sigma);
    9742             :         object.processbody=tempvar;
    9743             :       }
    9744             :       else if (object.processstatus==mCRLdone)
    9745             :       {
    9746             :         maintain_variables_in_rhs< mutable_map_substitution<> > sigma;
    9747             :         alphaconversionterm(object.processbody,parameters,sigma);
    9748             : 
    9749             :       }
    9750             :       else if (object.processstatus==GNFalpha)
    9751             :       {
    9752             :         return;
    9753             :       }
    9754             :       else
    9755             :       {
    9756             :         throw mcrl2::runtime_error("unknown type " + std::to_string(object.processstatus) +
    9757             :                                                 " in alphaconversion of " + process::pp(procId) +".");
    9758             :       }
    9759             :       return;
    9760             :     }
    9761             : 
    9762             :     /***** determinewhetherprocessescontaintime; **********/
    9763             : 
    9764       24644 :     bool containstimebody(
    9765             :       const process_expression& t,
    9766             :       bool* stable,
    9767             :       std::set < process_identifier >& visited,
    9768             :       bool allowrecursion,
    9769             :       bool& contains_if_then)
    9770             :     {
    9771       24644 :       if (is_merge(t))
    9772             :       {
    9773             :         /* the construction below is needed to guarantee that
    9774             :            both subterms are recursively investigated */
    9775         470 :         bool r1=containstimebody(process::merge(t).left(),stable,visited,allowrecursion,contains_if_then);
    9776         470 :         bool r2=containstimebody(process::merge(t).right(),stable,visited,allowrecursion,contains_if_then);
    9777         470 :         return r1||r2;
    9778             :       }
    9779             : 
    9780       24174 :       if (is_process_instance(t))
    9781             :       {
    9782           0 :         assert(0);
    9783             :         if (allowrecursion)
    9784             :         {
    9785             :           return (containstime_rec(process_instance(t).identifier(),stable,visited,contains_if_then));
    9786             :         }
    9787             :         return objectIndex(process_instance(t).identifier()).containstime;
    9788             :       }
    9789             : 
    9790       24174 :       if (is_process_instance_assignment(t))
    9791             :       {
    9792        6138 :         if (allowrecursion)
    9793             :         {
    9794        2489 :           return (containstime_rec(process_instance_assignment(t).identifier(),stable,visited,contains_if_then));
    9795             :         }
    9796        3649 :         return objectIndex(process_instance_assignment(t).identifier()).containstime;
    9797             :       }
    9798             : 
    9799       18036 :       if (is_hide(t))
    9800             :       {
    9801          24 :         return containstimebody(hide(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9802             :       }
    9803             : 
    9804       18012 :       if (is_rename(t))
    9805             :       {
    9806           0 :         return containstimebody(process::rename(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9807             :       }
    9808             : 
    9809       18012 :       if (is_allow(t))
    9810             :       {
    9811          96 :         return containstimebody(allow(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9812             :       }
    9813             : 
    9814       17916 :       if (is_block(t))
    9815             :       {
    9816           0 :         return containstimebody(block(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9817             :       }
    9818             : 
    9819       17916 :       if (is_comm(t))
    9820             :       {
    9821         119 :         return containstimebody(comm(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9822             :       }
    9823             : 
    9824       17797 :       if (is_choice(t))
    9825             :       {
    9826        2075 :         bool r1=containstimebody(choice(t).left(),stable,visited,allowrecursion,contains_if_then);
    9827        2075 :         bool r2=containstimebody(choice(t).right(),stable,visited,allowrecursion,contains_if_then);
    9828        2075 :         return r1||r2;
    9829             :       }
    9830             : 
    9831       15722 :       if (is_seq(t))
    9832             :       {
    9833        4854 :         bool r1=containstimebody(seq(t).left(),stable,visited,allowrecursion,contains_if_then);
    9834        4854 :         bool r2=containstimebody(seq(t).right(),stable,visited,allowrecursion,contains_if_then);
    9835        4854 :         return r1||r2;
    9836             :       }
    9837             : 
    9838       10868 :       if (is_if_then(t))
    9839             :       {
    9840             :         // If delta is added, c->p is translated into c->p<>delta,
    9841             :         // otherwise into c->p<>delta@0. In this last case the process
    9842             :         // contains time.
    9843        1198 :         contains_if_then=true;
    9844        1198 :         if (options.ignore_time)
    9845             :         {
    9846           0 :           return containstimebody(if_then(t).then_case(),stable,visited,allowrecursion,contains_if_then);
    9847             :         }
    9848             :         else
    9849             :         {
    9850        1198 :           return true;
    9851             :         }
    9852             :       }
    9853             : 
    9854        9670 :       if (is_if_then_else(t))
    9855             :       {
    9856         219 :         bool r1=containstimebody(if_then_else(t).then_case(),stable,visited,allowrecursion,contains_if_then);
    9857         219 :         bool r2=containstimebody(if_then_else(t).else_case(),stable,visited,allowrecursion,contains_if_then);
    9858         219 :         return r1||r2;
    9859             :       }
    9860             : 
    9861        9451 :       if (is_sum(t))
    9862             :       {
    9863         997 :         return containstimebody(sum(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9864             :       }
    9865             : 
    9866        8454 :       if (is_stochastic_operator(t))
    9867             :       {
    9868         157 :         return containstimebody(stochastic_operator(t).operand(),stable,visited,allowrecursion,contains_if_then);
    9869             :       }
    9870             : 
    9871       20069 :       if (is_action(t)||
    9872       10619 :           is_delta(t)||
    9873        2322 :           is_tau(t))
    9874             :       {
    9875        6888 :         return false;
    9876             :       }
    9877             : 
    9878        1409 :       if (is_at(t))
    9879             :       {
    9880         992 :         return true;
    9881             :       }
    9882             : 
    9883         417 :       if (is_sync(t))
    9884             :       {
    9885         417 :         bool r1=containstimebody(process::sync(t).left(),stable,visited,allowrecursion,contains_if_then);
    9886         417 :         bool r2=containstimebody(process::sync(t).right(),stable,visited,allowrecursion,contains_if_then);
    9887         417 :         return r1||r2;
    9888             :       }
    9889             : 
    9890           0 :       throw mcrl2::runtime_error("unexpected process format in containstime " + process::pp(t) +".");
    9891             :       return false;
    9892             :     }
    9893             : 
    9894        3381 :     bool containstime_rec(
    9895             :       const process_identifier& procId,
    9896             :       bool* stable,
    9897             :       std::set < process_identifier >& visited,
    9898             :       bool& contains_if_then)
    9899             :     {
    9900        3381 :       objectdatatype& object=objectIndex(procId);
    9901             : 
    9902        3381 :       if (visited.count(procId)==0)
    9903             :       {
    9904        2378 :         visited.insert(procId);
    9905        2378 :         const bool ct=containstimebody(object.processbody,stable,visited,true,contains_if_then);
    9906             :         static bool show_only_once=true;
    9907        2378 :         if (ct && options.ignore_time && show_only_once)
    9908             :         {
    9909           0 :           mCRL2log(mcrl2::log::warning) << "process " << procId.name() <<
    9910           0 :               " contains time, which is now not preserved. \n"  <<
    9911           0 :               "Use --timed or -T, or untick `add deadlocks' for a correct timed linearisation...\n";
    9912           0 :           show_only_once=false;
    9913             :         }
    9914        2378 :         if (object.containstime!=ct)
    9915             :         {
    9916         340 :           object.containstime=ct;
    9917         340 :           if (stable!=nullptr)
    9918             :           {
    9919         340 :             *stable=false;
    9920             :           }
    9921             :         }
    9922             :       }
    9923        3381 :       return (object.containstime);
    9924             :     }
    9925             : 
    9926        4803 :     bool containstimebody(const process_expression& t)
    9927             :     {
    9928        9606 :       std::set < process_identifier > visited;
    9929             :       bool stable;
    9930             :       bool contains_if_then;
    9931        9606 :       return containstimebody(t,&stable,visited,false,contains_if_then);
    9932             :     }
    9933             : 
    9934         686 :     bool determinewhetherprocessescontaintime(const process_identifier& procId)
    9935             : 
    9936             :     {
    9937             :       /* This function sets for all reachable processes in the array objectdata
    9938             :          whether they contain time in the field containstime. In verbose mode
    9939             :          it prints the process variables that contain time. Furtermore, it returns
    9940             :          whether there are processes that contain an if-then that will be translated
    9941             :          to an if-then-else with an delta@0 in the else branch, introducing time */
    9942         686 :       bool stable=0;
    9943         686 :       bool contains_if_then=false;
    9944             : 
    9945        2470 :       while (!stable)
    9946             :       {
    9947        1784 :         std::set < process_identifier > visited;
    9948         892 :         stable=1;
    9949         892 :         containstime_rec(procId,&stable,visited,contains_if_then);
    9950             :       }
    9951         686 :       return contains_if_then;
    9952             :     }
    9953             :     /***** transform_initial_distribution_term **********/
    9954             : 
    9955       10332 :     process_expression transform_initial_distribution_term(
    9956             :                             const process_expression& t,
    9957             :                             const std::map < process_identifier, process_pid_pair >& processes_with_initial_distribution)
    9958             :     {
    9959       10332 :       if (is_process_instance_assignment(t))
    9960             :       {
    9961        5206 :         const process_instance_assignment u=atermpp::down_cast<process_instance_assignment>(t);
    9962        5206 :         const process_expression new_process=processes_with_initial_distribution.at(u.identifier()).process_body();
    9963        2603 :         if (is_stochastic_operator(new_process))
    9964             :         {
    9965             :           // Add the initial stochastic_distribution.
    9966         102 :           const process_identifier& new_identifier=processes_with_initial_distribution.at(u.identifier()).process_id();
    9967         102 :           objectdatatype& object=objectIndex(new_identifier);
    9968         204 :           const variable_list new_parameters=object.parameters;
    9969         102 :           const stochastic_operator& sto=down_cast<stochastic_operator>(new_process);
    9970         204 :           assignment_list new_assignments;
    9971             :           
    9972         204 :           const variable_list relevant_stochastic_variables=parameters_that_occur_in_body(sto.variables(),object.processbody);
    9973         102 :           assert(relevant_stochastic_variables.size()<=new_parameters.size());
    9974         102 :           variable_list::const_iterator i=new_parameters.begin();
    9975         747 :           for(const variable& v: relevant_stochastic_variables)
    9976             :           {
    9977         645 :             new_assignments=push_back(new_assignments,assignment(*i,v));
    9978         645 :             i++;
    9979             :           }
    9980             :           // Some of the variables may occur only in the distribution, which is now moved out.
    9981             :           // Therefore, the assignments must be filtered.
    9982         102 :           new_assignments=filter_assignments(new_assignments + u.assignments(),object.parameters);
    9983             : 
    9984             :           // Furthermore, the old assignment must be applied to the distribution, when it is moved
    9985             :           // outside of the process body.
    9986         204 :           maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma;
    9987         281 :           for(const assignment& a:u.assignments())
    9988             :           {
    9989         179 :             local_sigma[a.lhs()]=a.rhs();
    9990         179 :             const std::set<variable> varset=find_free_variables(a.rhs());
    9991             :           }
    9992         204 :           return stochastic_operator(sto.variables(),
    9993         204 :                                      replace_variables_capture_avoiding_alt(sto.distribution(),
    9994             :                                                                               local_sigma),
    9995         306 :                                      process_instance_assignment(new_identifier,new_assignments));
    9996             :         }
    9997        2501 :         return t;
    9998             : 
    9999             :       }
   10000             : 
   10001        7729 :       if (is_choice(t))
   10002             :       {
   10003        1534 :         const process_expression r1_=transform_initial_distribution_term(choice(t).left(),processes_with_initial_distribution);
   10004        1534 :         const process_expression r2_=transform_initial_distribution_term(choice(t).right(),processes_with_initial_distribution);
   10005         767 :         if (is_stochastic_operator(r1_))
   10006             :         {
   10007           0 :           const stochastic_operator& r1=down_cast<const stochastic_operator>(r1_);
   10008           0 :           if (is_stochastic_operator(r2_))
   10009             :           {
   10010             :             /* both r1_ and r2_ are stochastic */
   10011           0 :             const stochastic_operator& r2=down_cast<const stochastic_operator>(r2_);
   10012           0 :             const process_expression& new_body1=r1.operand();
   10013           0 :             process_expression new_body2=r2.operand();
   10014           0 :             variable_list stochvars=r2.variables();
   10015           0 :             maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma;
   10016           0 :             alphaconvert(stochvars,local_sigma, r1.variables(),data_expression_list());
   10017           0 :             new_body2=substitute_pCRLproc(new_body2, local_sigma);
   10018             :             const data_expression new_distribution=
   10019           0 :                    process::replace_variables_capture_avoiding_with_an_identifier_generator(r2.distribution(),local_sigma,fresh_identifier_generator);
   10020             : 
   10021           0 :             return stochastic_operator(r1.variables() + stochvars,
   10022           0 :                                        real_times_optimized(r1.distribution(),new_distribution),
   10023           0 :                                        choice(new_body1,new_body2));
   10024             :           }
   10025             :           /* r1 is and r2_ is not a stochastic operator */
   10026           0 :           return stochastic_operator(r1.variables(),r1.distribution(),choice(r1.operand(),r2_));
   10027             :         }
   10028         767 :         if (is_stochastic_operator(r2_))
   10029             :         {
   10030             :           /* r1_ is not and r2_ is a stochastic operator */
   10031           0 :           const stochastic_operator& r2=down_cast<const stochastic_operator>(r2_);
   10032           0 :           return stochastic_operator(r2.variables(),r2.distribution(),choice(r1_,r2.operand()));
   10033             :         }
   10034             :         /* neither r1_ nor r2_ is stochastic */
   10035         767 :         return choice(r1_,r2_);
   10036             :       }
   10037             : 
   10038        6962 :       if (is_seq(t))
   10039             :       {
   10040        5206 :         const process_expression r1=transform_initial_distribution_term(seq(t).left(),processes_with_initial_distribution);
   10041        5206 :         const process_expression r2=transform_initial_distribution_term(seq(t).right(),processes_with_initial_distribution);
   10042        2603 :         if (is_stochastic_operator(r1))
   10043             :         {
   10044           0 :           const stochastic_operator& r=down_cast<const stochastic_operator>(r1);
   10045           0 :           return stochastic_operator(r.variables(),r.distribution(),seq(r.operand(),r2));
   10046             :         }
   10047        2603 :         return seq(r1,r2);
   10048             :       }
   10049             : 
   10050        4359 :       if (is_if_then(t))
   10051             :       {
   10052         354 :         const if_then& t_=atermpp::down_cast<if_then>(t);
   10053         708 :         const process_expression r=transform_initial_distribution_term(t_.then_case(),processes_with_initial_distribution);
   10054         354 :         if (is_stochastic_operator(r))
   10055             :         {
   10056           0 :           const stochastic_operator& r_=down_cast<const stochastic_operator>(r);
   10057           0 :           return stochastic_operator(r_.variables(),
   10058           0 :                                      if_(t_.condition(),r_.distribution(),if_(variables_are_equal_to_default_values(r_.variables()),real_one(),real_zero())),
   10059           0 :                                      if_then(t_.condition(),r_.operand()));
   10060             :         }
   10061         354 :         return if_then(t_.condition(),r);
   10062             :       }
   10063             : 
   10064        4005 :       if (is_if_then_else(t))
   10065             :       {
   10066           0 :         const if_then_else& t_=atermpp::down_cast<if_then_else>(t);
   10067           0 :         const process_expression r1_=transform_initial_distribution_term(t_.then_case(),processes_with_initial_distribution);
   10068           0 :         const process_expression r2_=transform_initial_distribution_term(t_.else_case(),processes_with_initial_distribution);
   10069           0 :         if (is_stochastic_operator(r1_))
   10070             :         {
   10071           0 :           const stochastic_operator& r1=down_cast<const stochastic_operator>(r1_);
   10072           0 :           if (is_stochastic_operator(r2_))
   10073             :           {
   10074             :             /* both r1_ and r2_ are stochastic */
   10075             : 
   10076           0 :             const stochastic_operator& r2=down_cast<const stochastic_operator>(r2_);
   10077           0 :             const process_expression& new_body1=r1.operand();
   10078           0 :             process_expression new_body2=r2.operand();
   10079           0 :             variable_list stochvars=r2.variables();
   10080           0 :             maintain_variables_in_rhs< mutable_map_substitution<> > local_sigma;
   10081           0 :             alphaconvert(stochvars,local_sigma, r1.variables(),data_expression_list());
   10082           0 :             new_body2=substitute_pCRLproc(new_body2, local_sigma);
   10083             :             const data_expression new_distribution=
   10084           0 :                    process::replace_variables_capture_avoiding_with_an_identifier_generator(r2.distribution(),local_sigma,fresh_identifier_generator);
   10085             : 
   10086           0 :             return stochastic_operator(r1.variables() + stochvars,
   10087           0 :                                        if_(t_.condition(),
   10088           0 :                                                lazy::and_(variables_are_equal_to_default_values(stochvars),r1.distribution()),
   10089           0 :                                                lazy::and_(variables_are_equal_to_default_values(r1.variables()),new_distribution)),
   10090           0 :                                        if_then_else(t_.condition(),new_body1,new_body2));
   10091             :           }
   10092             :           /* r1 is and r2_ is not a stochastic operator */
   10093           0 :           return stochastic_operator(r1.variables(),
   10094           0 :                                      if_(t_.condition(),r1.distribution(),
   10095           0 :                                                if_(variables_are_equal_to_default_values(r1.variables()),real_one(),real_zero())),
   10096           0 :                                      if_then_else(if_then_else(t).condition(),r1.operand(),r2_));
   10097             :         }
   10098           0 :         if (is_stochastic_operator(r2_))
   10099             :         {
   10100             :           /* r1_ is not and r2_ is a stochastic operator */
   10101           0 :           const stochastic_operator& r2=down_cast<const stochastic_operator>(r2_);
   10102           0 :           return stochastic_operator(r2.variables(),
   10103           0 :                                      if_(t_.condition(),
   10104           0 :                                          if_(variables_are_equal_to_default_values(r2.variables()),real_one(),real_zero()),
   10105             :                                          r2.distribution()),
   10106           0 :                                      if_then_else(t_.condition(),r1_,r2.operand()));
   10107             :         }
   10108             :         /* neither r1_ nor r2_ is stochastic */
   10109           0 :         return if_then_else(t_.condition(),r1_,r2_);
   10110             : 
   10111             :       }
   10112             : 
   10113        4005 :       if