Skip to content

Commit 145176d

Browse files
j2kunftynse
andauthored
polynomial: Add basic ops (#89525)
Adds a few basic polynomial ops. - add, sub, mul - mul_scalar - leading_term, monomial_mul, monomial (useful for lowering `mul` to standard MLIR) - from_tensor, to_tensor, constant --------- Co-authored-by: Jeremy Kun <[email protected]> Co-authored-by: Oleksandr "Alex" Zinenko <[email protected]>
1 parent aa596fa commit 145176d

File tree

7 files changed

+534
-20
lines changed

7 files changed

+534
-20
lines changed

mlir/include/mlir/Dialect/Polynomial/IR/Polynomial.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ class Monomial {
5151
return (exponent.ult(other.exponent));
5252
}
5353

54-
// Prints polynomial to 'os'.
55-
void print(raw_ostream &os) const;
56-
5754
friend ::llvm::hash_code hash_value(const Monomial &arg);
5855

5956
public:
@@ -102,6 +99,8 @@ class Polynomial {
10299

103100
unsigned getDegree() const;
104101

102+
ArrayRef<Monomial> getTerms() const { return terms; }
103+
105104
friend ::llvm::hash_code hash_value(const Polynomial &arg);
106105

107106
private:

mlir/include/mlir/Dialect/Polynomial/IR/Polynomial.td

Lines changed: 281 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,18 @@ def Polynomial_Dialect : Dialect {
3535

3636
```mlir
3737
// A constant polynomial in a ring with i32 coefficients and no polynomial modulus
38-
#ring = #polynomial.ring<ctype=i32>
38+
#ring = #polynomial.ring<coefficientType=i32>
3939
%a = polynomial.constant <1 + x**2 - 3x**3> : polynomial.polynomial<#ring>
4040

4141
// A constant polynomial in a ring with i32 coefficients, modulo (x^1024 + 1)
4242
#modulus = #polynomial.polynomial<1 + x**1024>
43-
#ring = #polynomial.ring<ctype=i32, ideal=#modulus>
43+
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#modulus>
4444
%a = polynomial.constant <1 + x**2 - 3x**3> : polynomial.polynomial<#ring>
4545

4646
// A constant polynomial in a ring with i32 coefficients, with a polynomial
4747
// modulus of (x^1024 + 1) and a coefficient modulus of 17.
4848
#modulus = #polynomial.polynomial<1 + x**1024>
49-
#ring = #polynomial.ring<ctype=i32, cmod=17, ideal=#modulus>
49+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=17, polynomialModulus=#modulus>
5050
%a = polynomial.constant <1 + x**2 - 3x**3> : polynomial.polynomial<#ring>
5151
```
5252
}];
@@ -63,7 +63,21 @@ class Polynomial_Attr<string name, string attrMnemonic, list<Trait> traits = []>
6363
def Polynomial_PolynomialAttr : Polynomial_Attr<"Polynomial", "polynomial"> {
6464
let summary = "An attribute containing a single-variable polynomial.";
6565
let description = [{
66-
#poly = #polynomial.poly<x**1024 + 1>
66+
A polynomial attribute represents a single-variable polynomial, which
67+
is used to define the modulus of a `RingAttr`, as well as to define constants
68+
and perform constant folding for `polynomial` ops.
69+
70+
The polynomial must be expressed as a list of monomial terms, with addition
71+
or subtraction between them. The choice of variable name is arbitrary, but
72+
must be consistent across all the monomials used to define a single
73+
attribute. The order of monomial terms is arbitrary, each monomial degree
74+
must occur at most once.
75+
76+
Example:
77+
78+
```mlir
79+
#poly = #polynomial.polynomial<x**1024 + 1>
80+
```
6781
}];
6882
let parameters = (ins "Polynomial":$polynomial);
6983
let hasCustomAssemblyFormat = 1;
@@ -79,10 +93,10 @@ def Polynomial_RingAttr : Polynomial_Attr<"Ring", "ring"> {
7993
integral, whose coefficients are taken modulo some statically known modulus
8094
(`coefficientModulus`).
8195

82-
Additionally, a polynomial ring can specify an _ideal_, which converts
96+
Additionally, a polynomial ring can specify a _polynomialModulus_, which converts
8397
polynomial arithmetic to the analogue of modular integer arithmetic, where
8498
each polynomial is represented as its remainder when dividing by the
85-
modulus. For single-variable polynomials, an "ideal" is always specificed
99+
modulus. For single-variable polynomials, an "polynomialModulus" is always specificed
86100
via a single polynomial, which we call `polynomialModulus`.
87101

88102
An expressive example is polynomials with i32 coefficients, whose
@@ -122,32 +136,284 @@ class Polynomial_Type<string name, string typeMnemonic>
122136

123137
def Polynomial_PolynomialType : Polynomial_Type<"Polynomial", "polynomial"> {
124138
let summary = "An element of a polynomial ring.";
125-
126139
let description = [{
127140
A type for polynomials in a polynomial quotient ring.
128141
}];
129-
130142
let parameters = (ins Polynomial_RingAttr:$ring);
131143
let assemblyFormat = "`<` $ring `>`";
132144
}
133145

146+
def PolynomialLike: TypeOrContainer<Polynomial_PolynomialType, "polynomial-like">;
147+
134148
class Polynomial_Op<string mnemonic, list<Trait> traits = []> :
135-
Op<Polynomial_Dialect, mnemonic, traits # [Pure]>;
149+
Op<Polynomial_Dialect, mnemonic, traits # [Pure]> {
150+
let assemblyFormat = "operands attr-dict `:` functional-type(operands, results)";
151+
}
136152

137153
class Polynomial_UnaryOp<string mnemonic, list<Trait> traits = []> :
138154
Polynomial_Op<mnemonic, traits # [SameOperandsAndResultType]> {
139155
let arguments = (ins Polynomial_PolynomialType:$operand);
140156
let results = (outs Polynomial_PolynomialType:$result);
141-
142-
let assemblyFormat = "$operand attr-dict `:` qualified(type($result))";
143157
}
144158

145159
class Polynomial_BinaryOp<string mnemonic, list<Trait> traits = []> :
146-
Polynomial_Op<mnemonic, traits # [SameOperandsAndResultType]> {
147-
let arguments = (ins Polynomial_PolynomialType:$lhs, Polynomial_PolynomialType:$rhs);
148-
let results = (outs Polynomial_PolynomialType:$result);
160+
Polynomial_Op<mnemonic, !listconcat(traits, [Pure, SameOperandsAndResultType, ElementwiseMappable])> {
161+
let arguments = (ins PolynomialLike:$lhs, PolynomialLike:$rhs);
162+
let results = (outs PolynomialLike:$result);
163+
let assemblyFormat = "operands attr-dict `:` type($result)";
164+
}
165+
166+
def Polynomial_AddOp : Polynomial_BinaryOp<"add", [Commutative]> {
167+
let summary = "Addition operation between polynomials.";
168+
let description = [{
169+
Performs polynomial addition on the operands. The operands may be single
170+
polynomials or containers of identically-typed polynomials, i.e., polynomials
171+
from the same underlying ring with the same coefficient types.
172+
173+
Addition is defined to occur in the ring defined by the ring attribute of
174+
the two operands, meaning the addition is taken modulo the coefficientModulus
175+
and the polynomialModulus of the ring.
176+
177+
Example:
178+
179+
```mlir
180+
// add two polynomials modulo x^1024 - 1
181+
#poly = #polynomial.polynomial<x**1024 - 1>
182+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
183+
%0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
184+
%1 = polynomial.constant #polynomial.polynomial<x**5 - x + 1> : !polynomial.polynomial<#ring>
185+
%2 = polynomial.add %0, %1 : !polynomial.polynomial<#ring>
186+
```
187+
}];
188+
}
189+
190+
def Polynomial_SubOp : Polynomial_BinaryOp<"sub"> {
191+
let summary = "Subtraction operation between polynomials.";
192+
let description = [{
193+
Performs polynomial subtraction on the operands. The operands may be single
194+
polynomials or containers of identically-typed polynomials, i.e., polynomials
195+
from the same underlying ring with the same coefficient types.
196+
197+
Subtraction is defined to occur in the ring defined by the ring attribute of
198+
the two operands, meaning the subtraction is taken modulo the coefficientModulus
199+
and the polynomialModulus of the ring.
200+
201+
Example:
149202

150-
let assemblyFormat = "$lhs `,` $rhs attr-dict `:` qualified(type($result))";
203+
```mlir
204+
// subtract two polynomials modulo x^1024 - 1
205+
#poly = #polynomial.polynomial<x**1024 - 1>
206+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
207+
%0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
208+
%1 = polynomial.constant #polynomial.polynomial<x**5 - x + 1> : !polynomial.polynomial<#ring>
209+
%2 = polynomial.sub %0, %1 : !polynomial.polynomial<#ring>
210+
```
211+
}];
212+
}
213+
214+
def Polynomial_MulOp : Polynomial_BinaryOp<"mul", [Commutative]> {
215+
let summary = "Multiplication operation between polynomials.";
216+
let description = [{
217+
Performs polynomial multiplication on the operands. The operands may be single
218+
polynomials or containers of identically-typed polynomials, i.e., polynomials
219+
from the same underlying ring with the same coefficient types.
220+
221+
Multiplication is defined to occur in the ring defined by the ring attribute of
222+
the two operands, meaning the multiplication is taken modulo the coefficientModulus
223+
and the polynomialModulus of the ring.
224+
225+
Example:
226+
227+
```mlir
228+
// multiply two polynomials modulo x^1024 - 1
229+
#poly = #polynomial.polynomial<x**1024 - 1>
230+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
231+
%0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
232+
%1 = polynomial.constant #polynomial.polynomial<x**5 - x + 1> : !polynomial.polynomial<#ring>
233+
%2 = polynomial.mul %0, %1 : !polynomial.polynomial<#ring>
234+
```
235+
}];
236+
}
237+
238+
def Polynomial_MulScalarOp : Polynomial_Op<"mul_scalar", [
239+
ElementwiseMappable, AllTypesMatch<["polynomial", "output"]>]> {
240+
let summary = "Multiplication by a scalar of the field.";
241+
let description = [{
242+
Multiplies the polynomial operand's coefficients by a given scalar value.
243+
The operation is defined to occur in the ring defined by the ring attribute
244+
of the two operands, meaning the multiplication is taken modulo the
245+
coefficientModulus of the ring.
246+
247+
The `scalar` input must have the same type as the polynomial ring's
248+
coefficientType.
249+
250+
Example:
251+
252+
```mlir
253+
// multiply two polynomials modulo x^1024 - 1
254+
#poly = #polynomial.polynomial<x**1024 - 1>
255+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
256+
%0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
257+
%1 = arith.constant 3 : i32
258+
%2 = polynomial.mul_scalar %0, %1 : !polynomial.polynomial<#ring>, i32
259+
```
260+
}];
261+
262+
let arguments = (ins
263+
PolynomialLike:$polynomial,
264+
AnyInteger:$scalar
265+
);
266+
let results = (outs
267+
PolynomialLike:$output
268+
);
269+
let assemblyFormat = "operands attr-dict `:` type($polynomial) `,` type($scalar)";
270+
let hasVerifier = 1;
271+
}
272+
273+
def Polynomial_LeadingTermOp: Polynomial_Op<"leading_term"> {
274+
let summary = "Compute the leading term of the polynomial.";
275+
let description = [{
276+
The degree of a polynomial is the largest $k$ for which the coefficient
277+
`a_k` of `x^k` is nonzero. The leading term is the term `a_k * x^k`, which
278+
this op represents as a pair of results. The first is the degree `k` as an
279+
index, and the second is the coefficient, whose type matches the
280+
coefficient type of the polynomial's ring attribute.
281+
282+
Example:
283+
284+
```mlir
285+
#poly = #polynomial.polynomial<x**1024 - 1>
286+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
287+
%0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
288+
%1, %2 = polynomial.leading_term %0 : !polynomial.polynomial<#ring> -> (index, i32)
289+
```
290+
}];
291+
let arguments = (ins Polynomial_PolynomialType:$input);
292+
let results = (outs Index:$degree, AnyInteger:$coefficient);
293+
let assemblyFormat = "operands attr-dict `:` type($input) `->` `(` type($degree) `,` type($coefficient) `)`";
294+
}
295+
296+
def Polynomial_MonomialOp: Polynomial_Op<"monomial"> {
297+
let summary = "Create a polynomial that consists of a single monomial.";
298+
let description = [{
299+
Construct a polynomial that consists of a single monomial term, from its
300+
degree and coefficient as dynamic inputs.
301+
302+
The coefficient type of the output polynomial's ring attribute must match
303+
the `coefficient` input type.
304+
305+
Example:
306+
307+
```mlir
308+
#poly = #polynomial.polynomial<x**1024 - 1>
309+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
310+
%deg = arith.constant 1023 : index
311+
%five = arith.constant 5 : i32
312+
%0 = polynomial.monomial %five, %deg : (i32, index) -> !polynomial.polynomial<#ring>
313+
```
314+
}];
315+
let arguments = (ins AnyInteger:$coefficient, Index:$degree);
316+
let results = (outs Polynomial_PolynomialType:$output);
317+
}
318+
319+
def Polynomial_MonicMonomialMulOp: Polynomial_Op<"monic_monomial_mul", [AllTypesMatch<["input", "output"]>]> {
320+
let summary = "Multiply a polynomial by a monic monomial.";
321+
let description = [{
322+
Multiply a polynomial by a monic monomial, meaning a polynomial of the form
323+
`1 * x^k` for an index operand `k`.
324+
325+
In some special rings of polynomials, such as a ring of polynomials
326+
modulo `x^n - 1`, `monomial_mul` can be interpreted as a cyclic shift of
327+
the coefficients of the polynomial. For some rings, this results in
328+
optimized lowerings that involve rotations and rescaling of the
329+
coefficients of the input.
330+
}];
331+
let arguments = (ins PolynomialLike:$input, Index:$monomialDegree);
332+
let results = (outs PolynomialLike:$output);
333+
}
334+
335+
def Polynomial_FromTensorOp : Polynomial_Op<"from_tensor", [Pure]> {
336+
let summary = "Creates a polynomial from integer coefficients stored in a tensor.";
337+
let description = [{
338+
`polynomial.from_tensor` creates a polynomial value from a tensor of coefficients.
339+
The input tensor must list the coefficients in degree-increasing order.
340+
341+
The input one-dimensional tensor may have size at most the degree of the
342+
ring's polynomialModulus generator polynomial, with smaller dimension implying that
343+
all higher-degree terms have coefficient zero.
344+
345+
Example:
346+
347+
```mlir
348+
#poly = #polynomial.polynomial<x**1024 - 1>
349+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
350+
%two = arith.constant 2 : i32
351+
%five = arith.constant 5 : i32
352+
%coeffs = tensor.from_elements %two, %two, %five : tensor<3xi32>
353+
%poly = polynomial.from_tensor %coeffs : tensor<3xi32> -> !polynomial.polynomial<#ring>
354+
```
355+
}];
356+
let arguments = (ins RankedTensorOf<[AnyInteger]>:$input);
357+
let results = (outs Polynomial_PolynomialType:$output);
358+
359+
let assemblyFormat = "$input attr-dict `:` type($input) `->` type($output)";
360+
361+
let builders = [
362+
// Builder that infers coefficient modulus from tensor bit width,
363+
// and uses whatever input ring is provided by the caller.
364+
OpBuilder<(ins "::mlir::Value":$input, "::mlir::polynomial::RingAttr":$ring)>
365+
];
366+
let hasVerifier = 1;
367+
}
368+
369+
def Polynomial_ToTensorOp : Polynomial_Op<"to_tensor", [Pure]> {
370+
let summary = "Creates a tensor containing the coefficients of a polynomial.";
371+
let description = [{
372+
`polynomial.to_tensor` creates a dense tensor value containing the
373+
coefficients of the input polynomial. The output tensor contains the
374+
coefficients in degree-increasing order.
375+
376+
Operations that act on the coefficients of a polynomial, such as extracting
377+
a specific coefficient or extracting a range of coefficients, should be
378+
implemented by composing `to_tensor` with the relevant `tensor` dialect
379+
ops.
380+
381+
The output tensor has shape equal to the degree of the polynomial ring
382+
attribute's polynomialModulus, including zeroes.
383+
384+
Example:
385+
386+
```mlir
387+
#poly = #polynomial.polynomial<x**1024 - 1>
388+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
389+
%two = arith.constant 2 : i32
390+
%five = arith.constant 5 : i32
391+
%coeffs = tensor.from_elements %two, %two, %five : tensor<3xi32>
392+
%poly = polynomial.from_tensor %coeffs : tensor<3xi32> -> !polynomial.polynomial<#ring>
393+
%tensor = polynomial.to_tensor %poly : !polynomial.polynomial<#ring> -> tensor<1024xi32>
394+
```
395+
}];
396+
let arguments = (ins Polynomial_PolynomialType:$input);
397+
let results = (outs RankedTensorOf<[AnyInteger]>:$output);
398+
let assemblyFormat = "$input attr-dict `:` type($input) `->` type($output)";
399+
400+
let hasVerifier = 1;
401+
}
402+
403+
def Polynomial_ConstantOp : Polynomial_Op<"constant", [Pure]> {
404+
let summary = "Define a constant polynomial via an attribute.";
405+
let description = [{
406+
Example:
407+
408+
```mlir
409+
#poly = #polynomial.polynomial<x**1024 - 1>
410+
#ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
411+
%0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
412+
```
413+
}];
414+
let arguments = (ins Polynomial_PolynomialAttr:$input);
415+
let results = (outs Polynomial_PolynomialType:$output);
416+
let assemblyFormat = "$input attr-dict `:` type($output)";
151417
}
152418

153419
#endif // POLYNOMIAL_OPS

mlir/lib/Dialect/Polynomial/IR/PolynomialDialect.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@
88

99
#include "mlir/Dialect/Polynomial/IR/Polynomial.h"
1010

11+
#include "mlir/Dialect/Arith/IR/Arith.h"
1112
#include "mlir/Dialect/Polynomial/IR/PolynomialAttributes.h"
1213
#include "mlir/Dialect/Polynomial/IR/PolynomialOps.h"
1314
#include "mlir/Dialect/Polynomial/IR/PolynomialTypes.h"
15+
#include "mlir/IR/Builders.h"
16+
#include "mlir/IR/BuiltinOps.h"
17+
#include "mlir/IR/BuiltinTypes.h"
18+
#include "mlir/IR/Dialect.h"
19+
#include "mlir/IR/PatternMatch.h"
20+
#include "mlir/Interfaces/InferTypeOpInterface.h"
21+
#include "mlir/Support/LogicalResult.h"
22+
#include "llvm/ADT/APInt.h"
1423
#include "llvm/ADT/TypeSwitch.h"
1524

1625
using namespace mlir;

0 commit comments

Comments
 (0)