Skip to content

Commit

Permalink
Add docs/src/examples/basics.md page (#134)
Browse files Browse the repository at this point in the history
* update docs

* update docs

* add dependency on HalfIntegers in docs

* update basics

* update docs

* Fix docs/src/examples/basics.md

Co-authored-by: Seth Axen <[email protected]>

* Fix typo in docs/src/examples/basics.md

Co-authored-by: Seth Axen <[email protected]>

* Fix docs/src/examples/basics.md

Co-authored-by: Seth Axen <[email protected]>

* Fix docs/src/examples/basics.md

Co-authored-by: Seth Axen <[email protected]>

* Fix docs/src/examples/basics.md

Co-authored-by: Seth Axen <[email protected]>

* Fix docs/src/examples/basics.md

Co-authored-by: Seth Axen <[email protected]>

* add docs for `sign`

* add type_parameter.md

* remove `warnonly=true`

* update first examples

* Fix `ishurwitz` by replacing `ishalfinteger` with `ishalfodd`

* add `ishalfodd` in the documentation because HalfIntegers.jl#59 takes time

---------

Co-authored-by: Seth Axen <[email protected]>
  • Loading branch information
hyrodium and sethaxen authored Feb 5, 2024
1 parent e82a56f commit 6d90f17
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 4 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,27 @@ A Julia implementation of quaternions.
as representations of 3D rotational orientation.
They can also be viewed as an extension of complex numbers.

## First example

```julia
julia> using Quaternions

julia> k = quat(0, 0, 0, 1)
Quaternion{Int64}(0, 0, 0, 1)

julia> j = quat(0, 0, 1, 0)
Quaternion{Int64}(0, 0, 1, 0)

julia> i = j*k
Quaternion{Int64}(0, 1, 0, 0)

julia> i^2 == j^2 == k^2 == i*j*k == -1 # Similar to `im^2`.
true

julia> 1 + i + k + j # Compatible with arithmetic operations as a `Number`.
Quaternion{Int64}(1, 1, 1, 1)
```

Check out [the docs](https://juliageometry.github.io/Quaternions.jl) for further instructions.

In JuliaGeometry organization, there is also [Octonions.jl](https://github.com/JuliaGeometry/Octonions.jl) package.
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
HalfIntegers = "f0d1745a-41c9-11e9-1dd9-e5d34d218721"
Quaternions = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0"

[compat]
Expand Down
3 changes: 3 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Quaternions
using Documenter
using HalfIntegers

DocMeta.setdocmeta!(Quaternions, :DocTestSetup, :(using Quaternions); recursive=true)

Expand All @@ -17,6 +18,8 @@ makedocs(;
"Home" => "index.md",
"APIs" => "api.md",
"Examples" => [
"examples/basics.md",
"examples/type_parameter.md",
"examples/rotations.md",
"examples/dual_quaternions.md"
],
Expand Down
89 changes: 89 additions & 0 deletions docs/src/examples/basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Basics

## Basic operations for quaternions
Quaternions can be defined with the [`Quaternion`](@ref) constructor or [`quat`](@ref) function.
Note that the order of the arguments is ``w+xi+yj+zk``, not ``xi+yj+zk+w``.

```@repl intro
using Quaternions
q1 = Quaternion(1,2,3,4)
q2 = quat(5,6,7,8)
q3 = quat(9)
```

The multiplication is not commutative.
```@repl intro
q1 * q2
q2 * q1
```

The multiplicative inverse can be calculated with [`Base.inv`](@ref).
```@repl intro
inv(q1)
inv(q1) * q1
```

The division is also not commutative.

```@repl intro
q1 / q2 # Same as `q1*inv(q2)` mathematically.
q2 \ q1 # Same as `inv(q2)*q1` mathematically.
```

A conjugate of a quaternion can be calculated with [`Base.conj`](@ref).
But `Base.imag(::Quaternion)` is not defined because it should return three real values which is not consistent with `imag(::Complex)` and `imag(::Real)`.
Instead, the [`imag_part`](@ref) function can be used to obtain the imaginary part of a quaternion.
See [issue#61](https://github.com/JuliaGeometry/Quaternions.jl/issues/61) for more discussion.

```@repl intro
conj(q1)
imag(q1) # Not supported.
imag_part(q1) # Use this instead.
```

Unit quaternions can be obtained with [`sign`](@ref).

```@repl intro
sign(q1)
sign(q2)
sign(q3)
sign(quat(0)) # Zero-quaternion will not be normalized.
```

## `Quaternion` vs `quat`
The general rule is that [`quat`](@ref) is to [`Quaternion`](@ref) as [`complex`](https://docs.julialang.org/en/v1/base/numbers/#Base.complex-Tuple{Complex}) is to [`Complex`](https://docs.julialang.org/en/v1/base/numbers/#Base.Complex).
`Complex` and `Quaternion` are both constructors so should return an object of the corresponding type, whereas `quat` and `complex` both can operate on types and arrays.

```@setup Quaternion-quat
using Quaternions
```

```@repl Quaternion-quat
Quaternion(1,2,3,4)
quat(1,2,3,4)
Quaternion(Int) # Similar to `Complex(Int)`.
quat(Int) # Similar to `complex(Int)`.
```

## Compatibility with `Complex`
There is no natural embedding ``\mathbb{C}\to\mathbb{H}``.
Thus, `quat(w,x,0,0)` is not equal to `complex(w,x)`, i.e.

```math
\mathbb{C} \ni w+ix \ne w+ix+0j+0k \in \mathbb{H}.
```

```@setup complex
using Quaternions
```

```@repl complex
1 + complex(1,2) # `Complex` is compatible with `Real`
1 + quat(1,2,3,4) # `Quaternion` is compatible with `Real`
1 + complex(1,2) + quat(1,2,3,4) # no compatibility
complex(1,2) == quat(1,2,0,0) # no compatibility
complex(1) == quat(1) # no compatibility
complex(1) == 1 == quat(1) # Both `quat(1)` and `complex(1)` are equal to `1`.
```

See [issue#62](https://github.com/JuliaGeometry/Quaternions.jl/issues/62) for more discussion.
61 changes: 61 additions & 0 deletions docs/src/examples/type_parameter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# The type parameter `T` in `Quaternion{T}`

The type parameter `T <: Real` in `Quaternion{T}` represents the type of real and imaginary parts of a quaternion.

## Lipschitz quaternions
By using this type parameter, some special quaternions such as [**Lipschitz quaternions**](https://en.wikipedia.org/wiki/Hurwitz_quaternion) ``L`` can be represented.

```math
L = \left\{a+bi+cj+dk \in \mathbb{H} \mid a,b,c,d \in \mathbb{Z}\right\}
```

```@setup LipschitzHurwitz
using Quaternions
```

```@repl LipschitzHurwitz
q1 = Quaternion{Int}(1,2,3,4)
q2 = Quaternion{Int}(5,6,7,8)
islipschitz(q::Quaternion) = isinteger(q.s) & isinteger(q.v1) & isinteger(q.v2) & isinteger(q.v3)
islipschitz(q1)
islipschitz(q2)
islipschitz(q1 + q2)
islipschitz(q1 * q2)
islipschitz(q1 / q2) # Division is not defined on L.
q1 * q2 == q2 * q1 # non-commutative
```

## Hurwitz quaternions
If all coefficients of a quaternion are integers or half-integers, the quaternion is called a [**Hurwitz quaternion**](https://en.wikipedia.org/wiki/Hurwitz_quaternion).
The set of Hurwitz quaternions is defined by

```math
H = \left\{a+bi+cj+dk \in \mathbb{H} \mid a,b,c,d \in \mathbb{Z} \ \text{or} \ a,b,c,d \in \mathbb{Z} + \tfrac{1}{2}\right\}.
```

Hurwitz quaternions can be implemented with [HalfIntegers.jl](https://github.com/sostock/HalfIntegers.jl) package.

```@repl LipschitzHurwitz
using HalfIntegers
q1 = Quaternion{HalfInt}(1, 2, 3, 4)
q2 = Quaternion{HalfInt}(5.5, 6.5, 7.5, 8.5)
q3 = Quaternion{HalfInt}(1, 2, 3, 4.5) # not Hurwitz quaternion
ishalfodd(x::Number) = isodd(twice(x)) # Should be defined in HalfIntegers.jl (HalfIntegers.jl#59)
ishurwitz(q::Quaternion) = (isinteger(q.s) & isinteger(q.v1) & isinteger(q.v2) & isinteger(q.v3)) | (ishalfodd(q.s) & ishalfodd(q.v1) & ishalfodd(q.v2) & ishalfodd(q.v3))
ishurwitz(q1)
ishurwitz(q2)
ishurwitz(q3)
ishurwitz(q1 + q2)
ishurwitz(q1 * q2)
ishurwitz(q1 / q2) # Division is not defined on H.
q1 * q2 == q2 * q1 # non-commucative
abs2(q1) # Squared norm is always an integer.
abs2(q2) # Squared norm is always an integer.
abs2(q3) # Squared norm is not an integer because `q3` is not Hurwitz quaternion.
```

## Biquaternions
If all coefficients of a quaternion are complex numbers, the quaternion is called a [**Biquaternion**](https://en.wikipedia.org/wiki/Biquaternion).
However, the type parameter `T` is restricted to `<:Real`, so biquaternions are not supported in this package.
Note that `Base.Complex` has the same type parameter restriction, and [bicomplex numbers](https://en.wikipedia.org/wiki/Bicomplex_number) are not supported in Base.
See [issue#79](https://github.com/JuliaGeometry/Quaternions.jl/issues/79) for more discussion.
9 changes: 5 additions & 4 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ pkg> add Quaternions

```@repl
using Quaternions
q = quat(0.0, 0.0, 0.0, 1.0)
r = quat(0, 0, 1, 0)
q*r
q+r
k = quat(0, 0, 0, 1)
j = quat(0, 0, 1, 0)
i = j*k
i^2 == j^2 == k^2 == i*j*k == -1 # Similar to `im^2`.
1 + i + k + j # Compatible with arithmetic operations as a `Number`.
```

0 comments on commit 6d90f17

Please sign in to comment.