chromatic-matroids 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ chromatic_matroids/dist/*
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: chromatic_matroids
3
+ Version: 0.0.1
4
+ Summary: A package that exposes some matroid operation and creations
5
+ Project-URL: Homepage, https://github.com/raulpenaguiao/chromatic-matroids/chromatic-matroids
6
+ Project-URL: Issues, https://github.com/raulpenaguiao/chromatic-matroids/chromatic-matroids/issues
7
+ Author: Sophie Rehberg
8
+ Author-email: Raul Penaguiao <raul.penaguiao@proton.me>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Matroid Package
17
+
18
+
19
+ This is a simple matroid package that contains constructor functions for basic combinatorial structures like set compositions, complext structures like matroids and algebraic structure like word quasisymmetric functions.
20
+ This builds up for the construction of chromatic invariants on matroids.
21
+
22
+ This abstracts away all the intricacies of matroid operations in order to compute the chromatic invariants.
23
+
24
+
25
+ ## Packages
26
+
27
+ ### Compositions
28
+
29
+ This package implements a construction of compositions:
30
+
31
+ ```
32
+ print("Composition Construction")
33
+ comp1 = Composition([1, 2, 1])
34
+ comp2 = Composition([2, 1])
35
+ print(f"Example 5: Basic compositions: {comp1}, {comp2}")
36
+ print("\n")
37
+
38
+ print("Composition Operations")
39
+ print(f"Rest of {comp1}: {comp1.rest()}")
40
+ print(f"Prepending 3 to {comp2}: {comp2.prepend(3)}")
41
+ print("\n")
42
+
43
+ print("Generate All Compositions")
44
+ comps3 = Composition.generate_all_composition(3)
45
+ print(f"All compositions of 3: {comps3}\n")
46
+ print("\n")
47
+ ```
48
+
49
+
50
+ ### Set compositions
51
+
52
+ This package implements a construction of set compositions.
53
+ For a construction example, run the following:
54
+
55
+ ```
56
+ print("Example 13: SetComposition Operations")
57
+ set_comp1 = SetComposition([[1, 2], [3, 4], [5]])
58
+ set_comp2 = SetComposition([[1], [2, 3]])
59
+ print(f"\nSet Compositions: {set_comp1}, {set_comp2}")
60
+ ```
61
+
62
+
63
+ ### Quasi-symmetric functions
64
+
65
+ This package implements a construction of quasi-symmetric functions.
66
+ For a construction example, run the following:
67
+ ```
68
+ print("Construct QSymFunction from a dictionary of monomial bases")
69
+ qsym_from_dict = QSymFunction(monomial_basis={"(1,2,1)": 2, "(2,1)": -1})
70
+ print("QSymFunction from dictionary:")
71
+ print(f"coefficients: {qsym_from_dict.coefficients}")
72
+ ```
73
+
74
+ ### Word quasi-symmetric functions
75
+
76
+ This package implements a construction of word quasi-symmetric functions.
77
+ For a construction example, run the following:
78
+ ```
79
+ print("Construct NCQSymFunctions from a dictionary of monomial bases")
80
+ nc_f = NCQSymFunction(monomial_basis=set_comp1)
81
+ nc_g = NCQSymFunction(monomial_basis=set_comp2)
82
+ nc_sum = nc_f + nc_g
83
+ print("Sum of NCQSymFunctions:")
84
+ print(f"nc_f: {nc_f.coefficients}")
85
+ print(f"nc_g: {nc_g.coefficients}")
86
+ print(f"nc_f + nc_g: {nc_sum.coefficients}")
87
+ ```
88
+
89
+ ### Graphs
90
+ This package implements a construction of graphs from edge list.
91
+
92
+ ### Matroids
93
+
94
+ This package implements a construction of matroids from base list.
95
+ It also implements construction of *Schubert matroids*, *graphical matroids*, *uniform matroids*, and *nested matroids.
96
+
97
+
98
+ ### Chromatic functions on matroids
99
+
100
+ This package implements a construction of chromatic invariants on matroids.
101
+
102
+
103
+
104
+ # To do
105
+
106
+ ## Test cases
107
+
108
+ We are still building up our unit test library
109
+
110
+ ## Efficiency
111
+
112
+ We are improving the construction of some methods related to computing stability of some set compositions with memorization.
@@ -0,0 +1,97 @@
1
+ # Matroid Package
2
+
3
+
4
+ This is a simple matroid package that contains constructor functions for basic combinatorial structures like set compositions, complext structures like matroids and algebraic structure like word quasisymmetric functions.
5
+ This builds up for the construction of chromatic invariants on matroids.
6
+
7
+ This abstracts away all the intricacies of matroid operations in order to compute the chromatic invariants.
8
+
9
+
10
+ ## Packages
11
+
12
+ ### Compositions
13
+
14
+ This package implements a construction of compositions:
15
+
16
+ ```
17
+ print("Composition Construction")
18
+ comp1 = Composition([1, 2, 1])
19
+ comp2 = Composition([2, 1])
20
+ print(f"Example 5: Basic compositions: {comp1}, {comp2}")
21
+ print("\n")
22
+
23
+ print("Composition Operations")
24
+ print(f"Rest of {comp1}: {comp1.rest()}")
25
+ print(f"Prepending 3 to {comp2}: {comp2.prepend(3)}")
26
+ print("\n")
27
+
28
+ print("Generate All Compositions")
29
+ comps3 = Composition.generate_all_composition(3)
30
+ print(f"All compositions of 3: {comps3}\n")
31
+ print("\n")
32
+ ```
33
+
34
+
35
+ ### Set compositions
36
+
37
+ This package implements a construction of set compositions.
38
+ For a construction example, run the following:
39
+
40
+ ```
41
+ print("Example 13: SetComposition Operations")
42
+ set_comp1 = SetComposition([[1, 2], [3, 4], [5]])
43
+ set_comp2 = SetComposition([[1], [2, 3]])
44
+ print(f"\nSet Compositions: {set_comp1}, {set_comp2}")
45
+ ```
46
+
47
+
48
+ ### Quasi-symmetric functions
49
+
50
+ This package implements a construction of quasi-symmetric functions.
51
+ For a construction example, run the following:
52
+ ```
53
+ print("Construct QSymFunction from a dictionary of monomial bases")
54
+ qsym_from_dict = QSymFunction(monomial_basis={"(1,2,1)": 2, "(2,1)": -1})
55
+ print("QSymFunction from dictionary:")
56
+ print(f"coefficients: {qsym_from_dict.coefficients}")
57
+ ```
58
+
59
+ ### Word quasi-symmetric functions
60
+
61
+ This package implements a construction of word quasi-symmetric functions.
62
+ For a construction example, run the following:
63
+ ```
64
+ print("Construct NCQSymFunctions from a dictionary of monomial bases")
65
+ nc_f = NCQSymFunction(monomial_basis=set_comp1)
66
+ nc_g = NCQSymFunction(monomial_basis=set_comp2)
67
+ nc_sum = nc_f + nc_g
68
+ print("Sum of NCQSymFunctions:")
69
+ print(f"nc_f: {nc_f.coefficients}")
70
+ print(f"nc_g: {nc_g.coefficients}")
71
+ print(f"nc_f + nc_g: {nc_sum.coefficients}")
72
+ ```
73
+
74
+ ### Graphs
75
+ This package implements a construction of graphs from edge list.
76
+
77
+ ### Matroids
78
+
79
+ This package implements a construction of matroids from base list.
80
+ It also implements construction of *Schubert matroids*, *graphical matroids*, *uniform matroids*, and *nested matroids.
81
+
82
+
83
+ ### Chromatic functions on matroids
84
+
85
+ This package implements a construction of chromatic invariants on matroids.
86
+
87
+
88
+
89
+ # To do
90
+
91
+ ## Test cases
92
+
93
+ We are still building up our unit test library
94
+
95
+ ## Efficiency
96
+
97
+ We are improving the construction of some methods related to computing stability of some set compositions with memorization.
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "chromatic_matroids"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name="Raul Penaguiao", email="raul.penaguiao@proton.me" },
10
+ { name="Sophie Rehberg", email="" },
11
+ ]
12
+ description = "A package that exposes some matroid operation and creations"
13
+ readme = "README.md"
14
+ requires-python = ">=3.8"
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ license = "MIT"
20
+ license-files = ["LICENSE"]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/raulpenaguiao/chromatic-matroids/chromatic-matroids"
24
+ Issues = "https://github.com/raulpenaguiao/chromatic-matroids/chromatic-matroids/issues"
@@ -0,0 +1,55 @@
1
+ # matroid_chromatic/chromatic.py
2
+ from typing import Dict
3
+ from matroid_chromatic import Matroid
4
+
5
+
6
+
7
+ def compute_chromatic_noncommutative_qsym_function(matroid: Matroid) -> dict:
8
+ """
9
+ Compute the non commutative qsym function as a dictionary that matches a
10
+ """
11
+
12
+
13
+
14
+ def compute_chromatic_polynomial(matroid: Matroid) -> list:
15
+ """
16
+ Compute the chromatic polynomial as a list of coefficients.
17
+
18
+ Args:
19
+ matroid: The matroid
20
+
21
+ Returns:
22
+ Value of chromatic polynomial at q
23
+ """
24
+ def mobius_function(X: frozenset, Y: frozenset) -> int:
25
+ """Compute the Möbius function value."""
26
+ if X == Y:
27
+ return 1
28
+ if not X.issubset(Y):
29
+ return 0
30
+
31
+ result = 0
32
+ for Z in range_sets[len(X):len(Y)]:
33
+ if X.issubset(Z) and Z.issubset(Y):
34
+ result -= mobius_function(X, Z)
35
+ return result
36
+
37
+ # Generate all sets between empty set and ground set
38
+ range_sets = []
39
+ for i in range(len(matroid.ground_set) + 1):
40
+ current_level = set()
41
+ for ind_set in matroid.independent_sets():
42
+ if len(ind_set) == i:
43
+ current_level.add(ind_set)
44
+ range_sets.append(current_level)
45
+
46
+ # Compute chromatic polynomial using Möbius inversion
47
+ result = [0 for _ in range(len(matroid.ground_set) + 1)]
48
+ empty_set = frozenset()
49
+ ground_set = frozenset(matroid.ground_set)
50
+
51
+ for X in matroid.independent_sets():
52
+ coeff = mobius_function(empty_set, X)
53
+ result[len(X)] += coeff
54
+
55
+ return result
@@ -0,0 +1,27 @@
1
+ # matroid_chromatic/chromatic_statistics_matorids.py
2
+ from matroid_chromatic import Matroid
3
+ from matroid_chromatic import SetComposition
4
+ from matroid_chromatic import Composition
5
+ from matroid_chromatic import QSymFunction
6
+ from matroid_chromatic import NCQSymFunction
7
+ from matroid_chromatic import stable_matroids_setcompositions
8
+
9
+ def chromatic_quasisymmetric_function(matroid: Matroid) -> QSymFunction:
10
+ """
11
+ Compute the chromatic quasisymmetric function of a matroid
12
+ """
13
+ return NCQSymFunction.comu(chromatic_non_commutative_quasisymmetric_function(matroid))
14
+
15
+
16
+ def chromatic_non_commutative_quasisymmetric_function(matroid: Matroid) -> NCQSymFunction:
17
+ """
18
+ Compute the chromatic non-commutative quasisymmetric function of a matroid
19
+ """
20
+ ground_list = list(matroid.ground_set)
21
+ relabeling_map = {i+1: ground_list[i] for i in range(len(ground_list))}
22
+ all_set_compositions = [opi.relabel(relabeling_map) for opi in SetComposition.generate_all_setcompositions(len(ground_list))]
23
+ coeffs = {str(opi): 1 for opi in all_set_compositions
24
+ if stable_matroids_setcompositions(matroid, opi)}
25
+ return NCQSymFunction(monomial_basis=coeffs)
26
+
27
+
@@ -0,0 +1,229 @@
1
+ # matroid_chromatic/compositions.py
2
+ from typing import Set, List, Tuple
3
+
4
+ class Composition:
5
+ """
6
+ A class representing compositions of integers as an imutable class. This means no methods change self.
7
+ A composition of n is a way of writing n as a sum of positive integers.
8
+ For example, [2,1,3] is a composition of 6.
9
+
10
+ This class implements quasi-shuffles of compositions
11
+ """
12
+ # Class variables for memoization of quasi-shuffle computations
13
+ _PREGEN = 4
14
+ _all_generated_compositions_size = 0 # Limit for precomputation
15
+ _all_generated_compositions_list = [] # Cache for precomputed results
16
+ _qshuffle_precomputation_dictionary = {} # Cache for precomputed results
17
+
18
+ def __init__(self, *args, **kwargs):
19
+ """
20
+ Initialize a composition of integers
21
+
22
+ Args:
23
+ *args: Variable length argument list. Can be a list or a tuple of positive integers
24
+ **kwargs: Arbitrary keyword arguments (reserved for future use)
25
+
26
+ Raises:
27
+ TypeError: If any argument is not an integer
28
+ ValueError: If any integer is not positive
29
+ """
30
+ # Check if args is a single list/tuple
31
+ if len(args) == 0:#Composition() = [] the unique composition of 0
32
+ self.parts = []
33
+ elif len(args) == 1:
34
+ if isinstance(args[0], (list, tuple)):
35
+ self.parts = list(args[0]) # Convert to list to ensure mutability
36
+ elif isinstance(args[0], str):
37
+ if args[0] == "()":
38
+ self.parts = []#Composition('()') = [] the unique composition of 0
39
+ else:
40
+ try:
41
+ self.parts = [int(i) for i in args[0][1:-1].split(",")]#Composition('(2,1,3)') = [2,1,3]
42
+ except:
43
+ raise Exception(f"Composition input malformed, expected a string of the form '(2,1,3)', got {args[0]}")
44
+ else:
45
+ raise Exception("")
46
+ else:
47
+ raise Exception("")
48
+ # Validate all arguments are positive integers
49
+ for part in self.parts:
50
+ if not isinstance(part, int):
51
+ raise TypeError(f"All parts must be integers, got {type(part)}")
52
+ if part <= 0:
53
+ raise ValueError(f"All parts must be positive integers, got {part}")
54
+
55
+ self.nparts = len(self.parts) # Number of parts in the composition
56
+ self.n = sum(self.parts) # Total sum of all parts
57
+
58
+ def __str__(self) -> str:
59
+ """
60
+ String representation of the composition using | as separator
61
+
62
+ Returns:
63
+ str: Composition parts joined by '|' character
64
+ """
65
+ return "(" + ",".join([str(i) for i in self.parts]) + ")"
66
+
67
+ def __repr__(self) -> str:
68
+ return self.__str__()
69
+
70
+ def __eq__(self, other) -> bool:
71
+ if not self.n == other.n:
72
+ return False
73
+ if not self.nparts == other.nparts:
74
+ return False
75
+ for a, b in zip(self.parts, other.parts):
76
+ if not a == b:
77
+ return False
78
+ return True
79
+
80
+ def rest(self) -> 'Composition':
81
+ """
82
+ Returns a new Composition object containing all but the first part
83
+ of this composition.
84
+
85
+ Returns:
86
+ Composition: A new composition without the first part
87
+ """
88
+ if len(self.parts) == 0:
89
+ raise Exception("Empty composition cannot be rest-ed")
90
+ return Composition(self.parts[1:])
91
+
92
+ def prepend(self, a: int) -> 'Composition':
93
+ """
94
+ Computes a new composition with a prepend element
95
+ Does not change self
96
+
97
+ Args:
98
+ self (Composition): a composition
99
+ a (int): term to prepend
100
+
101
+ Returns:
102
+ Composition: A new composition with a prepend element
103
+ """
104
+ return Composition([a] + self.parts)
105
+
106
+ @staticmethod
107
+ def generate_all_composition(n: int) -> list['Composition']:
108
+ """
109
+ Computes all compositions of a given size iteratively with memoization
110
+
111
+ Args:
112
+ n (int): The positive integer to generate compositions for
113
+
114
+ Returns:
115
+ list: A list of all compositions of n, ordered lexicographically
116
+ For example, generate_all_composition(3) returns:
117
+ [[3], [2,1], [1,2], [1,1,1]]
118
+
119
+ Note:
120
+ Uses memoization to avoid recomputing previously generated compositions.
121
+ Results are stored in _all_generated_compositions_list for future use.
122
+ """
123
+ # Check if these compositions were already generated
124
+ if n < Composition._all_generated_compositions_size:
125
+ if n < 0:
126
+ return [] # No compositions for negative numbers
127
+ return Composition._all_generated_compositions_list[n]
128
+
129
+ # Start with the trivial composition [n]
130
+ answer = [Composition([n])]
131
+
132
+ # Generate all compositions by breaking off initial parts
133
+ for k in range(1, n):
134
+ # For each k from 1 to n-1:
135
+ # Take each composition of k and prepend (n-k) to it
136
+ # This systematically generates all possible compositions
137
+ smaller_compositions = Composition.generate_all_composition(k)
138
+ for alpha in smaller_compositions:
139
+ answer.append(alpha.prepend(n-k))
140
+
141
+ # Update the memoization cache
142
+ Composition._all_generated_compositions_size = n + 1
143
+ Composition._all_generated_compositions_list += [answer]
144
+ return answer
145
+
146
+ @staticmethod
147
+ def quasi_shuffles(q: 'Composition', t: 'Composition') -> dict[str:int]:
148
+ """
149
+ Compute all possible quasi-shuffles of two compositions.
150
+ A quasi-shuffle combines two compositions allowing both interleaving and addition
151
+ of corresponding terms.
152
+
153
+ For example, quasi-shuffling [1,2] and [3,1] could give:
154
+ - [1,3,2,1] (interleaving)
155
+ - [4,2,1] (adding first terms)
156
+ - [1,5,1] (adding first and second terms)
157
+ And other combinations...
158
+
159
+ Args:
160
+ q (Composition): First composition
161
+ t (Composition): Second composition
162
+
163
+ Returns:
164
+ dict: Dictionary mapping resulting compositions to their coefficients.
165
+ The coefficients track how many ways that composition can be formed.
166
+
167
+ Note:
168
+ Uses the recursive formula:
169
+ qs(a·q, b·t) = a·qs(q, bt) + b·qs(aq, t) + (a+b)·qs(q, t)
170
+ where a·q means composition q with 'a' prepended
171
+ """
172
+ # Check memoization cache
173
+ if str(q) in Composition._qshuffle_precomputation_dictionary:
174
+ if str(t) in Composition._qshuffle_precomputation_dictionary[str(q)]:
175
+ return Composition._qshuffle_precomputation_dictionary[str(q)][str(t)]
176
+
177
+ # Base cases: if either composition is empty, return the other
178
+ if q.n == 0:
179
+ return {str(t): 1}
180
+ if t.n == 0:
181
+ return {str(q): 1}
182
+
183
+ # Get the first terms and rest of each composition
184
+ a = q.parts[0]
185
+ b = t.parts[0]
186
+ qrest = q.rest()
187
+ trest = t.rest()
188
+
189
+ answer = {}
190
+
191
+ # Case 1: Take 'a' from first composition > a·qs(q, bt)
192
+ qsh1 = Composition.quasi_shuffles(qrest, t)
193
+ for alphas in qsh1:
194
+ newqs = str(Composition(alphas).prepend(a))
195
+ if not(newqs in answer):
196
+ answer[newqs] = 0
197
+ answer[newqs] += qsh1[alphas]
198
+
199
+ # Case 2: Take 'b' from second composition > + b·qs(aq, t)
200
+ qsh2 = Composition.quasi_shuffles(q, trest)
201
+ for alphas in qsh2:
202
+ newqs = str(Composition(alphas).prepend(b))
203
+ if not(newqs in answer):
204
+ answer[newqs] = 0
205
+ answer[newqs] += qsh2[alphas]
206
+
207
+ # Case 3: Take both first terms and add them together > (a+b)·qs(q, t)
208
+ qsh3 = Composition.quasi_shuffles(qrest, trest)
209
+ for alphas in qsh3:
210
+ newqs = str(Composition(alphas).prepend(a + b))
211
+ if not(newqs in answer):
212
+ answer[newqs] = 0
213
+ answer[newqs] += qsh3[alphas]
214
+
215
+
216
+ if not str(q) in Composition._qshuffle_precomputation_dictionary:
217
+ Composition._qshuffle_precomputation_dictionary[str(q)] = {}
218
+ Composition._qshuffle_precomputation_dictionary[str(q)][str(t)] = answer
219
+ return answer
220
+
221
+
222
+ Composition._all_generated_compositions_list = [[Composition()]]
223
+ # Pregenerate all compositions and qshuffles up to size PREGEN
224
+ Composition.generate_all_composition(Composition._PREGEN)
225
+ for comp_list1 in Composition._all_generated_compositions_list:
226
+ for comp1 in comp_list1:
227
+ for comp_list2 in Composition._all_generated_compositions_list:
228
+ for comp2 in comp_list2:
229
+ Composition.quasi_shuffles(comp1, comp2)