123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openLangletnegativen=F.p_leqnF.e_zeroletpositiven=F.p_leqF.e_zeronletconcat~resultes=F.e_fun~resultVlist.f_concatesletrepeat~resultan=F.e_fun~resultVlist.f_repeat[a;n]letsumn=matchF.reprnwith|Addns->ns|_->[n](* -------------------------------------------------------------------------- *)(* --- Induction Tactical --- *)(* -------------------------------------------------------------------------- *)letvmode,pmode=Tactical.selector~id:"seq.side"~title:"Mode"~descr:"Unrolling mode"~options:[{vid="left";title="Unroll left";descr="Transform (A^n) into (A.A^n-1)";value=`Left};{vid="right";title="Unroll right";descr="Transform (A^n) into (A^n-1.A)";value=`Right};{vid="sum";title="Concat sum";descr="Transform A^(p+q) into (A^p.A^q)";value=`Sum}]()classsequence=object(self)inheritTactical.make~id:"Wp.sequence"~title:"Sequence"~descr:"Unroll repeat-sequence operator"~params:[pmode]methodselectfeedback(s:Tactical.selection)=letvalue=Tactical.selectedsinmatchF.reprvaluewith|Fun(f,[a;n])whenf==Vlist.f_repeat->letresult=F.typeofvalueinletat=Tactical.atsinbeginmatchself#get_fieldvmodewith|`Sum->(* n1>=0 && n2>=0 && ... |- (a *^ (n1 + n2 + ...)) -+-> ((a *^ n1) ^ (a *^ n2) ^ ...) *)beginmatchsumnwith|[s]->feedback#set_descr"Cannot unroll with selected option, '%a' is not a sum"F.pp_terms;Tactical.Not_configured|ns->(* NB. the term is rewriten in itself when the initial term is not a sum *)letpos=F.p_allpositivensinletcat=concat~result(List.map(repeat~resulta)ns)infeedback#set_descr"Unroll repeat-sequence: unroll sum";Tactical.Applicable(Tactical.condition"Positive"pos@@Tactical.rewrite?at["Unroll",pos,value,cat])end|`Left->(* n<=0 |- (a *^ n) -+-> [] *)(* n-1>=0 |- (a *^ n) -+-> (a ^ (a *^ (n-1))) *)letp=F.e_addnF.e_minus_oneinletunroll=concat~result[a;repeat~resultap]infeedback#set_descr"Unroll repeat-sequence: unroll first element";Tactical.Applicable(Tactical.rewrite?at["Nil",negativen,value,concat~result[];"Unroll",positivep,value,unroll;])|`Right->(* n<=0 |- (a *^ n) -+-> [] *)(* n-1>=0 |- (a *^ n) -+-> ((a *^ (n-1)) ^ a) *)letp=F.e_addnF.e_minus_oneinletunroll=concat~result[repeat~resultap;a]infeedback#set_descr"Unroll repeat-sequence: unroll last element";Tactical.Applicable(Tactical.rewrite?at["Nil",negativen,value,concat~result[];"Unroll",positivep,value,unroll;])end|_->Not_applicableendlettactical=Tactical.export(newsequence)(* -------------------------------------------------------------------------- *)