123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)(* Reduced product interaction modes. *)typeinteraction_modes=|Only_Reduce_Absolute_Using_Relative|Only_Reduce_Relative_Using_Absolute|Complete_Reduced_Product|No_Reduced_Product(* Retrieving the interaction mode from parameters. *)letget_interaction_mode()=matchParameters.Numerors_Mode.get()with|"relative"->Only_Reduce_Relative_Using_Absolute|"absolute"->Only_Reduce_Absolute_Using_Relative|"both"->Complete_Reduced_Product|"none"->No_Reduced_Product|_->assertfalse(* Identity effect with unit context. *)moduleIdentity=structincludeIdentitytypecontext=unitletresolve()x=xend(* Interval abstraction over rationals. *)moduleAbstraction=Field_interval.Make(Rational)(Identity)(* Numerors model based on rational intervals and without context. *)moduleModel=structmoduleScalar=Rationaltypescalar=Rational.tmoduleContext=Unit_contextmoduleComputation=Identitytype'acomputation='aComputation.tmoduleAdditive=AbstractionmoduleMultiplicative=AbstractionmoduleExact=AbstractionmoduleAbsolute=AbstractionmoduleRelative=Abstractiontypeexact=Abstraction.ttypeabsolute=Abstraction.ttyperelative=Abstraction.tletname="Numerors.Value"letbetweenlowerupper=letlower=Abstraction.singletonlowerinletupper=Abstraction.singletonupperinAbstraction.joinlowerupperletnew_absolute_elementary_error_bound=letupper=Scalar.absboundinletlower=Scalar.negupperinbetweenlowerupperletnew_relative_elementary_error_bound=letupper=Scalar.absboundinletlower=Scalar.negupperinbetweenlowerupperletdo_reduce_absolute_with_relative()=matchget_interaction_mode()with|Only_Reduce_Absolute_Using_Relative|Complete_Reduced_Product->true|Only_Reduce_Relative_Using_Absolute|No_Reduced_Product->falseletdo_reduce_relative_with_absolute()=matchget_interaction_mode()with|Only_Reduce_Relative_Using_Absolute|Complete_Reduced_Product->true|Only_Reduce_Absolute_Using_Relative|No_Reduced_Product->falseletrecompute_absolute~(exact:exact)~(relative:relative)=Abstraction.(exact*relative)letrecompute_relative~(exact:exact)~(absolute:absolute)=Abstraction.(absolute/exact)leta_x_plus_b_y_over_x_plus_y~a~x~b~y=letboundss=letb=Abstraction.boundssin[b.lower;b.upper]inletpermutationslr=List.(map(funl->map(funr->l,r)r)l|>flatten)inletcompute((a,x),(b,y))=Scalar.((a*x+b*y)/(x+y))inletax_permutations=permutations(boundsa)(boundsx)inletby_permutations=permutations(boundsb)(boundsy)inletvalues=List.mapcompute(permutationsax_permutationsby_permutations)inletlower=List.fold_leftScalar.minScalar.pos_infvaluesinletupper=List.fold_leftScalar.maxScalar.neg_infvaluesinbetweenlowerupperend(* Instantiate the value using the model. *)moduleValue=structincludeValue.Make(Model)letcontextualize(name,builtin)=(name,builtin())letbuiltins=List.mapcontextualizebuiltinsend(* Reduced product with Cvalues. *)moduleReduce_Cast(Abstract:Abstractions.S):Abstractions.S=structincludeAbstractletproject_ivalcvalue=tryCvalue.V.project_ivalcvaluewithCvalue.V.Not_based_on_null->Ival.topletcastget_cvalueset_numerorscontext~src_type~dst_typevalue=letopenEval.Bottom.Operatorsinlet+result=Val.forward_castcontext~src_type~dst_typevalueinmatchsrc_type,dst_typewith|Eval_typ.(TSInt_,TSFloatfkind)->letival=get_cvaluevalue|>project_ivalinletlower,upper=Ival.min_and_maxivalinletto_neg_infv=Option.valuev~default:Rational.neg_infinletto_pos_infv=Option.valuev~default:Rational.pos_infinletlower=Option.(mapQ.of_bigintlower|>to_neg_inf)inletupper=Option.(mapQ.of_bigintupper|>to_pos_inf)inletnumerors=Value.of_scalarsfkindlowerupperinset_numerorsnumerorsresult|_->resultmoduleVal=structincludeValletforward_cast=matchgetMain_values.CVal.key,memValue.keywith|None,_|_,false->forward_cast|Someget_cvalue,true->castget_cvalue(setValue.key)endend(* Public description of the Numerors abstract domain. *)letdescr="Infers ranges for the absolute and relative errors \
in floating-point computations."(* Registration of the Numerors abstract domain and its reduced product. *)letregistered=letname="numerors"andexperimental=trueinletmoduleName=(structletname=nameend)inletmoduleDomain=Simple_memory.Make_Domain(Name)(Value)inAbstractions.Hooks.register(fun(moduleA)->(moduleReduce_Cast(A)));Abstractions.Domain.register~name~experimental~descr(moduleDomain)