Skip to content

monomial.py

from pymwp import Monomial

DELTA = Tuple[int, int] module-attribute

delta type is tuple of two int values.

Monomial

A monomial is a pair made of:

  1. scalar - a value in the semi-ring
  2. a sorted list of deltas, where an index occurs at most once.

Deltas are coded as pairs \((i,j)\) with:

  • \(i\) the value and
  • \(j\) the index in the domain (infinite product)

We will have that \((i,j)\) will be equal to the unit of the semi-ring iff the \(j^{th}\) input is equal to \(i\) (so, the \(j^{th}\) choice is \(i\)).

We will make the assumption that the deltas of delta is sorted and no two deltas can have the same index.

Source code in pymwp/monomial.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
class Monomial:
    """
    A monomial is a pair made of:

    1. `scalar` - a value in the semi-ring
    2. a sorted list of `deltas`, where an index occurs at most once.

    Deltas are coded as pairs $(i,j)$ with:

    - $i$ the value and
    - $j$ the index in the domain (infinite product)

    We will have that $(i,j)$ will be equal to the unit of the semi-ring
    iff the $j^{th}$ input is equal to $i$ (so, the $j^{th}$ choice is $i$).

    We will make the assumption that the deltas of delta is sorted
    and no two deltas can have the same index.
    """

    def __init__(self, scalar: str = UNIT_MWP,
                 deltas: Optional[Union[List[DELTA], DELTA]] = None,
                 *args: Optional[DELTA]):
        """Create a monomial.

        Example:


        Create a monomial

        ```python
        mono = Monomial()
        ```

        Create monomial with scalar $m$ explicitly.

        ```python
        mono = Monomial('m')
        ```

        Create monomial with scalar $w$ and two deltas

        ```python
        mono = Monomial('w', (0, 0), (1, 1))
        ```

        Arguments:
            scalar: monomial scalar
            deltas: list of deltas - either a syntactic list,
                or sequence of tuples that represent deltas.
        """
        self.deltas = []
        self.scalar = scalar

        if deltas is not None:
            if isinstance(deltas, list):
                Monomial.insert_deltas(self, deltas)
            if isinstance(deltas, tuple):
                delta_list = [deltas] + list(args if args else [])
                Monomial.insert_deltas(self, delta_list)

    def __str__(self) -> str:
        deltas = [".delta({0},{1})".format(*delta)
                  for delta in self.deltas]
        return self.scalar + ''.join(deltas)

    def __mul__(self, other) -> Monomial:
        return self.prod(other)

    @staticmethod
    def format(value: Union[str, Monomial, Tuple]) -> Monomial:
        if isinstance(value, Monomial):
            return value
        if isinstance(value, str):
            return Monomial(value)
        if isinstance(value, Tuple):
            return Monomial(*value)

    def contains(self, m: Monomial) -> bool:
        """check if all deltas of m are in deltas of self

        Arguments:
            m: a monomial to search for intersection

        Returns:
            False if one delta of m not in self
            True otherwise
        """
        for b in m.deltas:
            if b not in self.deltas:
                return False
        return True

    def inclusion(self, monomial: Monomial) -> SetInclusion:
        """gives info about inclusion of self monomial with monomial

        Arguments:
            monomial: a monomial to see inclusion

        Returns:
            CONTAINS if self contains monomial
            INCLUDED if self is included in monomial
            EMPTY none of them
        """
        # self contains monomial ?
        contains: bool = self.contains(monomial)

        summ = sum_mwp(self.scalar, monomial.scalar)
        # if self contains monomial and self.scalar >= monomial.scalar
        if contains and (monomial.scalar == summ):
            return SetInclusion.CONTAINS
        else:
            # self included in monomial and self.scalar <= monomial.scalar
            included: bool = monomial.contains(self)
            if included and (self.scalar == summ):
                return SetInclusion.INCLUDED
            else:
                return SetInclusion.EMPTY

    def prod(self, monomial: Monomial) -> Monomial:
        """
        prod operation combines two monomials where
        one is this monomial (self) and the second is
        provided as an argument.

        The attributes of the resulting monomial are
        determined as follows:

        - output scalar is a product of the input scalars
        - two lists of deltas are merged according
          to rules of insert_delta

        Arguments:
            monomial: the second monomial

        Returns:
            a new Monomial that is a product of two monomials
        """
        # make a copy of self
        mono_product = self.copy()

        # determine the new scalar
        mono_product.scalar = prod_mwp(self.scalar, monomial.scalar)

        # if scalar is 0, monomial cannot have deltas
        if mono_product.scalar == ZERO_MWP:
            mono_product.deltas = []

        # otherwise merge the two lists of deltas
        # result already contains deltas from "self"
        # so we are adding to it the deltas from
        # the second monomial passed in as argument
        elif monomial.deltas:
            # TODO here insert only those not contained ?
            Monomial.insert_deltas(mono_product, monomial.deltas)

        return mono_product

    def choice_scalar(self, *choices: int) -> Optional[str]:
        """Determine if given sequence of choices matches monomial.

        Arguments:
            choices: tuple of choices

        Returns:
            Monomial's scalar if structure matches choices and None otherwise.
        """
        for (i, j) in self.deltas:
            if not i == choices[j]:
                return None
        return self.scalar

    def copy(self) -> Monomial:
        """Make a deep copy of a monomial."""
        return Monomial(self.scalar, self.deltas[:])

    def show(self) -> None:
        """Display scalar and the list of deltas."""
        print(str(self))

    def to_dict(self) -> dict:
        """Get dictionary representation of a monomial."""
        return {
            "scalar": self.scalar,
            "deltas": self.deltas
        }

    @staticmethod
    def insert_deltas(monomial: Monomial, deltas: List[DELTA]) -> None:
        """Insert new deltas into monomial list of deltas.

        Arguments:

            monomial: the monomial into whose list of
                deltas values will be inserted

            deltas: list of deltas to insert into monomial
        """

        # Deltas are inserted one after the other so that
        # the resulting list is ordered
        for delta in deltas:
            monomial.deltas = Monomial.insert_delta(monomial.deltas, delta)

            # change the scalar to 0 because we have a null
            # monomial after insert
            if not monomial.deltas:
                monomial.scalar = ZERO_MWP
                # we can stop inserting if this happens
                break

    @staticmethod
    def insert_delta(sorted_deltas: List[DELTA], delta: DELTA) -> List[DELTA]:
        """
        Takes as input a _sorted_ list of deltas and a delta.

        Check if two deltas have the same index:

        If they do, and if they:

        - disagree on the value expected, returns `[]` (empty list)
        - agree on the value expected, returns the original deltas

        If they don't:
         add the new delta in the deltas "at the right position".

        Arguments:
            sorted_deltas: list of deltas where to perform insert
            delta: the delta value to be inserted

        Returns:
            updated list of deltas.
        """

        # insert position index
        i = 0

        # iterate existing deltas and look for
        # where to insert the new value
        while i < len(sorted_deltas):

            # if delta to insert has higher index
            # go to next one
            if sorted_deltas[i][1] < delta[1]:
                i = i + 1

            # if delta to insert matches existing index
            elif sorted_deltas[i][1] == delta[1]:

                # when delta to insert is already in the
                # list, return the original list without
                # performing insert
                if sorted_deltas[i][0] == delta[0]:
                    return sorted_deltas

                # If the delta disagrees with the choices
                # previously stored, we simply return the
                # empty list: we will never be able to
                # accommodate both the requirement of
                # the existing list and of the new delta.
                return []

            else:
                break

        # perform insert at appropriate index
        sorted_deltas.insert(i, delta)
        return sorted_deltas

__init__(scalar=UNIT_MWP, deltas=None, *args)

Create a monomial.

Example:

Create a monomial

mono = Monomial()

Create monomial with scalar \(m\) explicitly.

mono = Monomial('m')

Create monomial with scalar \(w\) and two deltas

mono = Monomial('w', (0, 0), (1, 1))

Parameters:

Name Type Description Default
scalar str

monomial scalar

UNIT_MWP
deltas Optional[Union[List[DELTA], DELTA]]

list of deltas - either a syntactic list, or sequence of tuples that represent deltas.

None
Source code in pymwp/monomial.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def __init__(self, scalar: str = UNIT_MWP,
             deltas: Optional[Union[List[DELTA], DELTA]] = None,
             *args: Optional[DELTA]):
    """Create a monomial.

    Example:


    Create a monomial

    ```python
    mono = Monomial()
    ```

    Create monomial with scalar $m$ explicitly.

    ```python
    mono = Monomial('m')
    ```

    Create monomial with scalar $w$ and two deltas

    ```python
    mono = Monomial('w', (0, 0), (1, 1))
    ```

    Arguments:
        scalar: monomial scalar
        deltas: list of deltas - either a syntactic list,
            or sequence of tuples that represent deltas.
    """
    self.deltas = []
    self.scalar = scalar

    if deltas is not None:
        if isinstance(deltas, list):
            Monomial.insert_deltas(self, deltas)
        if isinstance(deltas, tuple):
            delta_list = [deltas] + list(args if args else [])
            Monomial.insert_deltas(self, delta_list)

choice_scalar(*choices)

Determine if given sequence of choices matches monomial.

Parameters:

Name Type Description Default
choices int

tuple of choices

()

Returns:

Type Description
Optional[str]

Monomial's scalar if structure matches choices and None otherwise.

Source code in pymwp/monomial.py
170
171
172
173
174
175
176
177
178
179
180
181
182
def choice_scalar(self, *choices: int) -> Optional[str]:
    """Determine if given sequence of choices matches monomial.

    Arguments:
        choices: tuple of choices

    Returns:
        Monomial's scalar if structure matches choices and None otherwise.
    """
    for (i, j) in self.deltas:
        if not i == choices[j]:
            return None
    return self.scalar

contains(m)

check if all deltas of m are in deltas of self

Parameters:

Name Type Description Default
m Monomial

a monomial to search for intersection

required

Returns:

Type Description
bool

False if one delta of m not in self

bool

True otherwise

Source code in pymwp/monomial.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def contains(self, m: Monomial) -> bool:
    """check if all deltas of m are in deltas of self

    Arguments:
        m: a monomial to search for intersection

    Returns:
        False if one delta of m not in self
        True otherwise
    """
    for b in m.deltas:
        if b not in self.deltas:
            return False
    return True

copy()

Make a deep copy of a monomial.

Source code in pymwp/monomial.py
184
185
186
def copy(self) -> Monomial:
    """Make a deep copy of a monomial."""
    return Monomial(self.scalar, self.deltas[:])

inclusion(monomial)

gives info about inclusion of self monomial with monomial

Parameters:

Name Type Description Default
monomial Monomial

a monomial to see inclusion

required

Returns:

Type Description
SetInclusion

CONTAINS if self contains monomial

SetInclusion

INCLUDED if self is included in monomial

SetInclusion

EMPTY none of them

Source code in pymwp/monomial.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def inclusion(self, monomial: Monomial) -> SetInclusion:
    """gives info about inclusion of self monomial with monomial

    Arguments:
        monomial: a monomial to see inclusion

    Returns:
        CONTAINS if self contains monomial
        INCLUDED if self is included in monomial
        EMPTY none of them
    """
    # self contains monomial ?
    contains: bool = self.contains(monomial)

    summ = sum_mwp(self.scalar, monomial.scalar)
    # if self contains monomial and self.scalar >= monomial.scalar
    if contains and (monomial.scalar == summ):
        return SetInclusion.CONTAINS
    else:
        # self included in monomial and self.scalar <= monomial.scalar
        included: bool = monomial.contains(self)
        if included and (self.scalar == summ):
            return SetInclusion.INCLUDED
        else:
            return SetInclusion.EMPTY

insert_delta(sorted_deltas, delta) staticmethod

Takes as input a sorted list of deltas and a delta.

Check if two deltas have the same index:

If they do, and if they:

  • disagree on the value expected, returns [] (empty list)
  • agree on the value expected, returns the original deltas

If they don't: add the new delta in the deltas "at the right position".

Parameters:

Name Type Description Default
sorted_deltas List[DELTA]

list of deltas where to perform insert

required
delta DELTA

the delta value to be inserted

required

Returns:

Type Description
List[DELTA]

updated list of deltas.

Source code in pymwp/monomial.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
@staticmethod
def insert_delta(sorted_deltas: List[DELTA], delta: DELTA) -> List[DELTA]:
    """
    Takes as input a _sorted_ list of deltas and a delta.

    Check if two deltas have the same index:

    If they do, and if they:

    - disagree on the value expected, returns `[]` (empty list)
    - agree on the value expected, returns the original deltas

    If they don't:
     add the new delta in the deltas "at the right position".

    Arguments:
        sorted_deltas: list of deltas where to perform insert
        delta: the delta value to be inserted

    Returns:
        updated list of deltas.
    """

    # insert position index
    i = 0

    # iterate existing deltas and look for
    # where to insert the new value
    while i < len(sorted_deltas):

        # if delta to insert has higher index
        # go to next one
        if sorted_deltas[i][1] < delta[1]:
            i = i + 1

        # if delta to insert matches existing index
        elif sorted_deltas[i][1] == delta[1]:

            # when delta to insert is already in the
            # list, return the original list without
            # performing insert
            if sorted_deltas[i][0] == delta[0]:
                return sorted_deltas

            # If the delta disagrees with the choices
            # previously stored, we simply return the
            # empty list: we will never be able to
            # accommodate both the requirement of
            # the existing list and of the new delta.
            return []

        else:
            break

    # perform insert at appropriate index
    sorted_deltas.insert(i, delta)
    return sorted_deltas

insert_deltas(monomial, deltas) staticmethod

Insert new deltas into monomial list of deltas.

Arguments:

monomial: the monomial into whose list of
    deltas values will be inserted

deltas: list of deltas to insert into monomial
Source code in pymwp/monomial.py
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
@staticmethod
def insert_deltas(monomial: Monomial, deltas: List[DELTA]) -> None:
    """Insert new deltas into monomial list of deltas.

    Arguments:

        monomial: the monomial into whose list of
            deltas values will be inserted

        deltas: list of deltas to insert into monomial
    """

    # Deltas are inserted one after the other so that
    # the resulting list is ordered
    for delta in deltas:
        monomial.deltas = Monomial.insert_delta(monomial.deltas, delta)

        # change the scalar to 0 because we have a null
        # monomial after insert
        if not monomial.deltas:
            monomial.scalar = ZERO_MWP
            # we can stop inserting if this happens
            break

prod(monomial)

prod operation combines two monomials where one is this monomial (self) and the second is provided as an argument.

The attributes of the resulting monomial are determined as follows:

  • output scalar is a product of the input scalars
  • two lists of deltas are merged according to rules of insert_delta

Parameters:

Name Type Description Default
monomial Monomial

the second monomial

required

Returns:

Type Description
Monomial

a new Monomial that is a product of two monomials

Source code in pymwp/monomial.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def prod(self, monomial: Monomial) -> Monomial:
    """
    prod operation combines two monomials where
    one is this monomial (self) and the second is
    provided as an argument.

    The attributes of the resulting monomial are
    determined as follows:

    - output scalar is a product of the input scalars
    - two lists of deltas are merged according
      to rules of insert_delta

    Arguments:
        monomial: the second monomial

    Returns:
        a new Monomial that is a product of two monomials
    """
    # make a copy of self
    mono_product = self.copy()

    # determine the new scalar
    mono_product.scalar = prod_mwp(self.scalar, monomial.scalar)

    # if scalar is 0, monomial cannot have deltas
    if mono_product.scalar == ZERO_MWP:
        mono_product.deltas = []

    # otherwise merge the two lists of deltas
    # result already contains deltas from "self"
    # so we are adding to it the deltas from
    # the second monomial passed in as argument
    elif monomial.deltas:
        # TODO here insert only those not contained ?
        Monomial.insert_deltas(mono_product, monomial.deltas)

    return mono_product

show()

Display scalar and the list of deltas.

Source code in pymwp/monomial.py
188
189
190
def show(self) -> None:
    """Display scalar and the list of deltas."""
    print(str(self))

to_dict()

Get dictionary representation of a monomial.

Source code in pymwp/monomial.py
192
193
194
195
196
197
def to_dict(self) -> dict:
    """Get dictionary representation of a monomial."""
    return {
        "scalar": self.scalar,
        "deltas": self.deltas
    }