Polynomial

Polynomial attributes

AffineMapAttr

An Attribute containing an AffineMap object

Syntax:

affine-map-attribute ::= `affine_map` `<` affine-map `>`

Examples:

affine_map<(d0) -> (d0)>
affine_map<(d0, d1, d2) -> (d0, d1)>

Parameters:

ParameterC++ typeDescription
valueAffineMap

ArrayAttr

A collection of other Attribute values

Syntax:

array-attribute ::= `[` (attribute-value (`,` attribute-value)*)? `]`

An array attribute is an attribute that represents a collection of attribute values.

Examples:

[]
[10, i32]
[affine_map<(d0, d1, d2) -> (d0, d1)>, i32, "string attribute"]

Parameters:

ParameterC++ typeDescription
value::llvm::ArrayRef<Attribute>

DenseArrayAttr

A dense array of integer or floating point elements.

A dense array attribute is an attribute that represents a dense array of primitive element types. Contrary to DenseIntOrFPElementsAttr this is a flat unidimensional array which does not have a storage optimization for splat. This allows to expose the raw array through a C++ API as ArrayRef<T> for compatible types. The element type must be bool or an integer or float whose bitwidth is a multiple of 8. Bool elements are stored as bytes.

This is the base class attribute. Access to C++ types is intended to be managed through the subclasses DenseI8ArrayAttr, DenseI16ArrayAttr, DenseI32ArrayAttr, DenseI64ArrayAttr, DenseF32ArrayAttr, and DenseF64ArrayAttr.

Syntax:

dense-array-attribute ::= `array` `<` (integer-type | float-type)
                                      (`:` tensor-literal)? `>`

Examples:

array<i8>
array<i32: 10, 42>
array<f64: 42., 12.>

When a specific subclass is used as argument of an operation, the declarative assembly will omit the type and print directly:

[1, 2, 3]

Parameters:

ParameterC++ typeDescription
elementTypeType
sizeint64_t
rawData::llvm::ArrayRef<char>64-bit aligned storage for dense array elements

DenseIntOrFPElementsAttr

An Attribute containing a dense multi-dimensional array of integer or floating-point values

Syntax:

tensor-literal ::= integer-literal | float-literal | bool-literal | [] | [tensor-literal (, tensor-literal)* ]
dense-intorfloat-elements-attribute ::= `dense` `<` tensor-literal `>` `:`
                                        ( tensor-type | vector-type )

A dense int-or-float elements attribute is an elements attribute containing a densely packed vector or tensor of integer or floating-point values. The element type of this attribute is required to be either an IntegerType or a FloatType.

Examples:

// A splat tensor of integer values.
dense<10> : tensor<2xi32>
// A tensor of 2 float32 elements.
dense<[10.0, 11.0]> : tensor<2xf32>

Parameters:

ParameterC++ typeDescription
typeShapedType
rawDataArrayRef<char>

DenseResourceElementsAttr

An Attribute containing a dense multi-dimensional array backed by a resource

Syntax:

dense-resource-elements-attribute ::=
  `dense_resource` `<` resource-handle `>` `:` shaped-type

A dense resource elements attribute is an elements attribute backed by a handle to a builtin dialect resource containing a densely packed array of values. This class provides the low-level attribute, which should only be interacted with in very generic terms, actual access to the underlying resource data is intended to be managed through one of the subclasses, such as; DenseBoolResourceElementsAttr, DenseUI64ResourceElementsAttr, DenseI32ResourceElementsAttr, DenseF32ResourceElementsAttr, DenseF64ResourceElementsAttr, etc.

Examples:

"example.user_op"() {attr = dense_resource<blob1> : tensor<3xi64> } : () -> ()

{-#
dialect_resources: {
    builtin: {
      blob1: "0x08000000010000000000000002000000000000000300000000000000"
    }
  }
#-}

Parameters:

ParameterC++ typeDescription
typeShapedType
rawHandleDenseResourceElementsHandle

DenseStringElementsAttr

An Attribute containing a dense multi-dimensional array of strings

Syntax:

dense-string-elements-attribute ::= `dense` `<` attribute-value `>` `:`
                                    ( tensor-type | vector-type )

A dense string elements attribute is an elements attribute containing a densely packed vector or tensor of string values. There are no restrictions placed on the element type of this attribute, enabling the use of dialect specific string types.

Examples:

// A splat tensor of strings.
dense<"example"> : tensor<2x!foo.string>
// A tensor of 2 string elements.
dense<["example1", "example2"]> : tensor<2x!foo.string>

Parameters:

ParameterC++ typeDescription
typeShapedType
valueArrayRef<StringRef>

DictionaryAttr

An dictionary of named Attribute values

Syntax:

dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`

A dictionary attribute is an attribute that represents a sorted collection of named attribute values. The elements are sorted by name, and each name must be unique within the collection.

Examples:

{}
{attr_name = "string attribute"}
{int_attr = 10, "string attr name" = "string attribute"}

Parameters:

ParameterC++ typeDescription
value::llvm::ArrayRef<NamedAttribute>

FloatAttr

An Attribute containing a floating-point value

Syntax:

float-attribute ::= (float-literal (`:` float-type)?)
                  | (hexadecimal-literal `:` float-type)

A float attribute is a literal attribute that represents a floating point value of the specified float type. It can be represented in the hexadecimal form where the hexadecimal value is interpreted as bits of the underlying binary representation. This form is useful for representing infinity and NaN floating point values. To avoid confusion with integer attributes, hexadecimal literals must be followed by a float type to define a float attribute.

Examples:

42.0         // float attribute defaults to f64 type
42.0 : f32   // float attribute of f32 type
0x7C00 : f16 // positive infinity
0x7CFF : f16 // NaN (one of possible values)
42 : f32     // Error: expected integer type

Parameters:

ParameterC++ typeDescription
type::mlir::Type
value::llvm::APFloat

IntegerAttr

An Attribute containing a integer value

Syntax:

integer-attribute ::= (integer-literal ( `:` (index-type | integer-type) )?)
                      | `true` | `false`

An integer attribute is a literal attribute that represents an integral value of the specified integer or index type. i1 integer attributes are treated as boolean attributes, and use a unique assembly format of either true or false depending on the value. The default type for non-boolean integer attributes, if a type is not specified, is signless 64-bit integer.

Examples:

10 : i32
10    // : i64 is implied here.
true  // A bool, i.e. i1, value.
false // A bool, i.e. i1, value.

Parameters:

ParameterC++ typeDescription
type::mlir::Type
valueAPInt

IntegerSetAttr

An Attribute containing an IntegerSet object

Syntax:

integer-set-attribute ::= `affine_set` `<` integer-set `>`

Examples:

affine_set<(d0) : (d0 - 2 >= 0)>

Parameters:

ParameterC++ typeDescription
valueIntegerSet

OpaqueAttr

An opaque representation of another Attribute

Syntax:

opaque-attribute ::= dialect-namespace `<` attr-data `>`

Opaque attributes represent attributes of non-registered dialects. These are attribute represented in their raw string form, and can only usefully be tested for attribute equality.

Examples:

#dialect<"opaque attribute data">

Parameters:

ParameterC++ typeDescription
dialectNamespaceStringAttr
attrData::llvm::StringRef
type::mlir::Type

SparseElementsAttr

An opaque representation of a multi-dimensional array

Syntax:

sparse-elements-attribute ::= `sparse` `<` attribute-value `,`
                              attribute-value `>` `:`
                              ( tensor-type | vector-type )

A sparse elements attribute is an elements attribute that represents a sparse vector or tensor object. This is where very few of the elements are non-zero.

The attribute uses COO (coordinate list) encoding to represent the sparse elements of the elements attribute. The indices are stored via a 2-D tensor of 64-bit integer elements with shape [N, ndims], which specifies the indices of the elements in the sparse tensor that contains non-zero values. The element values are stored via a 1-D tensor with shape [N], that supplies the corresponding values for the indices.

Example:

sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>

// This represents the following tensor:
///  [[1, 0, 0, 0],
///   [0, 0, 5, 0],
///   [0, 0, 0, 0]]

Parameters:

ParameterC++ typeDescription
typeShapedType
indicesDenseIntElementsAttr
valuesDenseElementsAttr

StringAttr

An Attribute containing a string

Syntax:

string-attribute ::= string-literal (`:` type)?

A string attribute is an attribute that represents a string literal value.

Examples:

"An important string"
"string with a type" : !dialect.string

Parameters:

ParameterC++ typeDescription
value::llvm::StringRef
type::mlir::Type

SymbolRefAttr

An Attribute containing a symbolic reference to an Operation

Syntax:

symbol-ref-attribute ::= symbol-ref-id (`::` symbol-ref-id)*

A symbol reference attribute is a literal attribute that represents a named reference to an operation that is nested within an operation with the OpTrait::SymbolTable trait. As such, this reference is given meaning by the nearest parent operation containing the OpTrait::SymbolTable trait. It may optionally contain a set of nested references that further resolve to a symbol nested within a different symbol table.

Rationale: Identifying accesses to global data is critical to enabling efficient multi-threaded compilation. Restricting global data access to occur through symbols and limiting the places that can legally hold a symbol reference simplifies reasoning about these data accesses.

See Symbols And SymbolTables for more information.

Examples:

@flat_reference
@parent_reference::@nested_reference

Parameters:

ParameterC++ typeDescription
rootReferenceStringAttr
nestedReferences::llvm::ArrayRef<FlatSymbolRefAttr>

TypeAttr

An Attribute containing a Type

Syntax:

type-attribute ::= type

A type attribute is an attribute that represents a type object.

Examples:

i32
!dialect.type

Parameters:

ParameterC++ typeDescription
valueType

UnitAttr

An Attribute value of unit type

Syntax:

unit-attribute ::= `unit`

A unit attribute is an attribute that represents a value of unit type. The unit type allows only one value forming a singleton set. This attribute value is used to represent attributes that only have meaning from their existence.

One example of such an attribute could be the swift.self attribute. This attribute indicates that a function parameter is the self/context parameter. It could be represented as a boolean attribute(true or false), but a value of false doesn’t really bring any value. The parameter either is the self/context or it isn’t.

Examples:

// A unit attribute defined with the `unit` value specifier.
func.func @verbose_form() attributes {dialectName.unitAttr = unit}

// A unit attribute in an attribute dictionary can also be defined without
// the value specifier.
func.func @simple_form() attributes {dialectName.unitAttr}

FloatPolynomialAttr

an attribute containing a single-variable polynomial with double precision floating point coefficients

A polynomial attribute represents a single-variable polynomial with double precision floating point coefficients.

The polynomial must be expressed as a list of monomial terms, with addition or subtraction between them. The choice of variable name is arbitrary, but must be consistent across all the monomials used to define a single attribute. The order of monomial terms is arbitrary, each monomial degree must occur at most once.

Example:

#poly = #polynomial.float_polynomial<0.5 x**7 + 1.5>

Parameters:

ParameterC++ typeDescription
polynomialFloatPolynomial

IntPolynomialAttr

an attribute containing a single-variable polynomial with integer coefficients

A polynomial attribute represents a single-variable polynomial with integer coefficients, which is used to define the modulus of a RingAttr, as well as to define constants and perform constant folding for polynomial ops.

The polynomial must be expressed as a list of monomial terms, with addition or subtraction between them. The choice of variable name is arbitrary, but must be consistent across all the monomials used to define a single attribute. The order of monomial terms is arbitrary, each monomial degree must occur at most once.

Example:

#poly = #polynomial.int_polynomial<x**1024 + 1>

Parameters:

ParameterC++ typeDescription
polynomial::mlir::heir::polynomial::IntPolynomial

PrimitiveRootAttr

an attribute containing an integer and its degree as a root of unity

Syntax:

#polynomial.primitive_root<
  ::mlir::IntegerAttr,   # value
  ::mlir::IntegerAttr   # degree
>

A primitive root attribute stores an integer root value and an integer degree, corresponding to a primitive root of unity of the given degree in an unspecified ring.

This is used as an attribute on polynomial.ntt and polynomial.intt ops to specify the root of unity used in lowering the transform.

Example:

#poly = #polynomial.primitive_root<value=123 : i32, degree : 7 index>

Parameters:

ParameterC++ typeDescription
value::mlir::IntegerAttr
degree::mlir::IntegerAttr

RingAttr

an attribute specifying a polynomial ring

Syntax:

#polynomial.ring<
  Type,   # coefficientType
  ::mlir::heir::polynomial::IntPolynomialAttr   # polynomialModulus
>

A ring describes the domain in which polynomial arithmetic occurs. The ring attribute in polynomial represents the more specific case of polynomials with a single indeterminate; whose coefficients can be represented by another MLIR type (coefficientType).

All semantics pertaining to arithmetic in the ring must be owned by the coefficient type. For example, if the polynomials are with integer coefficients taken modulo a prime $p$, then coefficientType must be a type that represents integers modulo $p$, such as mod_arith<p>.

Additionally, a polynomial ring may specify a polynomialModulus, which converts polynomial arithmetic to the analogue of modular integer arithmetic, where each polynomial is represented as its remainder when dividing by the modulus. For single-variable polynomials, a polynomial modulus is always specified via a single polynomial.

An expressive example is polynomials with i32 coefficients, whose coefficients are taken modulo 2**32 - 5, with a polynomial modulus of x**1024 - 1.

#poly_mod = #polynomial.int_polynomial<-1 + x**1024>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly_mod>

%0 = ... : polynomial.polynomial<#ring>

In this case, the value of a polynomial is always “converted” to a canonical form by applying repeated reductions by setting x**1024 = 1 and simplifying.

Parameters:

ParameterC++ typeDescription
coefficientTypeType
polynomialModulus::mlir::heir::polynomial::IntPolynomialAttr

TypedFloatPolynomialAttr

a typed float_polynomial

Syntax:

#polynomial.typed_float_polynomial<
  ::mlir::Type,   # type
  ::mlir::heir::polynomial::FloatPolynomialAttr   # value
>

Example:

!poly_ty = !polynomial.polynomial<ring=<coefficientType=f32>>
#poly = float<1.4 x**7 + 4.5> : !poly_ty
#poly_verbose = #polynomial.typed_float_polynomial<1.4 x**7 + 4.5> : !poly_ty

Parameters:

ParameterC++ typeDescription
type::mlir::Type
value::mlir::heir::polynomial::FloatPolynomialAttr

TypedIntPolynomialAttr

a typed int_polynomial

Syntax:

#polynomial.typed_int_polynomial<
  ::mlir::Type,   # type
  ::mlir::heir::polynomial::IntPolynomialAttr   # value
>

Example:

!poly_ty = !polynomial.polynomial<ring=<coefficientType=i32>>
#poly = int<1 x**7 + 4> : !poly_ty
#poly_verbose = #polynomial.typed_int_polynomial<1 x**7 + 4> : !poly_ty

Parameters:

ParameterC++ typeDescription
type::mlir::Type
value::mlir::heir::polynomial::IntPolynomialAttr

StridedLayoutAttr

An Attribute representing a strided layout of a shaped type

Syntax:

strided-layout-attribute ::= `strided` `<` `[` stride-list `]`
                             (`,` `offset` `:` dimension)? `>`
stride-list ::= /*empty*/
              | dimension (`,` dimension)*
dimension ::= decimal-literal | `?`

A strided layout attribute captures layout information of the memref type in the canonical form. Specifically, it contains a list of strides, one for each dimension. A stride is the number of elements in the linear storage one must step over to reflect an increment in the given dimension. For example, a MxN row-major contiguous shaped type would have the strides [N, 1]. The layout attribute also contains the offset from the base pointer of the shaped type to the first effectively accessed element, expressed in terms of the number of contiguously stored elements.

Strides must be positive and the offset must be non-negative. Both the strides and the offset may be dynamic, i.e. their value may not be known at compile time. This is expressed as a ? in the assembly syntax and as ShapedType::kDynamic in the code. Stride and offset values must satisfy the constraints above at runtime, the behavior is undefined otherwise.

See [Dialects/Builtin.md#memreftype](MemRef type) for more information.

Parameters:

ParameterC++ typeDescription
offsetint64_t
strides::llvm::ArrayRef<int64_t>array of strides (64-bit integer)

Polynomial types

PolynomialType

An element of a polynomial ring.

Syntax:

!polynomial.polynomial<
  ::mlir::heir::polynomial::RingAttr   # ring
>

A type for polynomials in a polynomial quotient ring.

Parameters:

ParameterC++ typeDescription
ring::mlir::heir::polynomial::RingAttran attribute specifying a polynomial ring

Polynomial ops

polynomial.add (heir::polynomial::AddOp)

Addition operation between polynomials.

Syntax:

operation ::= `polynomial.add` operands attr-dict `:` type($result)

Performs polynomial addition on the operands. The operands may be single polynomials or containers of identically-typed polynomials, i.e., polynomials from the same underlying ring with the same coefficient types.

This op is defined to occur in the ring defined by the ring attribute of the two operands, meaning the arithmetic is taken modulo the polynomialModulus of the ring as well as modulo any semantics defined by the coefficient type.

Example:

// add two polynomials modulo x^1024 - 1
#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%0 = polynomial.constant int<1 + x**2> : !polynomial.polynomial<#ring>
%1 = polynomial.constant int<x**5 - x + 1> : !polynomial.polynomial<#ring>
%2 = polynomial.add %0, %1 : !polynomial.polynomial<#ring>

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhspolynomial-like
rhspolynomial-like

Results:

ResultDescription
resultpolynomial-like

polynomial.constant (heir::polynomial::ConstantOp)

Define a constant polynomial via an attribute.

Example:

!int_poly_ty = !polynomial.polynomial<ring=<coefficientType=i32>>
%0 = polynomial.constant int<1 + x**2> : !int_poly_ty

!float_poly_ty = !polynomial.polynomial<ring=<coefficientType=f32>>
%1 = polynomial.constant float<0.5 + 1.3e06 x**2> : !float_poly_ty

Traits: AlwaysSpeculatableImplTrait, InferTypeOpAdaptor

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
value::mlir::Attributea typed float_polynomial or a typed int_polynomial

Results:

ResultDescription
outputAn element of a polynomial ring.

polynomial.from_tensor (heir::polynomial::FromTensorOp)

Creates a polynomial from integer coefficients stored in a tensor.

Syntax:

operation ::= `polynomial.from_tensor` $input attr-dict `:` type($input) `->` type($output)

polynomial.from_tensor creates a polynomial value from a tensor of coefficients. The input tensor must list the coefficients in degree-increasing order.

The input one-dimensional tensor may have size at most the degree of the ring’s polynomialModulus generator polynomial, with smaller dimension implying that all higher-degree terms have coefficient zero.

Example:

#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%two = arith.constant 2 : i32
%five = arith.constant 5 : i32
%coeffs = tensor.from_elements %two, %two, %five : tensor<3xi32>
%poly = polynomial.from_tensor %coeffs : tensor<3xi32> -> !polynomial.polynomial<#ring>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputranked tensor of any type values

Results:

ResultDescription
outputAn element of a polynomial ring.

polynomial.intt (heir::polynomial::INTTOp)

Computes the reverse integer Number Theoretic Transform (NTT).

Syntax:

operation ::= `polynomial.intt` $input attr-dict `:` qualified(type($input)) `->` type($output)

polynomial.intt computes the reverse integer Number Theoretic Transform (INTT) on the input tensor. This is the inverse operation of the polynomial.ntt operation.

The input tensor is interpreted as a point-value representation of the output polynomial at powers of a primitive n-th root of unity (see polynomial.ntt). The ring of the polynomial is taken from the required encoding attribute of the tensor.

The choice of primitive root may be optionally specified.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
root::mlir::heir::polynomial::PrimitiveRootAttran attribute containing an integer and its degree as a root of unity

Operands:

OperandDescription
inputranked tensor of integer values

Results:

ResultDescription
outputAn element of a polynomial ring.

polynomial.leading_term (heir::polynomial::LeadingTermOp)

Compute the leading term of the polynomial.

Syntax:

operation ::= `polynomial.leading_term` operands attr-dict `:` type($input) `->` `(` type($degree) `,` type($coefficient) `)`

The degree of a polynomial is the largest $k$ for which the coefficient a_k of x^k is nonzero. The leading term is the term a_k * x^k, which this op represents as a pair of results. The first is the degree k as an index, and the second is the coefficient, whose type matches the coefficient type of the polynomial’s ring attribute.

Example:

#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%0 = polynomial.constant int<1 + x**2> : !polynomial.polynomial<#ring>
%1, %2 = polynomial.leading_term %0 : !polynomial.polynomial<#ring> -> (index, i32)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputAn element of a polynomial ring.

Results:

ResultDescription
degreeindex
coefficientany type

polynomial.monic_monomial_mul (heir::polynomial::MonicMonomialMulOp)

Multiply a polynomial by a monic monomial.

Syntax:

operation ::= `polynomial.monic_monomial_mul` operands attr-dict `:` functional-type(operands, results)

Multiply a polynomial by a monic monomial, meaning a polynomial of the form 1 * x^k for an index operand k.

In some special rings of polynomials, such as a ring of polynomials modulo x^n - 1, monomial_mul can be interpreted as a cyclic shift of the coefficients of the polynomial. For some rings, this results in optimized lowerings that involve rotations and rescaling of the coefficients of the input.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputpolynomial-like
monomialDegreeindex

Results:

ResultDescription
outputpolynomial-like

polynomial.monomial (heir::polynomial::MonomialOp)

Create a polynomial that consists of a single monomial.

Syntax:

operation ::= `polynomial.monomial` operands attr-dict `:` functional-type(operands, results)

Construct a polynomial that consists of a single monomial term, from its degree and coefficient as dynamic inputs.

The coefficient type of the output polynomial’s ring attribute must match the coefficient input type.

Example:

#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%deg = arith.constant 1023 : index
%five = arith.constant 5 : i32
%0 = polynomial.monomial %five, %deg : (i32, index) -> !polynomial.polynomial<#ring>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
coefficientany type
degreeindex

Results:

ResultDescription
outputAn element of a polynomial ring.

polynomial.mul (heir::polynomial::MulOp)

Multiplication operation between polynomials.

Syntax:

operation ::= `polynomial.mul` operands attr-dict `:` type($result)

Performs polynomial multiplication on the operands. The operands may be single polynomials or containers of identically-typed polynomials, i.e., polynomials from the same underlying ring with the same coefficient types.

This op is defined to occur in the ring defined by the ring attribute of the two operands, meaning the arithmetic is taken modulo the polynomialModulus of the ring as well as modulo any semantics defined by the coefficient type.

Example:

// multiply two polynomials modulo x^1024 - 1
#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%0 = polynomial.constant int<1 + x**2> : !polynomial.polynomial<#ring>
%1 = polynomial.constant int<x**5 - x + 1> : !polynomial.polynomial<#ring>
%2 = polynomial.mul %0, %1 : !polynomial.polynomial<#ring>

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhspolynomial-like
rhspolynomial-like

Results:

ResultDescription
resultpolynomial-like

polynomial.mul_scalar (heir::polynomial::MulScalarOp)

Multiplication by a scalar of the field.

Syntax:

operation ::= `polynomial.mul_scalar` operands attr-dict `:` type($polynomial) `,` type($scalar)

Multiplies the polynomial operand’s coefficients by a given scalar value. The scalar input must have the same type as the polynomial ring’s coefficientType.

Example:

// multiply two polynomials modulo x^1024 - 1
#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%0 = polynomial.constant int<1 + x**2> : !polynomial.polynomial<#ring>
%1 = arith.constant 3 : i32
%2 = polynomial.mul_scalar %0, %1 : !polynomial.polynomial<#ring>, i32

Traits: AlwaysSpeculatableImplTrait, Elementwise, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
polynomialpolynomial-like
scalarany type

Results:

ResultDescription
outputpolynomial-like

polynomial.ntt (heir::polynomial::NTTOp)

Computes point-value tensor representation of a polynomial.

Syntax:

operation ::= `polynomial.ntt` $input attr-dict `:` qualified(type($input)) `->` type($output)

polynomial.ntt computes the forward integer Number Theoretic Transform (NTT) on the input polynomial. It returns a tensor containing a point-value representation of the input polynomial. The output tensor has shape equal to the degree of the ring’s polynomialModulus. The polynomial’s RingAttr is embedded as the encoding attribute of the output tensor.

Given an input polynomial F(x) over a ring whose polynomialModulus has degree n, and a primitive n-th root of unity omega_n, the output is the list of $n$ evaluations

f[k] = F(omega[n]^k) ; k = {0, ..., n-1}

The choice of primitive root may be optionally specified.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
root::mlir::heir::polynomial::PrimitiveRootAttran attribute containing an integer and its degree as a root of unity

Operands:

OperandDescription
inputAn element of a polynomial ring.

Results:

ResultDescription
outputranked tensor of integer values

polynomial.sub (heir::polynomial::SubOp)

Subtraction operation between polynomials.

Syntax:

operation ::= `polynomial.sub` operands attr-dict `:` type($result)

Performs polynomial subtraction on the operands. The operands may be single polynomials or containers of identically-typed polynomials, i.e., polynomials from the same underlying ring with the same coefficient types.

This op is defined to occur in the ring defined by the ring attribute of the two operands, meaning the arithmetic is taken modulo the polynomialModulus of the ring as well as modulo any semantics defined by the coefficient type.

Example:

// subtract two polynomials modulo x^1024 - 1
#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%0 = polynomial.constant int<1 + x**2> : !polynomial.polynomial<#ring>
%1 = polynomial.constant int<x**5 - x + 1> : !polynomial.polynomial<#ring>
%2 = polynomial.sub %0, %1 : !polynomial.polynomial<#ring>

Traits: AlwaysSpeculatableImplTrait, Elementwise, SameOperandsAndResultType, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhspolynomial-like
rhspolynomial-like

Results:

ResultDescription
resultpolynomial-like

polynomial.to_tensor (heir::polynomial::ToTensorOp)

Creates a tensor containing the coefficients of a polynomial.

Syntax:

operation ::= `polynomial.to_tensor` $input attr-dict `:` type($input) `->` type($output)

polynomial.to_tensor creates a dense tensor value containing the coefficients of the input polynomial. The output tensor contains the coefficients in degree-increasing order.

Operations that act on the coefficients of a polynomial, such as extracting a specific coefficient or extracting a range of coefficients, should be implemented by composing to_tensor with the relevant tensor dialect ops.

The output tensor has shape equal to the degree of the polynomial ring attribute’s polynomialModulus, including zeroes.

Example:

#poly = #polynomial.int_polynomial<x**1024 - 1>
#ring = #polynomial.ring<coefficientType=i32, polynomialModulus=#poly>
%two = arith.constant 2 : i32
%five = arith.constant 5 : i32
%coeffs = tensor.from_elements %two, %two, %five : tensor<3xi32>
%poly = polynomial.from_tensor %coeffs : tensor<3xi32> -> !polynomial.polynomial<#ring>
%tensor = polynomial.to_tensor %poly : !polynomial.polynomial<#ring> -> tensor<1024xi32>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputAn element of a polynomial ring.

Results:

ResultDescription
outputranked tensor of any type values