Skip to content

Commit

Permalink
Add divexact!, lcm!, submul! (#1812)
Browse files Browse the repository at this point in the history
  • Loading branch information
fingolfin authored Sep 27, 2024
1 parent b5e4786 commit 2c9570b
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 206 deletions.
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 @@ -530,6 +532,7 @@ export strictly_upper_triangular_matrix
export sturm_sequence
export sub
export sub!
export submul!
export subst
export summands
export supermodule
Expand Down
Loading

0 comments on commit 2c9570b

Please sign in to comment.