123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651(******************************************************************************)(* _ __ * The Kappa Language *)(* | |/ / * Copyright 2010-2020 CNRS - Harvard Medical School - INRIA - IRIF *)(* | ' / *********************************************************************)(* | . \ * This file is distributed under the terms of the *)(* |_|\_\ * GNU Lesser General Public License Version 3 *)(******************************************************************************)letdivide_expr_by_intei=Loc.annot_with_dummy(Alg_expr.BIN_ALG_OP(Operator.DIV,e,Loc.annot_with_dummy(Alg_expr.CONST(Nbr.Ii))))type('a,'b)corrected_rate_const={num:Nbr.t;den:Nbr.t;var:('a,'b)Alg_expr.eLoc.annotedoption;}letrecsimplify?(root_only=false)expr=matchexprwith|Alg_expr.BIN_ALG_OP(op,a,b),loc->leta,b=ifroot_onlythena,belsesimplifya,simplifybinletroot_only=truein(matchopwith|Operator.SUM->(matcha,bwith|(Alg_expr.CONSTa,_),(Alg_expr.CONSTb,_)->Alg_expr.CONST(Nbr.addab),loc|(Alg_expr.CONSTa,_),_whenNbr.is_zeroa->b|_,(Alg_expr.CONSTb,_)whenNbr.is_zerob->a|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_))->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Operator.MINUS->(matcha,bwith|(Alg_expr.CONSTa,_),(Alg_expr.CONSTb,_)->Alg_expr.CONST(Nbr.subab),loc|_,(Alg_expr.CONSTb,_)whenNbr.is_zerob->a|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_TOKEN_|Alg_expr.DIFF_KAPPA_INSTANCE_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_))->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Operator.MULT->(matcha,bwith|(Alg_expr.CONSTa,_),(Alg_expr.CONSTb,_)->Alg_expr.CONST(Nbr.multab),loc|(Alg_expr.CONSTa',_),_whenNbr.is_equala'Nbr.zero->a|_,(Alg_expr.CONSTb',_)whenNbr.is_equalb'Nbr.zero->b|(Alg_expr.CONSTa,_),_whenNbr.is_equalaNbr.one->b|_,(Alg_expr.CONSTb,_)whenNbr.is_equalbNbr.one->a|((Alg_expr.CONSTa,loc_cst),(Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONSTb,_),c),_|Alg_expr.BIN_ALG_OP(Operator.MULT,c,(Alg_expr.CONSTb,_)),_))|((Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONSTb,_),c),_|Alg_expr.BIN_ALG_OP(Operator.MULT,c,(Alg_expr.CONSTb,_)),_),(Alg_expr.CONSTa,loc_cst))->(* a*(b*c) -> (a*b)*c if a & b are constant *)simplify~root_only(Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONST(Nbr.multab),loc_cst),c),loc)|((Alg_expr.CONSTa,loc_cst),(Alg_expr.BIN_ALG_OP(Operator.DIV,(Alg_expr.CONSTb,_),c),_))|((Alg_expr.BIN_ALG_OP(Operator.DIV,(Alg_expr.CONSTb,_),c),_),(Alg_expr.CONSTa,loc_cst))->(* a*(b/c) -> (a*b)/c if a & b are constant *)simplify~root_only(Alg_expr.BIN_ALG_OP(Operator.DIV,(Alg_expr.CONST(Nbr.multab),loc_cst),c),loc)|((Alg_expr.BIN_ALG_OP(Operator.DIV,b,(Alg_expr.CONSTc,_)),_),(Alg_expr.CONSTa,loc_cst))|((Alg_expr.CONSTa,loc_cst),(Alg_expr.BIN_ALG_OP(Operator.DIV,b,(Alg_expr.CONSTc,_)),_))when(not(Nbr.is_zeroc))&&Nbr.is_zero(Nbr.remac)->(* a*(b/c) -> ((a/c)*b) if a & c are constant and c|a *)simplify~root_only(Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONST(Nbr.internal_divac),loc_cst),b),loc)|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP((Operator.DIV|Operator.MULT|Operator.SUM|Operator.MINUS|Operator.POW|Operator.MODULO|Operator.MIN|Operator.MAX),_,_)|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_))->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Operator.DIV->(matcha,bwith|_,(Alg_expr.CONSTb,_)whenNbr.is_equalbNbr.one->a|(Alg_expr.CONSTa,_),(Alg_expr.CONSTb,_)when(not(Nbr.is_zerob))&&Nbr.is_zero(Nbr.remab)->Alg_expr.CONST(Nbr.internal_divab),loc|((Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONSTa,_),b),loc_bin),(Alg_expr.CONSTc,_))whenNbr.is_zero(Nbr.remac)->(* (a*b/c) & c|a -> ((c/a)*b)*)simplify~root_only(Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONST(Nbr.internal_divca),loc_bin),b),loc)|((Alg_expr.BIN_ALG_OP(Operator.MULT,b,(Alg_expr.CONSTa,_)),loc_bin),(Alg_expr.CONSTc,_))whenNbr.is_zero(Nbr.remac)->(* (b*a/c) & c|a -> ((c/a)*b)*)simplify~root_only(Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONST(Nbr.internal_divca),loc_bin),b),loc)|(a,(Alg_expr.BIN_ALG_OP(Operator.DIV,(Alg_expr.CONSTb,_),(Alg_expr.CONSTc,_)),locdiv))->(* (a/b/c) -> a/(b*c) *)simplify~root_only(Alg_expr.BIN_ALG_OP(Operator.DIV,a,Alg_expr.(CONST(Nbr.multbc),locdiv)),loc)|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP((Operator.DIV|Operator.MULT|Operator.SUM|Operator.MINUS|Operator.POW|Operator.MODULO|Operator.MIN|Operator.MAX),_,_)|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_))->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Operator.POW->(matcha,bwith|_,(Alg_expr.CONSTb,_)whenNbr.is_equalbNbr.one->a|(Alg_expr.CONSTa,_),(Alg_expr.CONSTb,_)whenNbr.is_smallera(Nbr.I11)&&Nbr.is_greaterbNbr.zero&&Nbr.is_smallerb(Nbr.I11)->Alg_expr.CONST(Nbr.powab),loc|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_))->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Operator.MODULO->(matcha,bwith|_,(Alg_expr.CONSTb,_)whenNbr.is_equalbNbr.one->a|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_))->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Operator.MIN|Operator.MAX->Alg_expr.BIN_ALG_OP(op,a,b),loc)|Alg_expr.UN_ALG_OP(op,a),loc->leta=simplifyain(matchopwith|Operator.UMINUS->(matchawith|Alg_expr.CONSTa,_->Alg_expr.CONST(Nbr.nega),loc|((Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_)->Alg_expr.UN_ALG_OP(op,a),loc)|Operator.COSINUS|Operator.EXP->(matchawith|Alg_expr.CONSTa,_whenNbr.is_zeroa->Alg_expr.CONSTNbr.one,loc|((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_)->Alg_expr.UN_ALG_OP(op,a),loc)|Operator.SINUS|Operator.TAN->(matchawith|Alg_expr.CONSTa,_whenNbr.is_equalaNbr.one->Alg_expr.CONSTNbr.zero,loc|((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_)->Alg_expr.UN_ALG_OP(op,a),loc)|Operator.SQRT|Operator.LOG|Operator.INT->Alg_expr.UN_ALG_OP(op,a),loc)|Alg_expr.DIFF_KAPPA_INSTANCE(expr,mix),loc->letexpr=simplifyexprin(matchexprwith|Alg_expr.CONST_,_->Alg_expr.CONSTNbr.zero,loc|((Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_)->Alg_expr.DIFF_KAPPA_INSTANCE(expr,mix),loc)|Alg_expr.DIFF_TOKEN(expr,token),loc->letexpr=simplifyexprin(matchexprwith|Alg_expr.CONST_,_->Alg_expr.CONSTNbr.zero,loc|((Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.DIFF_TOKEN_),_)->Alg_expr.DIFF_TOKEN(expr,token),loc)|Alg_expr.STATE_ALG_OP_,_|Alg_expr.ALG_VAR_,_|Alg_expr.KAPPA_INSTANCE_,_|Alg_expr.TOKEN_ID_,_|Alg_expr.CONST_,_->expr|Alg_expr.IF(cond,yes,no),loc->letcond,yes,no=simplify_boolcond,simplifyyes,simplifynoin(matchcondwith|Alg_expr.TRUE,_->yes|Alg_expr.FALSE,_->no|Alg_expr.UN_BOOL_OP(_,_),_|Alg_expr.BIN_BOOL_OP(_,_,_),_|Alg_expr.COMPARE_OP(_,_,_),_->Alg_expr.IF(cond,yes,no),loc)andsimplify_boolexpr_bool=matchexpr_boolwith|Alg_expr.TRUE,_|Alg_expr.FALSE,_->expr_bool|Alg_expr.UN_BOOL_OP(op,a),loc->(matchsimplify_boolawith|Alg_expr.TRUE,_->Alg_expr.FALSE,loc|Alg_expr.FALSE,_->Alg_expr.TRUE,loc|(Alg_expr.BIN_BOOL_OP(_,_,_),_|Alg_expr.COMPARE_OP(_,_,_),_|Alg_expr.UN_BOOL_OP(_,_),_)asa'->Alg_expr.UN_BOOL_OP(op,a'),loc)|Alg_expr.BIN_BOOL_OP(op,a,b),loc->leta,b=simplify_boola,simplify_boolbin(matchopwith|Operator.AND->(matcha,bwith|(Alg_expr.TRUE,_),_->b|(Alg_expr.FALSE,_),_->a|_,(Alg_expr.TRUE,_)->a|_,(Alg_expr.FALSE,_)->b|(((Alg_expr.BIN_BOOL_OP(_,_,_)|Alg_expr.COMPARE_OP(_,_,_)|Alg_expr.UN_BOOL_OP(_,_)),_),((Alg_expr.BIN_BOOL_OP(_,_,_)|Alg_expr.COMPARE_OP(_,_,_)|Alg_expr.UN_BOOL_OP(_,_)),_))->Alg_expr.BIN_BOOL_OP(op,a,b),loc)|Operator.OR->(matcha,bwith|(Alg_expr.TRUE,_),_->a|(Alg_expr.FALSE,_),_->b|_,(Alg_expr.TRUE,_)->b|_,(Alg_expr.FALSE,_)->a|(((Alg_expr.BIN_BOOL_OP(_,_,_)|Alg_expr.COMPARE_OP(_,_,_)|Alg_expr.UN_BOOL_OP(_,_)),_),((Alg_expr.BIN_BOOL_OP(_,_,_)|Alg_expr.COMPARE_OP(_,_,_)|Alg_expr.UN_BOOL_OP(_,_)),_))->Alg_expr.BIN_BOOL_OP(op,a,b),loc))|Alg_expr.COMPARE_OP(op,a,b),loc->leta,b=simplifya,simplifybin(matcha,bwith|(Alg_expr.CONSTa,_),(Alg_expr.CONSTb,_)->(matchopwith|Operator.GREATER->ifNbr.is_greaterabthenAlg_expr.TRUE,locelseAlg_expr.FALSE,loc|Operator.SMALLER->ifNbr.is_smallerabthenAlg_expr.TRUE,locelseAlg_expr.FALSE,loc|Operator.EQUAL->ifNbr.is_equalabthenAlg_expr.TRUE,locelseAlg_expr.FALSE,loc|Operator.DIFF->ifNbr.is_equalabthenAlg_expr.FALSE,locelseAlg_expr.TRUE,loc)|(((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_TOKEN_|Alg_expr.DIFF_KAPPA_INSTANCE_),_),((Alg_expr.CONST_|Alg_expr.ALG_VAR_|Alg_expr.BIN_ALG_OP_|Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.IF_|Alg_expr.DIFF_TOKEN_|Alg_expr.DIFF_KAPPA_INSTANCE_),_))->Alg_expr.COMPARE_OP(op,a,b),loc)letsimplifyexpr=letroot_only=falseinsimplify~root_onlyexprletreccleanexpr=letexpr=fstexprinmatchexprwith|Alg_expr.BIN_ALG_OP(op,a,b)->Loc.annot_with_dummy(Alg_expr.BIN_ALG_OP(op,cleana,cleanb))|Alg_expr.UN_ALG_OP(op,a)->Loc.annot_with_dummy(Alg_expr.UN_ALG_OP(op,cleana))|Alg_expr.DIFF_TOKEN(expr,dt)->Loc.annot_with_dummy(Alg_expr.DIFF_TOKEN(cleanexpr,dt))|Alg_expr.DIFF_KAPPA_INSTANCE(expr,dt)->Loc.annot_with_dummy(Alg_expr.DIFF_KAPPA_INSTANCE(cleanexpr,dt))|Alg_expr.STATE_ALG_OP_|Alg_expr.ALG_VAR_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.CONST_->Loc.annot_with_dummyexpr|Alg_expr.IF(cond,yes,no)->Loc.annot_with_dummy(Alg_expr.IF(clean_boolcond,cleanyes,cleanno))andclean_boolexpr_bool=letexpr=fstexpr_boolinmatchexprwith|Alg_expr.TRUE|Alg_expr.FALSE->Loc.annot_with_dummyexpr|Alg_expr.UN_BOOL_OP(op,a)->Loc.annot_with_dummy(Alg_expr.UN_BOOL_OP(op,clean_boola))|Alg_expr.BIN_BOOL_OP(op,a,b)->Loc.annot_with_dummy(Alg_expr.BIN_BOOL_OP(op,clean_boola,clean_boolb))|Alg_expr.COMPARE_OP(op,a,b)->Loc.annot_with_dummy(Alg_expr.COMPARE_OP(op,cleana,cleanb))letrecget_corrected_ratee=matchewith|Alg_expr.BIN_ALG_OP(Operator.MULT,(Alg_expr.CONSTcst,_),e),_|Alg_expr.BIN_ALG_OP(Operator.MULT,e,(Alg_expr.CONSTcst,_)),_->(matchget_corrected_rateewith|None->None|Somecorrected_rate->Some{corrected_ratewithnum=Nbr.multcstcorrected_rate.num})|Alg_expr.BIN_ALG_OP(Operator.DIV,e,(Alg_expr.CONSTcst,_)),_->(matchget_corrected_rateewith|None->None|Somecorrected_rate->Some{corrected_ratewithden=Nbr.multcstcorrected_rate.den})|Alg_expr.BIN_ALG_OP(Operator.SUM,e1,e2),_->(matchget_corrected_ratee1with|None->None|Somecorrected_rate1->(matchget_corrected_ratee2with|Somecorrected_rate2whencomparecorrected_rate1.varcorrected_rate2.var=0&&Nbr.is_equalcorrected_rate1.dencorrected_rate2.den->Some{corrected_rate1withnum=Nbr.addcorrected_rate1.numcorrected_rate2.num;}|Somecorrected_rate2whencomparecorrected_rate1.varcorrected_rate2.var=0->Some{corrected_rate1withnum=Nbr.add(Nbr.multcorrected_rate2.dencorrected_rate1.num)(Nbr.multcorrected_rate1.dencorrected_rate2.num);den=Nbr.multcorrected_rate1.dencorrected_rate2.den;}|None|Some_->None))|(Alg_expr.BIN_ALG_OP((Operator.MULT|Operator.DIV|Operator.MINUS|Operator.POW|Operator.MODULO|Operator.MAX|Operator.MIN),_,_),_)|((Alg_expr.UN_ALG_OP_|Alg_expr.STATE_ALG_OP_|Alg_expr.KAPPA_INSTANCE_|Alg_expr.TOKEN_ID_|Alg_expr.DIFF_TOKEN_|Alg_expr.DIFF_KAPPA_INSTANCE_|Alg_expr.IF_),_)->None|Alg_expr.ALG_VAR_,_->Some{var=Somee;num=Nbr.one;den=Nbr.one}|Alg_expr.CONSTcst,_->Some{var=None;num=cst;den=Nbr.one}letget_corrected_ratee=get_corrected_rate(cleane)letprintpr_varfcorrected_rate_const=matchcorrected_rate_constwith|None->Format.fprintff"None"|Somea->(matcha.varwith|Some_->Format.fprintff"(%a/%a).%a"Nbr.printa.numNbr.printa.denpr_vara.var|None->Format.fprintff"(%a/%a)"Nbr.printa.numNbr.printa.den)letnecessarily_equala_optb_opt=matcha_opt,b_optwith|None,_|_,None->false|Somea,Someb->Option_util.equalAlg_expr.equala.varb.var&&Nbr.is_equal(Nbr.multa.numb.den)(Nbr.multa.denb.num)letdepemptyadd_mixtureadd_tokenuniondep_env?time_varexpr=letrecauxadd_mixtureadd_tokenuniondep_envexpraccu=matchfstexprwith|Alg_expr.BIN_ALG_OP(_,e1,e2)|Alg_expr.IF(_,e1,e2)->auxadd_mixtureadd_tokenuniondep_enve1(auxadd_mixtureadd_tokenuniondep_enve2accu)|Alg_expr.UN_ALG_OP(_,e)|Alg_expr.DIFF_TOKEN(e,_)|Alg_expr.DIFF_KAPPA_INSTANCE(e,_)->auxadd_mixtureadd_tokenuniondep_enveaccu|Alg_expr.STATE_ALG_OPOperator.TIME_VAR->(matchtime_varwith|Someid->add_mixtureidaccu|None->raise(ExceptionDefn.Internal_Error("A variable for time shall be provided to analyse the \
dependences in a time-dependent expression",sndexpr)))|Alg_expr.STATE_ALG_OP(Operator.CPUTIME|Operator.EVENT_VAR|Operator.NULL_EVENT_VAR|Operator.TMAX_VAR|Operator.EMAX_VAR)->accu|Alg_expr.ALG_VARid->union(dep_envid)accu|Alg_expr.KAPPA_INSTANCEmix->add_mixturemixaccu|Alg_expr.TOKEN_IDid->add_tokenidaccu|Alg_expr.CONST_->accuinauxadd_mixtureadd_tokenuniondep_envexpremptyletrecdiff_genf_mixf_tokenf_symbf_timeexpr=matchfstexprwith|Alg_expr.IF(b,e1,e2)->Loc.annot_with_dummy(Alg_expr.IF(b,diff_genf_mixf_tokenf_symbf_timee1,diff_genf_mixf_tokenf_symbf_timee2))|Alg_expr.BIN_ALG_OP(op,e1,e2)->(matchopwith|Operator.SUM->Alg_expr.add(diff_genf_mixf_tokenf_symbf_timee1)(diff_genf_mixf_tokenf_symbf_timee2)|Operator.MULT->Alg_expr.add(Alg_expr.multe1(diff_genf_mixf_tokenf_symbf_timee2))(Alg_expr.multe2(diff_genf_mixf_tokenf_symbf_timee1))|Operator.MINUS->Alg_expr.minus(diff_genf_mixf_tokenf_symbf_timee1)(diff_genf_mixf_tokenf_symbf_timee2)|Operator.MIN|Operator.MAX->Alg_expr.int0|Operator.MODULO->diff_genf_mixf_tokenf_symbf_timee1|Operator.DIV->Alg_expr.div(Alg_expr.minus(Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee1)e2)(Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee2)e1))(Alg_expr.powe2(Alg_expr.int2))|Operator.POW->(* (u^v)*(v'*ln(u)+v*u'/u) *)Alg_expr.mult(Alg_expr.powe1e2)(Alg_expr.add(Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee2)(Alg_expr.lne1))(Alg_expr.div(Alg_expr.multe2(diff_genf_mixf_tokenf_symbf_timee1))e1)))|Alg_expr.UN_ALG_OP(op,e)->(matchopwith|Operator.UMINUS->Alg_expr.uminus(diff_genf_mixf_tokenf_symbf_timee)|Operator.COSINUS->Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee)(Alg_expr.uminus(Alg_expr.sine))|Operator.SINUS->Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee)(Alg_expr.cose)|Operator.LOG->Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee)(Alg_expr.div(Alg_expr.int1)e)|Operator.SQRT->Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee)(Alg_expr.div(Alg_expr.int(-1))(Alg_expr.sqrte))|Operator.EXP->Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee)e|Operator.TAN->Alg_expr.mult(diff_genf_mixf_tokenf_symbf_timee)(Alg_expr.add(Alg_expr.int1)(Alg_expr.powe(Alg_expr.int2)))|Operator.INT->Alg_expr.int0)|Alg_expr.STATE_ALG_OPOperator.TIME_VAR->f_time()|Alg_expr.STATE_ALG_OP(Operator.CPUTIME|Operator.EVENT_VAR|Operator.NULL_EVENT_VAR|Operator.TMAX_VAR|Operator.EMAX_VAR)->Alg_expr.int0|Alg_expr.KAPPA_INSTANCEmix->f_mixmix|Alg_expr.TOKEN_IDid->f_tokenid|Alg_expr.CONST_->Alg_expr.int0|Alg_expr.ALG_VAR_|Alg_expr.DIFF_TOKEN_|Alg_expr.DIFF_KAPPA_INSTANCE_->f_symbexprletdiff_tokenexprtoken=letf_mix_=Alg_expr.int0inletf_tokena=ifa=tokenthenAlg_expr.int1elseAlg_expr.int0inletf_symbexpr=Alg_expr.DIFF_TOKEN(expr,token),Loc.dummyinletf_time_=Alg_expr.int0indiff_genf_mixf_tokenf_symbf_timeexprletdiff_mixture?time_varexprmixture=letf_mixa=ifa=mixturethenAlg_expr.int1elseAlg_expr.int0inletf_token_=Alg_expr.int0inletf_symbexpr=Alg_expr.DIFF_KAPPA_INSTANCE(expr,mixture),Loc.dummyinletf_time()=matchtime_varwith|Somebwhenmixture=b->Alg_expr.int1|Some_->Alg_expr.int0|None->raise(ExceptionDefn.Internal_Error("A time-dependent expression cannot be differentiated without \
specifying a variable for time progress",Loc.dummy))indiff_genf_mixf_tokenf_symbf_timeexprletfold_over_mix_in_listfmixaccu=List.fold_left(funaccuarray_id->Array.fold_left(funaccupid->fpidaccu)accuarray_id)accumixletfold_over_mix_in_alg_exprfexpraccu=letl=Alg_expr.extract_connected_componentsexprinList.fold_left(funaccumix->fold_over_mix_in_listfmixaccu)acculletfold_over_mixtures_in_alg_exprsfmodelaccu=letalgs_expr=Model.get_algsmodelinletobservables=Model.get_obsmodelin(*algs*)letaccu=Array.fold_left(funaccu(_,mix)->fold_over_mix_in_alg_exprfmixaccu)accualgs_exprin(*observations*)letaccu=Array.fold_left(funaccumix->fold_over_mix_in_alg_exprfmixaccu)accuobservablesin(*rules*)letrules=Model.get_rulesmodelin(*rate*)letaccu=Array.fold_left(funaccuelementary_rule->letrate=elementary_rule.Primitives.rateinletaccu=fold_over_mix_in_alg_exprfrateaccuin(*unary_rate*)letunary_rate=elementary_rule.Primitives.unary_rateinletaccu=matchunary_ratewith|None->accu|Some(expr,_)->fold_over_mix_in_alg_exprfexpraccuin(*delta tokens*)letdelta_tokens=elementary_rule.Primitives.delta_tokensinletaccu=List.fold_left(funaccu(expr,_)->fold_over_mix_in_alg_exprfexpraccu)accudelta_tokensinaccu)accurulesinaccu