Next: bit_buffer, Previous: benchmarking, Up: Top [Contents]
%--------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%--------------------------------------------------%
% Copyright (C) 1994-1995,1997,1999,2004-2006,2008,2011-2012 The University of Melbourne.
% Copyright (C) 2013-2019, 2022-2023, 2025 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%--------------------------------------------------%
%
% File: bimap.m.
% Main author: conway.
% Stability: high.
%
% This file provides a bijective map ADT.
% A map (also known as a dictionary or an associative array) is a collection
% of (Key, Value) pairs which allows you to look up any Value given its Key.
% A bimap also allows you to efficiently look up the Key given the Value.
% This time efficiency comes at the expense of using twice as much space.
%
%--------------------------------------------------%
%--------------------------------------------------%
:- module bimap.
:- interface.
:- import_module assoc_list.
:- import_module list.
:- import_module map.
:- import_module maybe.
%--------------------------------------------------%
:- type bimap(K, V).
%--------------------------------------------------%
% Initialize an empty bimap.
%
:- func init = bimap(K, V).
:- pred init(bimap(K, V)::out) is det.
% Initialize a bimap with the given key-value pair.
%
:- func singleton(K, V) = bimap(K, V).
% Check whether a bimap is empty.
%
:- pred is_empty(bimap(K, V)::in) is semidet.
% True if both bimaps have the same set of key-value pairs, regardless of
% how the bimaps were constructed.
%
% Unifying bimaps does not work as one might expect because the internal
% structures of two bimaps that contain the same set of key-value pairs
% may be different.
%
:- pred equal(bimap(K, V)::in, bimap(K, V)::in) is semidet.
% Search the bimap. The first mode searches for a value given a key
% and the second mode searches for a key given a value.
%
:- pred search(bimap(K, V), K, V).
:- mode search(in, in, out) is semidet.
:- mode search(in, out, in) is semidet.
% Search the bimap for the value corresponding to a given key.
%
:- func forward_search(bimap(K, V), K) = V is semidet.
:- pred forward_search(bimap(K, V)::in, K::in, V::out) is semidet.
% Search the bimap for the key corresponding to the given value.
%
:- func reverse_search(bimap(K, V), V) = K is semidet.
:- pred reverse_search(bimap(K, V)::in, K::out, V::in) is semidet.
% Look up the value in the bimap corresponding to the given key.
% Throws an exception if the key is not present in the bimap.
%
:- func lookup(bimap(K, V), K) = V.
:- pred lookup(bimap(K, V)::in, K::in, V::out) is det.
% Look up the key in the bimap corresponding to the given value.
% Throws an exception if the value is not present in the bimap.
%
:- func reverse_lookup(bimap(K, V), V) = K.
:- pred reverse_lookup(bimap(K, V)::in, K::out, V::in) is det.
% Succeeds if-and-only-if the bimap contains the given key.
%
:- pred contains_key(bimap(K, V)::in, K::in) is semidet.
% Succeeds if-and-only-if the bimap contains the given value.
%
:- pred contains_value(bimap(K, V)::in, V::in) is semidet.
% Given a bimap, return a list of all the keys in the bimap.
%
:- func ordinates(bimap(K, V)) = list(K).
:- pred ordinates(bimap(K, V)::in, list(K)::out) is det.
% Given a bimap, return a list of all the data values in the bimap.
%
:- func coordinates(bimap(K, V)) = list(V).
:- pred coordinates(bimap(K, V)::in, list(V)::out) is det.
% Insert a new key-value pair into the bimap.
% Fails if either the key or value already exists.
%
:- func insert(bimap(K, V), K, V) = bimap(K, V) is semidet.
:- pred insert(K::in, V::in, bimap(K, V)::in, bimap(K, V)::out)
is semidet.
% As above but throws an exception if the key or value already
% exists.
%
:- func det_insert(bimap(K, V), K, V) = bimap(K, V).
:- pred det_insert(K::in, V::in, bimap(K, V)::in, bimap(K, V)::out)
is det.
% search_insert(K, V, MaybeOldV, !Bimap):
%
% Search for the key K in the bimap. If the key is already in the bimap,
% with corresponding value OldV, set MaybeOldV to yes(OldV). If it
% is not in the bimap, then insert it with value V, and set MaybeOldV
% to no. The value of V should be guaranteed to be different to
% all the values already in !.Bimap. If it isn't, this predicate
% will throw an exception.
%
:- pred search_insert(K::in, V::in, maybe(V)::out,
bimap(K, V)::in, bimap(K, V)::out) is det.
% Update the key and value if already present, otherwise insert the
% new key and value.
%
% NOTE: setting the key-value pair (K, V) will remove the key-value pairs
% (K, V1) and (K1, V) if they exist.
%
:- func set(bimap(K, V), K, V) = bimap(K, V).
:- pred set(K::in, V::in, bimap(K, V)::in, bimap(K, V)::out) is det.
% Insert key-value pairs from an association list into the given bimap.
% Fails if the contents of the association list and the initial bimap
% do not implicitly form a bijection.
%
:- func insert_from_assoc_list(assoc_list(K, V), bimap(K, V)) =
bimap(K, V) is semidet.
:- pred insert_from_assoc_list(assoc_list(K, V)::in,
bimap(K, V)::in, bimap(K, V)::out) is semidet.
% As above but throws an exception if the association list and
% initial bimap are not implicitly bijective.
%
:- func det_insert_from_assoc_list(assoc_list(K, V), bimap(K, V))
= bimap(K, V).
:- pred det_insert_from_assoc_list(assoc_list(K, V)::in,
bimap(K, V)::in, bimap(K, V)::out) is det.
% Insert key-value pairs from a pair of corresponding lists.
% Throws an exception if the lists are not of equal lengths
% or if they do not implicitly define a bijection.
%
:- func det_insert_from_corresponding_lists(list(K), list(V),
bimap(K, V)) = bimap(K, V).
:- pred det_insert_from_corresponding_lists(list(K)::in, list(V)::in,
bimap(K, V)::in, bimap(K, V)::out) is det.
% Apply set to each key-value pair in the association list.
% The key-value pairs from the association list may update existing keys
% and values in the bimap.
%
:- func set_from_assoc_list(assoc_list(K, V), bimap(K, V))
= bimap(K, V).
:- pred set_from_assoc_list(assoc_list(K, V)::in,
bimap(K, V)::in, bimap(K, V)::out) is det.
% As above but with a pair of corresponding lists in place of an
% association list. Throws an exception if the lists are not of
% equal length.
%
:- func set_from_corresponding_lists(list(K), list(V),
bimap(K, V)) = bimap(K, V).
:- pred set_from_corresponding_lists(list(K)::in, list(V)::in,
bimap(K, V)::in, bimap(K, V)::out) is det.
% Delete a key-value pair from a bimap. If the key is not present,
% leave the bimap unchanged.
%
:- func delete_key(bimap(K, V), K) = bimap(K, V).
:- pred delete_key(K::in, bimap(K, V)::in, bimap(K, V)::out) is det.
% Delete a key-value pair from a bimap. If the value is not present,
% leave the bimap unchanged.
%
:- func delete_value(bimap(K, V), V) = bimap(K, V).
:- pred delete_value(V::in, bimap(K, V)::in, bimap(K, V)::out) is det.
% Apply delete_key to a list of keys.
%
:- func delete_keys(bimap(K, V), list(K)) = bimap(K, V).
:- pred delete_keys(list(K)::in, bimap(K, V)::in, bimap(K, V)::out)
is det.
% Apply delete_value to a list of values.
%
:- func delete_values(bimap(K, V), list(V)) = bimap(K, V).
:- pred delete_values(list(V)::in, bimap(K, V)::in, bimap(K, V)::out)
is det.
% overlay(BIMapA, BIMapB, BIMap):
% Apply map.overlay to the forward maps of BIMapA and BIMapB,
% and compute the reverse map from the resulting map.
%
:- func overlay(bimap(K, V), bimap(K, V)) = bimap(K, V).
:- pred overlay(bimap(K, V)::in, bimap(K, V)::in, bimap(K, V)::out)
is det.
% Count the number of key-value pairs in the bimap.
%
:- func count(bimap(K, V)) = int.
% Convert a bimap to an association list.
%
:- func to_assoc_list(bimap(K, V)) = assoc_list(K, V).
:- pred to_assoc_list(bimap(K, V)::in, assoc_list(K, V)::out) is det.
% Convert an association list to a bimap. Fails if the association list
% does not implicitly define a bijection, i.e. a key or value occurs
% multiple times in the association list.
%
:- func from_assoc_list(assoc_list(K, V)) = bimap(K, V) is semidet.
:- pred from_assoc_list(assoc_list(K, V)::in, bimap(K, V)::out)
is semidet.
% As above but throws an exception instead of failing if the
% association list does not implicitly define a bijection.
%
:- func det_from_assoc_list(assoc_list(K, V)) = bimap(K, V).
:- pred det_from_assoc_list(assoc_list(K, V)::in, bimap(K, V)::out)
is det.
% Convert a pair of lists into a bimap. Fails if the lists do not
% implicitly define a bijection or if the lists are of unequal length.
%
:- func from_corresponding_lists(list(K), list(V)) = bimap(K, V)
is semidet.
:- pred from_corresponding_lists(list(K)::in, list(V)::in,
bimap(K, V)::out) is semidet.
% As above but throws an exception instead of failing if the lists
% do not implicitly define a bijection or are of unequal length.
%
:- func det_from_corresponding_lists(list(K), list(V)) = bimap(K, V).
:- pred det_from_corresponding_lists(list(K)::in, list(V)::in,
bimap(K, V)::out) is det.
:- func apply_forward_map_to_list(bimap(K, V), list(K)) = list(V).
:- pred apply_forward_map_to_list(bimap(K, V)::in, list(K)::in,
list(V)::out) is det.
:- func apply_reverse_map_to_list(bimap(K, V), list(V)) = list(K).
:- pred apply_reverse_map_to_list(bimap(K, V)::in, list(V)::in,
list(K)::out) is det.
% Apply a transformation predicate to all the keys.
% Throws an exception if the resulting bimap is not bijective.
%
:- func map_keys(func(V, K) = L, bimap(K, V)) = bimap(L, V).
:- pred map_keys(pred(V, K, L)::in(pred(in, in, out) is det),
bimap(K, V)::in, bimap(L, V)::out) is det.
% Apply a transformation predicate to all the values.
% Throws an exception if the resulting bimap is not bijective.
%
:- func map_values(func(K, V) = W, bimap(K, V)) = bimap(K, W).
:- pred map_values(pred(K, V, W)::in(pred(in, in, out) is det),
bimap(K, V)::in, bimap(K, W)::out) is det.
% Perform an inorder traversal, by key, of the bimap, applying an
% accumulator predicate for each key-value pair.
%
:- func foldl(func(K, V, A) = A, bimap(K, V), A) = A.
:- pred foldl(pred(K, V, A, A), bimap(K, V), A, A).
:- mode foldl(in(pred(in, in, in, out) is det), in, in, out) is det.
:- mode foldl(in(pred(in, in, mdi, muo) is det), in, mdi, muo) is det.
:- mode foldl(in(pred(in, in, di, uo) is det), in, di, uo) is det.
:- mode foldl(in(pred(in, in, in, out) is semidet), in, in, out) is semidet.
:- mode foldl(in(pred(in, in, mdi, muo) is semidet), in, mdi, muo) is semidet.
:- mode foldl(in(pred(in, in, di, uo) is semidet), in, di, uo) is semidet.
% Perform a traversal of the bimap, applying an accumulator predicate
% with two accumulators for each key-value pair. (Although no more
% expressive than foldl, this is often a more convenient format,
% and a little more efficient).
%
:- pred foldl2(pred(K, V, A, A, B, B), bimap(K, V), A, A, B, B).
:- mode foldl2(in(pred(in, in, in, out, in, out) is det),
in, in, out, in, out) is det.
:- mode foldl2(in(pred(in, in, in, out, mdi, muo) is det),
in, in, out, mdi, muo) is det.
:- mode foldl2(in(pred(in, in, in, out, di, uo) is det),
in, in, out, di, uo) is det.
:- mode foldl2(in(pred(in, in, di, uo, di, uo) is det),
in, di, uo, di, uo) is det.
:- mode foldl2(in(pred(in, in, in, out, in, out) is semidet),
in, in, out, in, out) is semidet.
:- mode foldl2(in(pred(in, in, in, out, mdi, muo) is semidet),
in, in, out, mdi, muo) is semidet.
:- mode foldl2(in(pred(in, in, in, out, di, uo) is semidet),
in, in, out, di, uo) is semidet.
% Perform a traversal of the bimap, applying an accumulator predicate
% with three accumulators for each key-value pair. (Although no more
% expressive than foldl, this is often a more convenient format,
% and a little more efficient).
%
:- pred foldl3(pred(K, V, A, A, B, B, C, C), bimap(K, V),
A, A, B, B, C, C).
:- mode foldl3(in(pred(in, in, in, out, in, out, in, out) is det),
in, in, out, in, out, in, out) is det.
:- mode foldl3(in(pred(in, in, in, out, in, out, mdi, muo) is det),
in, in, out, in, out, mdi, muo) is det.
:- mode foldl3(in(pred(in, in, in, out, in, out, di, uo) is det),
in, in, out, in, out, di, uo) is det.
:- mode foldl3(in(pred(in, in, in, out, di, uo, di, uo) is det),
in, in, out, di, uo, di, uo) is det.
:- mode foldl3(in(pred(in, in, di, uo, di, uo, di, uo) is det),
in, di, uo, di, uo, di, uo) is det.
:- mode foldl3(in(pred(in, in, in, out, in, out, in, out) is semidet),
in, in, out, in, out, in, out) is semidet.
:- mode foldl3(in(pred(in, in, in, out, in, out, mdi, muo) is semidet),
in, in, out, in, out, mdi, muo) is semidet.
:- mode foldl3(in(pred(in, in, in, out, in, out, di, uo) is semidet),
in, in, out, in, out, di, uo) is semidet.
% Extract a the forward map from the bimap, the map from key to value.
%
:- func forward_map(bimap(K, V)) = map(K, V).
% Extract the reverse map from the bimap, the map from value to key.
%
:- func reverse_map(bimap(K, V)) = map(V, K).
%--------------------------------------------------%
%--------------------------------------------------%
Next: bit_buffer, Previous: benchmarking, Up: Top [Contents]