https://gitlab.com/tezos/tezos
Raw File
Tip revision: 2d5c013526b75497bed330a4e73d6a5b3a8df596 authored by Arvid Jakobsson on 13 February 2024, 14:37:55 UTC
[pre-commit]: check GitLab CI schema validation
Tip revision: 2d5c013
model.mli
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2022 Nomadic Labs. <contact@nomadic-labs.com>               *)
(*                                                                           *)
(* Permission is hereby granted, free of charge, to any person obtaining a   *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense,  *)
(* and/or sell copies of the Software, and to permit persons to whom the     *)
(* Software is furnished to do so, subject to the following conditions:      *)
(*                                                                           *)
(* The above copyright notice and this permission notice shall be included   *)
(* in all copies or substantial portions of the Software.                    *)
(*                                                                           *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL   *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING   *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER       *)
(* DEALINGS IN THE SOFTWARE.                                                 *)
(*                                                                           *)
(*****************************************************************************)

(** Specifying model arity and eliminator type *)
type (_, _, _) arity =
  | Zero_arity : ('elt, 'elt, unit) arity
  | Succ_arity : ('elt, 'b, 'a) arity -> ('elt, 'elt -> 'b, int * 'a) arity

val arity_0 : ('elt, 'elt, unit) arity

val arity_1 : ('elt, 'elt -> 'elt, int * unit) arity

val arity_2 : ('elt, 'elt -> 'elt -> 'elt, int * (int * unit)) arity

val arity_3 :
  ('elt, 'elt -> 'elt -> 'elt -> 'elt, int * (int * (int * unit))) arity

(** Abstract representation of models.
    Models are strongly typed: {!Model_impl.arg_type} exposes what a model
    expects on input. The relation between [arg_type] and [model_type]
    is encoded through a value of type [arity]. *)
module type Model_impl = sig
  type arg_type

  val name : Namespace.t

  (** If [true], the generated function takes
      [Saturation_repr.may_saturate Saturation_repr.t] as arguments
      instead of [int]s. Otherwise, the generated function takes [int]s.
  *)
  val takes_saturation_reprs : bool

  module Def (X : Costlang.S) : sig
    type model_type

    val arity : (X.size, model_type, arg_type) arity

    val model : model_type X.repr
  end
end

type 'arg model = (module Model_impl with type arg_type = 'arg)

type packed_model = Model : _ model -> packed_model

(** Instantiation of a {!Model_impl.Def} with a {!Costlang.S} *)
module type Instantiated = sig
  type 'a repr

  type size

  type arg_type

  type model_type

  val arity : (size, model_type, arg_type) arity

  val model : arg_type -> size repr
end

module Instantiate (X : Costlang.S) (M : Model_impl) :
  Instantiated
    with type 'a repr = 'a X.repr
     and type size = X.size
     and type arg_type = M.arg_type

(** Model that has been applied to some arguments. Typically, we get an Applied
    model when we apply some workload from a benchmark to its model.
    Can be obtained with {!apply}.
 *)
module type Applied = functor (X : Costlang.S) -> sig
  type t = X.size X.repr

  val applied : t
end

type applied = (module Applied)

(** Model containers for benchmarks. We distinguish two kinds:
    - Abstract, which is simply a ['arg model], with a [conv] function
      that transforms a benchmark's workload into the model's arguments.
    - Aggregate, which is usually obtained from multiple models, a subset
      of which should be in [sub_models].
*)
type 'workload t =
  | Abstract : {conv : 'workload -> 'arg; model : 'arg model} -> 'workload t
  | Aggregate : {
      model : 'workload -> applied;
      sub_models : packed_model list;
    }
      -> 'workload t

val pp : Format.formatter -> _ t -> unit

(** Build [_ t] from [_ model], with a type conversion fucntion [conv].
    If [~takes_saturation_reprs: true] is given, its generated code
    will take [_ Saturation_reprs.t] instead of [int].
*)
val make : ?takes_saturation_reprs:bool -> conv:('a -> 'b) -> 'b model -> 'a t

val make_aggregated :
  model:('a -> applied) -> sub_models:packed_model list -> 'a t

(** [apply] takes a model and an appropriate workload, and returns an applied model *)
val apply : 'a t -> 'a -> applied

(** Addition on models. Note that the results is always an {!Aggregate} *)
val add_model : 'a t -> 'b t -> ('a * 'b) t

(** Transformator for the type of workloads *)
val precompose : ('a -> 'b) -> 'b t -> 'a t

(** Returns the set of free variables of a model *)
val get_free_variable_set : _ model -> Free_variable.Set.t

val get_free_variable_set_of_t : _ t -> Free_variable.Set.t

(** Returns the set of free variables of an applied model

    Note that this can be very different from [get_free_variable_set].
*)
val get_free_variable_set_applied :
  'workload t -> 'workload -> Free_variable.Set.t

(* -------------------------------------------------------------------------- *)
(** Commonly used abstract models
    Except for [zero], they all require a unique name in {!Namespace.t}, and some
    {!Free_variable.t}s. Those free are deduced during the inference in Snoop, and
    the resulting values are (usually) the gas parameters for the protocol.
*)

(** [zero] is the "zero" for the addition on models. It can be seen as the model
    of the empty code.
    [fun () -> 0]
*)
val zero : unit model

(** Model for code that executes in constant time
    [fun () -> const]
*)
val unknown_const1 : name:Namespace.t -> const:Free_variable.t -> unit model

(** Model ignores the arguments.
    [fun n -> const]
*)
val unknown_const1_skip1 :
  name:Namespace.t -> const:Free_variable.t -> (int * unit) model

(** Model ignores the arguments.
    [fun n m -> const]
*)
val unknown_const1_skip2 :
  name:Namespace.t -> const:Free_variable.t -> (int * (int * unit)) model

(** [fun n -> coeff × n] *)
val linear : name:Namespace.t -> coeff:Free_variable.t -> (int * unit) model

(** [fun n -> intercept + coeff × n] *)
val affine :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * unit) model

(** [fun n -> intercept + coeff × (n - offset)] *)
val affine_offset :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  offset:int ->
  (int * unit) model

(** [fun n -> coeff * n²] *)
val quadratic : name:Namespace.t -> coeff:Free_variable.t -> (int * unit) model

(** [fun n -> intercept + coeff × n×log(n)] *)
val nlogn :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * unit) model

(** [fun n -> intercept + coeff × n×sqrt(n)] *)
val nsqrtn_const :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * unit) model

(** [fun n -> coeff * log(n)] *)
val logn : name:Namespace.t -> coeff:Free_variable.t -> (int * unit) model

(** [fun a b -> intercept + coeff × (a+b)] *)
val linear_sum :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** [fun a b -> intercept + coeff × (a-b)] *)
val linear_sat_sub :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** [fun a b -> intercept + coeff × max(a,b)] *)
val linear_max :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** fun a b -> intercept + coeff × min(a,b) *)
val linear_min :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** fun a b -> intercept + coeff × (min(a,b) - offset) *)
val linear_min_offset :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  offset:int ->
  (int * (int * unit)) model

(** [fun a b -> intercept + coeff × (a×b)] *)
val linear_mul :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** [fun a b -> coeff1 × a + coeff2 × b] *)
val bilinear :
  name:Namespace.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  (int * (int * unit)) model

(** [fun a b -> intercept + coeff1 × a + coeff2 × b] *)
val bilinear_affine :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  (int * (int * unit)) model

(** [fun a b -> intercept + coeff × b] *)
val affine_skip1 :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** [fun n m -> intercept + coeff × n×log(m)] *)
val nlogm :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  coeff:Free_variable.t ->
  (int * (int * unit)) model

(** [fun n m -> intercept + (linear_coeff × n) + (log_coeff × log(m))] *)
val n_plus_logm :
  name:Namespace.t ->
  intercept:Free_variable.t ->
  linear_coeff:Free_variable.t ->
  log_coeff:Free_variable.t ->
  (int * (int * unit)) model

(** [fun a b c -> coeff1 × a + coeff2 × b + coeff3 × c] *)
val trilinear :
  name:Namespace.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  coeff3:Free_variable.t ->
  (int * (int * (int * unit))) model

(** A multi-affine model in two parts. The breakpoint [break] indicates the
    point at which the slope changes coefficient.
*)
val breakdown :
  name:Namespace.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  break:int ->
  (int * unit) model

(** A multi-affine model in three parts, with breakpoints [break1] and [break2].
    Expects [break1] <= [break2]
 *)
val breakdown2 :
  name:Namespace.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  coeff3:Free_variable.t ->
  break1:int ->
  break2:int ->
  (int * unit) model

(** [breakdown2] with a non-zero value at 0 *)
val breakdown2_const :
  name:Namespace.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  coeff3:Free_variable.t ->
  const:Free_variable.t ->
  break1:int ->
  break2:int ->
  (int * unit) model

(** [breakdown2] with a non-zero value at 0 and offset *)
val breakdown2_const_offset :
  name:Namespace.t ->
  coeff1:Free_variable.t ->
  coeff2:Free_variable.t ->
  coeff3:Free_variable.t ->
  const:Free_variable.t ->
  break1:int ->
  break2:int ->
  offset:int ->
  (int * unit) model

(* -------------------------------------------------------------------------- *)

module type Binary_operation = sig
  module Def (X : Costlang.S) : sig
    val op : X.size X.repr -> X.size X.repr -> X.size X.repr
  end
end

(** Synthesize two models of the same signature by the specified binary operation.
*)
val synthesize :
  name:Namespace.t ->
  binop:(module Binary_operation) ->
  x_label:string ->
  x_model:'a model ->
  y_label:string ->
  y_model:'a model ->
  'a model
back to top