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