<commit_before>%% -------------------------------------------------------------------
%%
%% Copyright (c) 2014 SyncFree Consortium.  All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License.  You may obtain
%% a copy of the License at
%%
%%   http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied.  See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------

-module(lasp_lattice).
-author("<NAME> <<EMAIL>>").

-include("lasp.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

%% Exported utility functions.
-export([threshold_met/3,
         is_inflation/3,
         is_lattice_inflation/3,
         is_strict_inflation/3,
         is_lattice_strict_inflation/3,
         causal_product/3,
         causal_remove/2,
         causal_union/3]).

%% @doc Determine if a threshold is met.
%%
%%      Given a particular type, `Threshold' and `Value', determine if
%%      a given threshold is met by a particular lattice.
%%
%%      When the threshold is specified as `{strict, value()', ensure
%%      that the lattice is a strict inflation over the supplied
%%      threshold.
%%
%%      `Value' and `Threshold' both should be an instance of one of the
%%      `type()'s and not a pure value.
%%
threshold_met({Type, _}, Value, Current) ->
    threshold_met(Type, Value, Current);
threshold_met(lasp_ivar, undefined, {strict, undefined}) ->
    false;
threshold_met(lasp_ivar, undefined, undefined) ->
    true;
threshold_met(lasp_ivar, Value, undefined) when Value =/= undefined ->
    true;
threshold_met(lasp_ivar, _Value, {strict, undefined}) ->
    true;
threshold_met(lasp_ivar, Value, Threshold) when Value =:= Threshold ->
    true;
threshold_met(lasp_ivar, Value, Threshold) when Value =/= Threshold ->
    false;

threshold_met(lasp_top_k_var, Value, Threshold) ->
    is_inflation(lasp_top_k_var, Threshold, Value);

threshold_met(lasp_orset_gbtree, Value, {strict, Threshold}) ->
    is_strict_inflation(lasp_orset_gbtree, Threshold, Value);
threshold_met(lasp_orset_gbtree, Value, Threshold) ->
    is_inflation(lasp_orset_gbtree, Threshold, Value);

threshold_met(lasp_orset, Value, {strict, Threshold}) ->
    is_strict_inflation(lasp_orset, Threshold, Value);
threshold_met(lasp_orset, Value, Threshold) ->
    is_inflation(lasp_orset, Threshold, Value);

threshold_met(lasp_orswot, Value, {strict, Threshold}) ->
    is_strict_inflation(lasp_orswot, Threshold, Value);
threshold_met(lasp_orswot, Value, Threshold) ->
    is_inflation(lasp_orswot, Threshold, Value);

threshold_met(riak_dt_orswot, Value, {strict, Threshold}) ->
    is_strict_inflation(riak_dt_orswot, Threshold, Value);
threshold_met(riak_dt_orswot, Value, Threshold) ->
    is_inflation(riak_dt_orswot, Threshold, Value);

threshold_met(riak_dt_map, Value, {strict, Threshold}) ->
    is_strict_inflation(riak_dt_map, Threshold, Value);
threshold_met(riak_dt_map, Value, Threshold) ->
    is_inflation(riak_dt_map, Threshold, Value);

threshold_met(riak_dt_gcounter, Value, {strict, Threshold}) ->
    Threshold < riak_dt_gcounter:value(Value);
threshold_met(riak_dt_gcounter, Value, Threshold) ->
    Threshold =< riak_dt_gcounter:value(Value).

%% @doc Determine if a change is an inflation or not.
%%
%%      Given a particular type and two instances of that type,
%%      determine if `Current' is an inflation of `Previous'.
%%
is_inflation({Type, _}, Previous, Current) ->
    is_inflation(Type, Previous, Current);
is_inflation(Type, Previous, Current) ->
    is_lattice_inflation(Type, Previous, Current).

%% @doc Determine if a change is a strict inflation or not.
%%
%%      Given a particular type and two instances of that type,
%%      determine if `Current' is a strict inflation of `Previous'.
%%
is_strict_inflation({Type, _}, Previous, Current) ->
    is_strict_inflation(Type, Previous, Current);
is_strict_inflation(Type, Previous, Current) ->
    is_lattice_strict_inflation(Type, Previous, Current).

%% @doc Determine if a change for a given type is an inflation or not.
%%
%%      Given a particular type and two instances of that type,
%%      determine if `Current' is an inflation of `Previous'.
%%
%%      Inflation of an I-Var is moving from the undefined state to a
%%      defined state.
%%
%%      Inflation of a G-Set ensures that the `Previous' sets elements
%%      are contained by the `Current' set.
%%
%%      Inflation of an OR-Set ensures that the `Previous' sets elements
%%      all exist with the same unique idenfiers as `Current'.
%%
%%      Inflation of a G-Counter ensure that all actors in the
%%      `Previous' state are covered in the `Current' state with at
%%      least the same counts.
%%
is_lattice_inflation(lasp_ivar, undefined, undefined) ->
    true;
is_lattice_inflation(lasp_ivar, undefined, _Current) ->
    true;
is_lattice_inflation(lasp_ivar, Previous, Current)
        when Previous =/= Current ->
    false;
is_lattice_inflation(lasp_ivar, Previous, Current)
        when Previous =:= Current ->
    true;

is_lattice_inflation(lasp_orswot, {Previous, _, _}, {Current, _, _}) ->
    riak_dt_vclock:descends(Current, Previous);

is_lattice_inflation(lasp_top_k_var, {K, Previous}, {K, Current}) ->
    orddict:fold(fun(Key, Value, Acc) ->
                        case orddict:find(Key, Current) of
                            error ->
                                Acc andalso false;
                            {ok, Value1} ->
                                Acc andalso (Value1 >= Value)
                        end
                end, true, Previous);

is_lattice_inflation(lasp_orset_gbtree, Previous, Current) ->
    gb_trees_ext:foldl(fun(Element, Ids, Acc) ->
                        case gb_trees:lookup(Element, Current) of
                            none ->
                                Acc andalso false;
                            {value, Ids1} ->
                                Acc andalso ids_inflated(lasp_orset_gbtree, Ids, Ids1)
                        end
                end, true, Previous);

is_lattice_inflation(lasp_orset, Previous, Current) ->
    lists:foldl(fun({Element, Ids}, Acc) ->
                        case lists:keyfind(Element, 1, Current) of
                            false ->
                                Acc andalso false;
                            {_, Ids1} ->
                                Acc andalso ids_inflated(lasp_orset, Ids, Ids1)
                        end
                end, true, Previous);

is_lattice_inflation(riak_dt_orswot, {Previous, _, _}, {Current, _, _}) ->
    riak_dt_vclock:descends(Current, Previous);

is_lattice_inflation(riak_dt_map, {Previous, _, _}, {Current, _, _}) ->
    riak_dt_vclock:descends(Current, Previous);

is_lattice_inflation(riak_dt_gcounter, Previous, Current) ->
    PreviousList = lists:sort(orddict:to_list(Previous)),
    CurrentList = lists:sort(orddict:to_list(Current)),
    lists:foldl(fun({Actor, Count}, Acc) ->
            case lists:keyfind(Actor, 1, CurrentList) of<commit_msg>Rework threshold checking for counters.<commit_after>%% -------------------------------------------------------------------
%%
%% Copyright (c) 2014 SyncFree Consortium.  All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License.  You may obtain
%% a copy of the License at
%%
%%   http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied.  See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------

-module(lasp_lattice).
-author("<NAME> <<EMAIL>>").

-include("lasp.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

%% Exported utility functions.
-export([threshold_met/3,
         is_inflation/3,
         is_lattice_inflation/3,
         is_strict_inflation/3,
         is_lattice_strict_inflation/3,
         causal_product/3,
         causal_remove/2,
         causal_union/3]).

%% @doc Determine if a threshold is met.
%%
%%      Given a particular type, `Threshold' and `Value', determine if
%%      a given threshold is met by a particular lattice.
%%
%%      When the threshold is specified as `{strict, value()', ensure
%%      that the lattice is a strict inflation over the supplied
%%      threshold.
%%
%%      `Value' and `Threshold' both should be an instance of one of the
%%      `type()'s and not a pure value.
%%
threshold_met({Type, _}, Value, Current) ->
    threshold_met(Type, Value, Current);
threshold_met(lasp_ivar, undefined, {strict, undefined}) ->
    false;
threshold_met(lasp_ivar, undefined, undefined) ->
    true;
threshold_met(lasp_ivar, Value, undefined) when Value =/= undefined ->
    true;
threshold_met(lasp_ivar, _Value, {strict, undefined}) ->
    true;
threshold_met(lasp_ivar, Value, Threshold) when Value =:= Threshold ->
    true;
threshold_met(lasp_ivar, Value, Threshold) when Value =/= Threshold ->
    false;

threshold_met(lasp_top_k_var, Value, Threshold) ->
    is_inflation(lasp_top_k_var, Threshold, Value);

threshold_met(lasp_orset_gbtree, Value, {strict, Threshold}) ->
    is_strict_inflation(lasp_orset_gbtree, Threshold, Value);
threshold_met(lasp_orset_gbtree, Value, Threshold) ->
    is_inflation(lasp_orset_gbtree, Threshold, Value);

threshold_met(lasp_orset, Value, {strict, Threshold}) ->
    is_strict_inflation(lasp_orset, Threshold, Value);
threshold_met(lasp_orset, Value, Threshold) ->
    is_inflation(lasp_orset, Threshold, Value);

threshold_met(lasp_orswot, Value, {strict, Threshold}) ->
    is_strict_inflation(lasp_orswot, Threshold, Value);
threshold_met(lasp_orswot, Value, Threshold) ->
    is_inflation(lasp_orswot, Threshold, Value);

threshold_met(riak_dt_orswot, Value, {strict, Threshold}) ->
    is_strict_inflation(riak_dt_orswot, Threshold, Value);
threshold_met(riak_dt_orswot, Value, Threshold) ->
    is_inflation(riak_dt_orswot, Threshold, Value);

threshold_met(riak_dt_map, Value, {strict, Threshold}) ->
    is_strict_inflation(riak_dt_map, Threshold, Value);
threshold_met(riak_dt_map, Value, Threshold) ->
    is_inflation(riak_dt_map, Threshold, Value);

threshold_met(riak_dt_gcounter, Value, {value, {strict, Threshold}}) ->
    Threshold < riak_dt_gcounter:value(Value);
threshold_met(riak_dt_gcounter, Value, {value, Threshold}) ->
    Threshold =< riak_dt_gcounter:value(Value);

threshold_met(riak_dt_gcounter, Value, {strict, Threshold}) ->
    is_strict_inflation(riak_dt_gcounter, Threshold, Value);
threshold_met(riak_dt_gcounter, Value, Threshold) ->
    is_inflation(riak_dt_gcounter, Threshold, Value).

%% @doc Determine if a change is an inflation or not.
%%
%%      Given a particular type and two instances of that type,
%%      determine if `Current' is an inflation of `Previous'.
%%
is_inflation({Type, _}, Previous, Current) ->
    is_inflation(Type, Previous, Current);
is_inflation(Type, Previous, Current) ->
    is_lattice_inflation(Type, Previous, Current).

%% @doc Determine if a change is a strict inflation or not.
%%
%%      Given a particular type and two instances of that type,
%%      determine if `Current' is a strict inflation of `Previous'.
%%
is_strict_inflation({Type, _}, Previous, Current) ->
    is_strict_inflation(Type, Previous, Current);
is_strict_inflation(Type, Previous, Current) ->
    is_lattice_strict_inflation(Type, Previous, Current).

%% @doc Determine if a change for a given type is an inflation or not.
%%
%%      Given a particular type and two instances of that type,
%%      determine if `Current' is an inflation of `Previous'.
%%
%%      Inflation of an I-Var is moving from the undefined state to a
%%      defined state.
%%
%%      Inflation of a G-Set ensures that the `Previous' sets elements
%%      are contained by the `Current' set.
%%
%%      Inflation of an OR-Set ensures that the `Previous' sets elements
%%      all exist with the same unique idenfiers as `Current'.
%%
%%      Inflation of a G-Counter ensure that all actors in the
%%      `Previous' state are covered in the `Current' state with at
%%      least the same counts.
%%
is_lattice_inflation(lasp_ivar, undefined, undefined) ->
    true;
is_lattice_inflation(lasp_ivar, undefined, _Current) ->
    true;
is_lattice_inflation(lasp_ivar, Previous, Current)
        when Previous =/= Current ->
    false;
is_lattice_inflation(lasp_ivar, Previous, Current)
        when Previous =:= Current ->
    true;

is_lattice_inflation(lasp_orswot, {Previous, _, _}, {Current, _, _}) ->
    riak_dt_vclock:descends(Current, Previous);

is_lattice_inflation(lasp_top_k_var, {K, Previous}, {K, Current}) ->
    orddict:fold(fun(Key, Value, Acc) ->
                        case orddict:find(Key, Current) of
                            error ->
                                Acc andalso false;
                            {ok, Value1} ->
                                Acc andalso (Value1 >= Value)
                        end
                end, true, Previous);

is_lattice_inflation(lasp_orset_gbtree, Previous, Current) ->
    gb_trees_ext:foldl(fun(Element, Ids, Acc) ->
                        case gb_trees:lookup(Element, Current) of
                            none ->
                                Acc andalso false;
                            {value, Ids1} ->
                                Acc andalso ids_inflated(lasp_orset_gbtree, Ids, Ids1)
                        end
                end, true, Previous);

is_lattice_inflation(lasp_orset, Previous, Current) ->
    lists:foldl(fun({Element, Ids}, Acc) ->
                        case lists:keyfind(Element, 1, Current) of
                            false ->
                                Acc andalso false;
                            {_, Ids1} ->
                                Acc andalso ids_inflated(lasp_orset, Ids, Ids1)
                        end
                end, true, Previous);

is_lattice_inflation(riak_dt_orswot, {Previous, _, _}, {Current, _, _}) ->
    riak_dt_vclock:descends(Current, Previous);

is_lattice_inflation(riak_dt_map, {Previous, _, _}, {Current, _, _}) ->
    riak_dt_vclock:descends(Current, Previous);

is_lattice_inflation(riak_dt_gcounter, Previous, Current) ->
    PreviousList = orddict:to_list(Previous),
    CurrentList = orddict:to_list(Current),
    lists:foldl(fun({Actor, Count}, Acc) ->
            case lists:keyfind(Actor, 1, CurrentList) of
{'fraction_non_alphanumeric': 0.12586115527291997, 'fraction_numerical': 0.003179650238473768, 'mean_word_length': 2.909114448472294, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7208452', 'n_tokens_mistral': 4720, 'n_tokens_neox': 4595, 'n_words': 1240}