defmodule Datadog.Sketch.IndexMapping do
@moduledoc """
Basic module for handling various index mapping algorithms. All functions in
this module proxy to the respective index mapping implementation module.
"""
@typedoc """
A general struct that has index mapping data. Every index mapping
implementation _must_ contain this data.
"""
@type t :: %{
__struct__: module(),
gamma: float(),
index_offset: float(),
multiplier: float()
}
@doc """
Checks if an index mapping matches another index mapping.
"""
@callback equals(t(), t()) :: boolean()
@doc """
Returns value after mapping.
"""
@callback index(t(), float()) :: integer()
@doc """
Takes a mapped value and returns the original value within the set accuracy.
"""
@callback value(t(), integer()) :: float()
@doc """
Returns the lower bound the mapping can contain.
"""
@callback lower_bound(t(), integer()) :: float()
@doc """
Returns the relative accuracy of the mapping.
"""
@callback relative_accuracy(t()) :: float()
@doc """
Returns a Protobuf-able struct for the index mapping. Used for
sending data to Datadog.
"""
@callback to_proto(t()) :: struct()
@doc """
Checks if an index mapping matches another index mapping.
iex> implementation_one = IndexMapping.Logarithmic.new(0.0000000000001)
...> implementation_two = IndexMapping.Logarithmic.new(0.0000000000002)
...> IndexMapping.equals(implementation_one, implementation_two)
true
iex> implementation_one = IndexMapping.Logarithmic.new(0.01)
...> implementation_two = IndexMapping.Logarithmic.new(0.00001)
...> IndexMapping.equals(implementation_one, implementation_two)
false
"""
@spec equals(t(), t()) :: boolean()
def equals(%{__struct__: module} = self, other), do: module.equals(self, other)
@doc """
Returns value after mapping.
iex> index_mapping = IndexMapping.Logarithmic.new(0.01)
...> IndexMapping.index(index_mapping, 115)
237
iex> index_mapping = IndexMapping.Logarithmic.new(0.001)
...> IndexMapping.index(index_mapping, 12345678901234567890)
21979
"""
@spec index(t(), float()) :: integer()
def index(%{__struct__: module} = self, value), do: module.index(self, value)
@doc """
Takes a mapped value and returns the original value within the set accuracy.
iex> index_mapping = IndexMapping.Logarithmic.new(0.01)
...> IndexMapping.value(index_mapping, 237)
115.59680764552533
iex> index_mapping = IndexMapping.Logarithmic.new(0.001)
...> IndexMapping.value(index_mapping, 21979)
1.23355147396003e19
"""
@spec value(t(), integer()) :: float()
def value(%{__struct__: module} = self, index), do: module.value(self, index)
@doc """
Returns the lower bound the mapping can contain.
iex> index_mapping = IndexMapping.Logarithmic.new(0.01)
...> IndexMapping.lower_bound(index_mapping, 0)
1.0
iex> index_mapping = IndexMapping.Logarithmic.new(0.01)
...> IndexMapping.lower_bound(index_mapping, 10)
1.2214109013609646
"""
@spec lower_bound(t(), integer()) :: float()
def lower_bound(%{__struct__: module} = self, index), do: module.lower_bound(self, index)
@doc """
Returns the lower bound the mapping can contain.
iex> index_mapping = IndexMapping.Logarithmic.new(0.01)
...> IndexMapping.relative_accuracy(index_mapping)
0.009999999999999898
"""
@spec relative_accuracy(t()) :: float()
def relative_accuracy(%{__struct__: module} = self), do: module.relative_accuracy(self)
@doc """
Returns a Protobuf-able struct for the index mapping. Used for
sending data to Datadog.
iex> index_mapping = IndexMapping.Logarithmic.new(0.01)
...> IndexMapping.to_proto(index_mapping)
%Datadog.Sketch.Protobuf.IndexMapping{gamma: 1.02020202020202, interpolation: :NONE}
"""
@spec to_proto(t()) :: struct()
def to_proto(%{__struct__: module} = self), do: module.to_proto(self)
@doc """
Checks if the two values are within the tolerance given.
## Examples
iex> IndexMapping.within_tolerance(90, 134, 50)
true
iex> IndexMapping.within_tolerance(0.00128, 0.00864, 0.01)
false
"""
@spec within_tolerance(float(), float(), float()) :: bool()
def within_tolerance(x, y, tolerance) do
if x == 0 or y == 0 do
abs(x) <= tolerance and abs(y) <= tolerance
else
abs(x - y) <= tolerance * max(abs(x), abs(y))
end
end
end