Esempio n. 1
0
def object_hook_f(obj):
    """``obj`` is a representation of a straightforward translation of JSON into Python. For a known
    special construct (must be a ``dict``), convert it into its correct object representation and
    return it. Otherwise return ``obj`` as-is. (May be used as ``object_hook`` function for the
    various JSON decoder APIs.)
    """
    if len(obj) == 2 and '__cls__' in obj and '__val__' in obj:
        if obj['__cls__'] == 'builtin.bytes':
            return bytes(elem for elem in obj['__val__'])
        if obj['__cls__'] == 'builtin.complex':
            return complex(obj['__val__'])
        if obj['__cls__'] == 'builtin.frozenset':
            return frozenset(decode(elem) for elem in obj['__val__'])
        if obj['__cls__'] == 'builtin.list':
            return list(decode(elem) for elem in obj['__val__'])
        if obj['__cls__'] == 'builtin.range':
            return range(decode(obj['__val__'][0]), decode(obj['__val__'][1]),
                         decode(obj['__val__'][2]))
        if obj['__cls__'] == 'builtin.tuple':
            return tuple(decode(elem) for elem in obj['__val__'])
        if obj['__cls__'] == 'Atom':
            return _mo.Atom(decode(obj['__val__']), direct_load=True)
        if obj['__cls__'] == 'Couplet':
            return _mo.Couplet(left=decode(obj['__val__'][0]),
                               right=decode(obj['__val__'][1]),
                               direct_load=True)
        if obj['__cls__'] == 'Set':
            return _mo.Set((decode(elem) for elem in obj['__val__']),
                           direct_load=True)
        if obj['__cls__'] == 'Multiset':
            return _mo.Multiset(
                {decode(val): mult
                 for val, mult in obj['__val__']},
                direct_load=True)
    return obj
Esempio n. 2
0
def order_slice(mclan: 'P(P(M x M) x N)',
                less_than_f,
                offset: '( A )',
                limit: '( A )',
                _checked: bool = True) -> 'P(P(M x M) x N)':
    r"""Return a multiclan that contains the relations with indices ``offset <= index < offset +
    limit``, after having been ordered according to ``order``.

    :param mclan: The source data. Must be a :term:`multiclan`.
    :param less_than_f: A function that accepts two :term:`relation`\s as arguments and returns
        ``True`` if the first one is less than the second one.
    :param offset: An :term:`atom` with an integer value that indicates the index of the first
        relation (after sorting the multiclan) in the result. Set to ``Atom(0)`` if you want to
        start with the first relation of the sorted multiclan.
    :param limit: An atom with an integer value that indicates how many relations should be in
        the resulting multiclan. When ``limit`` is ``float('inf')``, all relations are returned.
    """
    tuple_list_generator = order_slice_to_listgen(mclan, less_than_f, offset,
                                                  limit, _checked)
    if tuple_list_generator is _undef.Undef():
        return _undef.Undef()
    mclan = _mo.Multiset({rel: mult
                          for (rel, mult) in tuple_list_generator},
                         direct_load=True)
    return mclan
Esempio n. 3
0
def make_labeled_partition(set_or_mset, class_invariant_func):
    r"""Return a 'labeled' partition of ``set_or_mset``, partitioned according to
    ``class_invariant_func``.

    :param set_or_mset: The :term:`set` or :term:`multiset` that is to be partitioned.
    :param class_invariant_func: A function from elements of ``set_or_mset`` to `MathObject`\s. It
        defines an :term:`equivalence relation` on ``set_or_mset`` such that

        .. math:: x, y \in set\_or\_mset :
            x \equiv y \iff class\_invariant\_func(x) = class\_invariant\_func(y)

    :return: A :term:`function` with structure :math:`P(range(class\_invariant\_func) \times
        P(set\_or\_mset.ground\_set))` that maps the range of ``class_invariant_func`` when
        applied to ``set_or_mset`` to sets of elements of ``set_or_mset`` that belong to the
        given equivalence class.
    """
    if set_or_mset.is_set:
        partition_dict = _create_partition_dict_from_set(set_or_mset, class_invariant_func)
        return _mo.Set((_mo.Couplet(label, _mo.Set(components, direct_load=True)
                .cache_clan(set_or_mset.cached_clan), direct_load=True)
            for label, components in partition_dict.items()), direct_load=True)
    elif set_or_mset.is_multiset:
        partition_dict = _create_partition_dict_from_multiset(set_or_mset, class_invariant_func)
        return _mo.Set((_mo.Couplet(label, _mo.Multiset(counter, direct_load=True)
                .cache_multiclan(set_or_mset.cached_multiclan), direct_load=True)
            for label, counter in partition_dict.items()), direct_load=True)
    else:
        raise AssertionError('First argument must be Set or Multiset')
Esempio n. 4
0
def partition(set_or_mset, class_invariant_func):
    r"""Return ``set_or_mset`` partitioned according to ``class_invariant_func``.

    :param set_or_mset: The :term:`set` or :term:`multiset` that is to be partitioned.
    :param class_invariant_func: A function from elements of ``set_or_mset`` to
        `MathObject`\s. It defines an :term:`equivalence relation` on ``set_or_mset`` such that

        .. math:: x, y \in set\_or\_mset :
            x \equiv y \iff class\_invariant\_func(x) = class\_invariant\_func(y)

    :return: A set with structure :math:`P(set\_or\_mset.ground\_set)` that defines a partition on
        ``set_or_mset``, imposed by the equivalence relation defined by the function
        ``class_invariant_func``.
    """
    if set_or_mset.is_set:
        partition_dict = _create_partition_dict_from_set(set_or_mset, class_invariant_func)
        # Create the resulting Set of Sets from the partition components.
        return _mo.Set((_mo.Set(components, direct_load=True)
            .cache_clan(set_or_mset.cached_clan)
            for components in partition_dict.values()), direct_load=True)
    elif set_or_mset.is_multiset:
        partition_dict = _create_partition_dict_from_multiset(set_or_mset, class_invariant_func)
        # Create the resulting Set of Multisets from the partition components.
        return _mo.Set((_mo.Multiset(counter, direct_load=True)
            .cache_multiclan(set_or_mset.cached_multiclan)
            for counter in partition_dict.values()), direct_load=True)
    else:
        raise AssertionError('First argument must be Set or Multiset')
Esempio n. 5
0
    def intersect(multiset1: 'P( M x N )',
                  multiset2: 'P( M x N )',
                  _checked=True) -> 'P( M x N )':
        """Return the multiset intersection of ``multiset1`` with ``multiset2``.

        :return: The :term:`multiset intersection` of ``multiset1`` and ``multiset2`` or `Undef()`
            if ``multiset1`` or ``multiset2`` are not instances of :class:`~.Multiset`.
        """
        if _checked:
            if not is_member(multiset1):
                return _undef.make_or_raise_undef2(multiset1)
            if not is_member(multiset2):
                return _undef.make_or_raise_undef2(multiset2)
        else:
            assert is_member_or_undef(multiset1)
            assert is_member_or_undef(multiset2)
            if multiset1 is _undef.Undef() or multiset2 is _undef.Undef():
                return _undef.make_or_raise_undef(2)
        values = multiset1.data & multiset2.data
        result = _mo.Multiset(values)
        if not result.is_empty:
            # Multiclan flags:
            if multiset1.cached_is_multiclan or multiset2.cached_is_multiclan:
                result.cache_multiclan(CacheStatus.IS)
                if multiset1.cached_is_absolute or multiset2.cached_is_absolute:
                    result.cache_absolute(CacheStatus.IS)
                if multiset1.cached_is_functional or multiset2.cached_is_functional:
                    result.cache_functional(CacheStatus.IS)
                if multiset1.cached_is_right_functional or multiset2.cached_is_right_functional:
                    result.cache_right_functional(CacheStatus.IS)
                if multiset1.cached_is_regular or multiset2.cached_is_regular:
                    result.cache_regular(CacheStatus.IS)
                if multiset1.cached_is_right_regular or multiset2.cached_is_right_regular:
                    result.cache_right_regular(CacheStatus.IS)
        return result
Esempio n. 6
0
def from_dict(dict1: dict) -> 'P(P(M x M) x N)':
    r"""Return a :term:`multiclan` with a single :term:`relation` where the :term:`couplet`\s are the
    elements of ``dict1``."""
    rel = _relations.from_dict(dict1)
    mclan = _mo.Multiset(rel, direct_load=True)
    mclan.cache_multiclan(_mo.CacheStatus.IS)
    mclan.cache_functional(_mo.CacheStatus.IS)
    mclan.cache_regular(_mo.CacheStatus.IS)
    return mclan
Esempio n. 7
0
def diag(*args, _checked=True) -> 'P(P(M x M) x N)':
    """Return a multiclan diagonal of the arguments.

    :param args: Pass in the elements from which the :term:`clan diagonal` is formed. (If you want
        to pass in an iterable, you need to prefix it with an asterisk ``*``.)
    """
    rels = _relations.diag(*args, _checked=_checked)
    if rels is _undef.Undef():
        return _undef.make_or_raise_undef(2)
    clan = _mo.Multiset(rels, direct_load=True)
    clan.cache_multiclan(CacheStatus.IS)
    clan.cache_functional(CacheStatus.IS).cache_right_functional(
        CacheStatus.IS)
    clan.cache_reflexive(CacheStatus.IS).cache_symmetric(CacheStatus.IS)
    clan.cache_regular(CacheStatus.IS).cache_right_regular(CacheStatus.IS)
    return clan
Esempio n. 8
0
    def union(multiset1: 'P( M x N )',
              multiset2: 'P( M x N )',
              _checked=True) -> 'P( M x N )':
        """Return the multiset union of ``multiset1`` with ``multiset2``.

        :return: The :term:`multiset union` of ``multiset1`` and ``multiset2`` or `Undef()` if
            ``multiset1`` or ``multiset2`` are not instances of :class:`~.Multiset`.
        """
        # pylint: disable=too-many-branches
        if _checked:
            if not is_member(multiset1):
                return _undef.make_or_raise_undef2(multiset1)
            if not is_member(multiset2):
                return _undef.make_or_raise_undef2(multiset2)
        else:
            assert is_member_or_undef(multiset1)
            assert is_member_or_undef(multiset2)
            if multiset1 is _undef.Undef() or multiset2 is _undef.Undef():
                return _undef.make_or_raise_undef(2)
        values = multiset1.data | multiset2.data
        result = _mo.Multiset(values, direct_load=True)
        if not result.is_empty:
            # Multiclan flags:
            if multiset1.cached_is_multiclan and multiset2.cached_is_multiclan:
                result.cache_multiclan(CacheStatus.IS)
                if multiset1.cached_is_absolute and multiset2.cached_is_absolute:
                    result.cache_absolute(CacheStatus.IS)
                elif multiset1.cached_is_not_absolute or multiset2.cached_is_not_absolute:
                    result.cache_absolute(CacheStatus.IS_NOT)
                if multiset1.cached_is_functional and multiset2.cached_is_functional:
                    result.cache_functional(CacheStatus.IS)
                elif multiset1.cached_is_not_functional or multiset2.cached_is_not_functional:
                    result.cache_functional(CacheStatus.IS_NOT)
                if multiset1.cached_is_right_functional and multiset2.cached_is_right_functional:
                    result.cache_right_functional(CacheStatus.IS)
                elif multiset1.cached_is_not_right_functional \
                        or multiset2.cached_is_not_right_functional:
                    result.cache_right_functional(CacheStatus.IS_NOT)
                if multiset1.cached_is_not_regular or multiset1.cached_is_not_regular:
                    result.cache_regular(CacheStatus.IS_NOT)
                if multiset1.cached_is_not_right_regular or multiset1.cached_is_not_right_regular:
                    result.cache_right_regular(CacheStatus.IS_NOT)
            elif multiset1.cached_is_not_multiclan or multiset2.cached_is_not_multiclan:
                result.cache_multiclan(CacheStatus.IS_NOT)
        return result
Esempio n. 9
0
def unary_multi_extend(set_or_mset, op, _checked=True) -> 'P( M x N )':
    r"""Return the :term:`unary extension` of ``op`` from one :term:`algebra` to another algebra.

    For this extension, the elements of the extended algebra must be :term:`multiset`\s of the
    elements of the original algebra.

    :param set_or_mset: A :term:`set` or a :term:`multiset` with elements on which ``op`` operates.
    :param op: A :term:`unary operation` that operates on the elements of ``set_or_mset``.
    :return: A set that consists of the defined results of ``op`` when executed on the elements of
        ``set_or_mset``, or `Undef()` if ``set_or_mset`` is neither a set nor a multiset.
    """
    if _checked:
        if not _multisets.is_member(set_or_mset) and not _sets.is_member(
                set_or_mset):
            return _undef.make_or_raise_undef2(set_or_mset)
    else:
        assert _multisets.is_member(set_or_mset) or _sets.is_member(set_or_mset) \
               or set_or_mset is _undef.Undef()
        if set_or_mset is _undef.Undef():
            return _undef.make_or_raise_undef(2)

    def _get_values_set(set_):
        result_counter = _collections.Counter()
        for elem in set_:
            result = op(elem)
            if result is not _undef.Undef():
                result_counter[result] += 1
        return result_counter

    def _get_values_multiset(mset):
        result_counter = _collections.Counter()
        for elem, multiplicity in mset.data.items():
            result = op(elem)
            if result is not _undef.Undef():
                result_counter[result] += multiplicity
        return result_counter

    get_values = _get_values_multiset if _multisets.is_member(
        set_or_mset) else _get_values_set

    return _mo.Multiset(get_values(set_or_mset))
Esempio n. 10
0
def binary_multi_extend(multiset1: 'P( M x N )',
                        multiset2: 'P( M x N )',
                        op,
                        _checked=True) -> 'P( M x N )':
    r"""Return the :term:`binary extension` of ``op`` from one :term:`algebra` to another algebra.

    For this extension, the elements of the extended algebra must be :term:`multiset`\s of the
    elements of the original algebra.

    :param multiset1: A :term:`multiset` with elements on which ``op`` operates.
    :param multiset2: A multiset with elements on which ``op`` operates.
    :param op: A :term:`binary operation` that operates on the elements of ``multiset1`` and
        ``multiset2``.
    :return: A multiset that consists of the defined results of ``op`` when executed on all
        combinations of the elements of ``multiset1`` and ``multiset2``, or `Undef()` if either
        set is not a :class:`~.Multiset`.
    """
    if _checked:
        if not _multisets.is_member(multiset1):
            return _undef.make_or_raise_undef2(multiset1)
        if not _multisets.is_member(multiset2):
            return _undef.make_or_raise_undef2(multiset2)
    else:
        assert _multisets.is_member_or_undef(multiset1)
        assert _multisets.is_member_or_undef(multiset2)
        if multiset1 is _undef.Undef() or multiset2 is _undef.Undef():
            return _undef.make_or_raise_undef(2)

    def _get_values(_set1, _set2):
        return_count = _collections.Counter()
        for elem1, multi1 in _set1.data.items():
            for elem2, multi2 in _set2.data.items():
                result = op(elem1, elem2)
                if result is not _undef.Undef():
                    return_count[result] += multi1 * multi2

        return return_count

    return _mo.Multiset(_get_values(multiset1, multiset2), direct_load=True)
Esempio n. 11
0
def multify(set_: 'P( M )', _checked=True) -> 'P( M x N )':
    """Return a :term:`multiset` based on ``set_`` where all multiples are set to 1."""
    if _checked:
        if not is_member(set_):
            return _undef.make_or_raise_undef2(set_)
    else:
        assert is_member_or_undef(set_)
        if set_ is _undef.Undef():
            return _undef.make_or_raise_undef(2)
    result = _mo.Multiset(set_.data, direct_load=True)
    if not result.is_empty:
        result.cache_multiclan(set_.cached_clan)
        if set_.cached_is_relation:
            # We don't yet have a concept of multirelations (multisets of couplets). This would be
            # handled here.
            pass
        elif set_.cached_is_clan:
            result.cache_absolute(set_.cached_absolute)
            result.cache_functional(set_.cached_functional)
            result.cache_right_functional(set_.cached_right_functional)
            result.cache_reflexive(set_.cached_reflexive)
            result.cache_symmetric(set_.cached_symmetric)
            result.cache_transitive(set_.cached_transitive)
            result.cache_regular(set_.cached_regular)
            result.cache_right_regular(set_.cached_right_regular)
        if set_.cached_is_not_relation and set_.cached_is_not_clan:
            # set_ is known to be a plain set.
            result.cache_absolute(set_.cached_absolute)
            result.cache_functional(_mo.CacheStatus.N_A)
            result.cache_right_functional(_mo.CacheStatus.N_A)
            result.cache_reflexive(_mo.CacheStatus.N_A)
            result.cache_symmetric(_mo.CacheStatus.N_A)
            result.cache_transitive(_mo.CacheStatus.N_A)
            result.cache_regular(_mo.CacheStatus.N_A)
            result.cache_right_regular(_mo.CacheStatus.N_A)
    return result
Esempio n. 12
0
def import_csv(csv_file_or_filepath,
               types: {} = None,
               skip_rows: int = 0,
               index_column: str = None,
               has_dup_rows: bool = False,
               columns: [] = None) -> 'PP( A x M )':
    r"""Import the file ``csv_file_or_filepath`` as CSV data and return a clan or multiclan.

    :param csv_file_or_filepath: The file path or file object (for example ``StringIO`` buffer) to
        import.
    :param types: (Optional) A dictionary of type conversions. The keys are the column names; the
        values are functors (or types) that receive the string from the CSV cell and return the
        value to be imported. Example: ``{'foo': int, 'bar': float}``. By default all values are
        interpreted as `string`\s.
    :param skip_rows: (Optional) A number of lines to skip (default 0). Some CSV files have a
        preamble that can be skipped with this option.
    :param index_column: (Optional) A name for an index column. (No index column is created if this
        argument is not specified.) The index starts with 0. (This option is not compatible with the
        ``has_dup_rows`` option.)
    :param has_dup_rows: (Optional) If ``True``, allow duplicate rows and return a multiclan
        instead of a clan. By default, the value is ``False`` and a clan is returned. (This option
        is not compatible with the option ``index_column``.)
    :param columns: (Optional) A list of column names. If present, this list is used as the
        sequence of columns (and all lines in the data are loaded). If missing, the first line of
        the data must be a header that contains the column names (and this header line is not
        loaded as data).
    :return: A :term:`clan` (if ``has_dup_rows is ``False`` or not provided) or a :term:`multiclan`
        (if ``has_dup_rows`` is ``True``).
    """
    if types is None:
        types = {}

    def _filter_row(row):
        """Remove missing and blank elements from the CSV row."""
        for key, val in row.items():
            if val is None or val == '':
                continue
            yield key, val

    _util.get_left_cached.left_cache = {}
    import_csv.regular = True  # Set to false if any row is missing one or more values

    assert ((index_column is not None) &
            (has_dup_rows is False)) or (index_column is None)

    def _import_csv(csv_file):
        for _ in range(0, skip_rows):
            next(csv_file)
        reader = _csv.DictReader(csv_file, fieldnames=columns)

        _index = 0
        for row in reader:
            filtered_row = {key: val for key, val in _filter_row(row)}
            if import_csv.regular and len(row) != len(filtered_row):
                import_csv.regular = False
            for key, val in types.items():
                if key in filtered_row:
                    filtered_row[key] = val(filtered_row[key])
            if index_column is not None:
                filtered_row[index_column] = _index
                _index += 1
            yield _mo.Set(
                (_mo.Couplet(left=_util.get_left_cached(left), right=_mo.Atom(right),
                direct_load=True) for left, right in filtered_row.items()), direct_load=True)\
                .cache_relation(_mo.CacheStatus.IS).cache_functional(_mo.CacheStatus.IS)

    if hasattr(csv_file_or_filepath, "readlines"):  # Support StringIO.
        if has_dup_rows:
            return _mo.Multiset(_import_csv(csv_file_or_filepath),
                                direct_load=True).cache_multiclan(
                                    _mo.CacheStatus.IS).cache_functional(
                                        _mo.CacheStatus.IS).cache_regular(
                                            _mo.CacheStatus.from_bool(
                                                import_csv.regular))
        else:
            return _mo.Set(_import_csv(csv_file_or_filepath), direct_load=True)\
                .cache_clan(_mo.CacheStatus.IS).cache_functional(_mo.CacheStatus.IS)\
                .cache_regular(_mo.CacheStatus.from_bool(import_csv.regular))
    else:
        with open(csv_file_or_filepath, encoding='utf-8',
                  errors='ignore') as file:
            if has_dup_rows:
                return _mo.Multiset(
                    _import_csv(file), direct_load=True).cache_multiclan(
                        _mo.CacheStatus.IS).cache_functional(
                            _mo.CacheStatus.IS).cache_regular(
                                _mo.CacheStatus.from_bool(import_csv.regular))
            else:
                return _mo.Set(_import_csv(file), direct_load=True)\
                    .cache_clan(_mo.CacheStatus.IS).cache_functional(_mo.CacheStatus.IS)\
                    .cache_regular(_mo.CacheStatus.from_bool(import_csv.regular))
Esempio n. 13
0
#
# algebraixlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along with algebraixlib.
# If not, see <http://www.gnu.org/licenses/>.
# --------------------------------------------------------------------------------------------------
import algebraixlib.algebras.multiclans as _multiclans
import algebraixlib.algebras.multisets as _multisets
import algebraixlib.mathobjects as _mo
from algebraixlib.util.latexprinter import math_object_to_latex as _math_object_to_latex

# --------------------------------------------------------------------------------------------------

ms_1 = _mo.Multiset({'a': 3, 'b': 3})
ms_2 = _mo.Multiset({'b': 2, 'c': 1})

# Multiset Union operation Example
simple_union = _multisets.union(ms_1, ms_2)

print(str(ms_1) + ' UNION ' + str(ms_2))
print('=> EVALUATES TO ' + str(simple_union))

ms_3 = _mo.Multiset({'a': 3, 'b': 3, 'c': 1})
if ms_3 == simple_union:
    print(
        "multiset's union takes the max of all the multiples merges the arguments into one "
        "result multiset.\n")

# Multiset Intersect Operation Example