Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add divexact!, lcm!, submul! #1812

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions docs/src/ring.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,49 @@ right, respectively, of `a`.

## Unsafe ring operators

To speed up polynomial arithmetic, various unsafe operators are provided, which may
mutate the output rather than create a new object.
To speed up polynomial and matrix arithmetic, it sometimes makes sense to mutate values
in place rather than replace them with a newly created object every time they are
modified.

```julia
zero!(a::NCRingElement)
mul!(a::T, b::T, c::T) where T <: NCRingElement
add!(a::T, b::T, c::T) where T <: NCRingElement
addmul!(a::T, b::T, c::T, t::T) where T <: NCRingElement
```
For this purpose, certain mutating operators are required. In order to support immutable
types (struct in Julia) and systems that don't have in-place operators, all unsafe
operators must return the (ostensibly) mutated value. Only the returned value is used
in computations, so this lifts the requirement that the unsafe operators actually
mutate the value.

Note the exclamation point is a convention, which indicates that the object may be
mutated in-place.

To make use of these functions, one must be certain that no other references are held
to the object being mutated, otherwise those values will also be changed!

The results of `deepcopy` and all arithmetic operations, including powering and division
can be assumed to be new objects without other references being held, as can objects
returned from constructors.

In each case the mutated object is the leftmost parameter.
!!! note

It is important to recognise that `R(a)` where `R` is the ring `a` belongs
to, does not create a new value. For this case, use `deepcopy(a)`.

```@docs
zero!
one!
add!
sub!
mul!
neg!
inv!
addmul!
submul!
divexact!
div!
rem!
mod!
gcd!
lcm!
```

The `add!(a, b)` operation does the same thing as `add!(a, a, b)`. The
optional `addmul!(a, b, c, t)` operation does the same thing as
`mul!(t, b, c); add!(a, t)` where `t` is a temporary which can be mutated so
that an addition allocation is not needed.

## Random generation

Expand Down
54 changes: 9 additions & 45 deletions docs/src/ring_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,51 +517,6 @@ point division. Here we mean exact division in the ring.
A fallback for this function is provided in terms of `divexact` so an implementation
can be omitted if preferred.

### Unsafe operators

To speed up polynomial and matrix arithmetic, it sometimes makes sense to mutate values
in place rather than replace them with a newly created object every time they are
modified.

For this purpose, certain mutating operators are required. In order to support immutable
types (struct in Julia) and systems that don't have in-place operators, all unsafe
operators must return the (ostensibly) mutated value. Only the returned value is used
in computations, so this lifts the requirement that the unsafe operators actually
mutate the value.

Note the exclamation point is a convention, which indicates that the object may be
mutated in-place.

To make use of these functions, one must be certain that no other references are held
to the object being mutated, otherwise those values will also be changed!

The results of `deepcopy` and all arithmetic operations, including powering and division
can be assumed to be new objects without other references being held, as can objects
returned from constructors.

!!! note

It is important to recognise that `R(a)` where `R` is the ring `a` belongs
to, does not create a new value. For this case, use `deepcopy(a)`.

```julia
zero!(f::MyElem)
```

Set the value $f$ to zero in place. Return the mutated value.

```julia
mul!(c::MyElem, a::MyElem, b::MyElem)
```

Set $c$ to the value $ab$ in place. Return the mutated value. Aliasing is permitted.

```julia
add!(c::MyElem, a::MyElem, b::MyElem)
```

Set $c$ to the value $a + b$ in place. Return the mutated value. Aliasing is permitted.

### Random generation

The random functions are only used for test code to generate test data. They therefore
Expand Down Expand Up @@ -679,6 +634,15 @@ functions. As these functions are optional, they do not need to exist. Julia wil
already inform the user that the function has not been implemented if it is called but
doesn't exist.

### Optional unsafe operators

The various operators described in [Unsafe ring operators](@ref) such as
`add!` and `mul!` have default implementations which are not faster than their
regular safe counterparts. Implementors may wish to implement some or all of
them for their rings. Note that in general only the variants with the most
arguments needs to be implemented. E.g. for `add!` only `add(z,a,b)` has to be
implemented for any new ring type, as `add!(a,b)` delegates to `add!(a,a,b)`.

### Optional basic manipulation functionality

```julia
Expand Down
8 changes: 1 addition & 7 deletions src/Groups.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,16 +237,10 @@ end
################################################################################

# further mutable functions in fundamental_interface.jl:
# one!(g::GroupElem)
# mul!(out::T, g::T, h::T) where {T<:GroupElem} = g * h
# inv!(out::T, g::T) where {T<:GroupElem} = inv(g)

"""
one!(g::GroupElem)

Return `one(g)`, possibly modifying `g`.
"""
one!(g::GroupElem) = one(parent(g))

"""
div_right!(out::T, g::T, h::T) where {GEl <: GroupElem}

Expand Down
3 changes: 3 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export div_left!
export div_right
export div_right!
export divexact
export divexact!
export divexact_left
export divexact_low
export divexact_right
Expand Down Expand Up @@ -349,6 +350,7 @@ export laurent_series
export laurent_series_field
export laurent_series_ring
export lcm
export lcm!
export leading_coefficient
export leading_exponent_vector
export leading_exponent_word
Expand Down Expand Up @@ -566,6 +568,7 @@ export weights
export with_unicode
export zero
export zero!
export submul!
fingolfin marked this conversation as resolved.
Show resolved Hide resolved
export zero_matrix
export zeros
export zz
Loading
Loading