Skip to content

Commit

Permalink
begin SVD docs example
Browse files Browse the repository at this point in the history
  • Loading branch information
fkastner committed Mar 8, 2020
1 parent 1605f46 commit bf8dd0a
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 34 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
docs/build/
test/Manifest.toml
*~
*.log
*.jl.cov
Expand Down
6 changes: 0 additions & 6 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,3 @@ version = "0.1.0"

[deps]
Primes = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@
This package implements a number type to represent numbers you can safely give to
your students to work with.

The goal is that when common linear algebra or numerical algorithms work using `NiceNumber`s
that then one can be sure that the algorithm can be reasonably easy worked through by hand
with the given numbers.

Nice numbers as implemented in this package consist of a rational part and a square root part with
a rational coefficient. Thus every `NiceNumber` is specified using two `Rational{Int}`s and one `Int`.

## Installation

Since this package isn't registered yet, you have to use the GitHub URL of the repository:
```julia
```jldoctest readme
(v1.3) pkg> add https://github.com/fkastner/NiceNumbers.jl
```

## Usage Example

```julia
```jldoctest readme
julia> using NiceNumbers
julia> n = NiceNumber(1,2,3);
Expand Down
11 changes: 4 additions & 7 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ using Documenter, NiceNumbers
makedocs(
sitename = "NiceNumbers.jl",
modules = [NiceNumbers],
pages = [
"Home" => "index.md"
],
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true")
pages = ["Home" => "index.md",
"Example: SVD" => "example_svd.md"],
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
)

deploydocs(
repo = "github.com/fkastner/NiceNumbers.jl.git"
)
deploydocs(repo = "github.com/fkastner/NiceNumbers.jl.git")
85 changes: 85 additions & 0 deletions docs/src/example_svd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Example: SVD
*Building an SVD exercise*

In this example we want to see how we can use `NiceNumber`s to construct an exercise for a
singular value decomposition.

## The Math
For a given matrix ``A\in\mathbb{R}^{m\times n}``, ``m\geq n``, we try to find a decomposition of the form
```math
A = U(\Sigma 0)^\top V^\top
```
where `U` and `V` are orthogonal (or unitary) square matrices.

## Using NiceNumbers to build the exercise
Load the relevant packages:
```jldoctest SVD
julia> using NiceNumbers, LinearAlgebra
```

Decide on an orthogonal basis in ``\mathbb{R}^m`` (here ``m=3``)
```jldoctest SVD
julia> u1 = NiceNumber.([3,12,4])
3-element Array{NiceNumber,1}:
3//1
12//1
4//1
julia> u2 = NiceNumber.([-4,0,3])
3-element Array{NiceNumber,1}:
-4//1
0//1
3//1
julia> u3 = cross(u1,u2)
3-element Array{NiceNumber,1}:
36//1
-25//1
48//1
```
and take note of their norms
```jldoctest SVD
julia> n1 = Int(norm(u1))
13
julia> n2 = Int(norm(u2))
5
julia> n3 = Int(norm(u3))
65
julia> n3 == n1*n2
true
```

```jldoctest SVD
julia> U = 1//n3 * [u1*n2 u2*n1 u3]
3×3 Array{NiceNumber,2}:
3//13 -4//5 36//65
12//13 0//1 -5//13
4//13 3//5 48//65
julia> V = 1//5* NiceNumber.([-3 4;4 3])
2×2 Array{NiceNumber,2}:
-3//5 4//5
4//5 3//5
julia> Σ = diagm(NiceNumber.([13,5]))
2×2 Array{NiceNumber,2}:
13//1 0//1
0//1 5//1
julia> S = [Σ;0 0]
3×2 Array{NiceNumber,2}:
13//1 0//1
0//1 5//1
0//1 0//1
julia> R = pinv(S)
2×3 Array{NiceNumber,2}:
1//13 0//1 0//1
0//1 1//5 0//1
julia> A = U*S*V'
3×2 Array{NiceNumber,2}:
-5//1 0//1
-36//5 48//5
0//1 5//1
julia> A⁺ = V*R*U'
2×3 Array{NiceNumber,2}:
-2929//21125 -36//845 1728//21125
-1728//21125 48//845 1921//21125
```
11 changes: 10 additions & 1 deletion src/NiceNumbers.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module NiceNumbers

import Primes: factor, prodfactors
import Base: +, -, *, /, inv, one, zero, isinteger
import Base: +, -, *, inv, /, sqrt, <, one, zero, isinteger, isfinite
import Base.promote_rule

export NiceNumber
Expand All @@ -27,6 +27,8 @@ struct NiceNumber <: Real
new(a, coeff, radicand)
end
end
NiceNumber(a, coeff, radicand::Rational) =
NiceNumber(a, coeff // denominator(radicand), numerator(radicand) * denominator(radicand))
NiceNumber(x::T) where {T<:Union{Integer,Rational}} = NiceNumber(x, 0, 0)
NiceNumber(n::NiceNumber) = n

Expand All @@ -49,9 +51,12 @@ one(::NiceNumber) = NiceNumber(1, 0, 0)
zero(::NiceNumber) = NiceNumber(0, 0, 0)

AbstractFloat(n::NiceNumber) = float(n.a) + float(n.coeff) * n.radicand
(::Type{T})(n::NiceNumber) where {T<:AbstractFloat} =
convert(T, n.a) + convert(T, n.coeff) * convert(T, n.radicand)

isrational(n::NiceNumber) = n.coeff == 0
isinteger(n::NiceNumber) = isrational(n) && isinteger(n.a)
isfinite(n::NiceNumber) = isfinite(n.a) && isfinite(n.coeff)

function Base.show(io::IO, n::NiceNumber)
if isrational(n)
Expand Down Expand Up @@ -85,4 +90,8 @@ end
inv(n::NiceNumber) = NiceNumber(n.a, -n.coeff, n.radicand) * inv(n.a^2 - n.coeff^2 * n.radicand)
/(n::NiceNumber, m::NiceNumber) = n * inv(m)

sqrt(n::NiceNumber) = isrational(n) ? NiceNumber(0, 1, n.a) : error("That's not nice anymore!")

<(n::NiceNumber, m::NiceNumber) = float(n) < float(m)

end # module
3 changes: 3 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
54 changes: 36 additions & 18 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,48 +1,66 @@
using NiceNumbers
using Test
using Test, LinearAlgebra


@testset "NiceNumbers" begin
@testset "Constructors" begin
@test NiceNumber(8) == NiceNumber(8, 0, 0)
@test NiceNumber(2, 3, 4) == NiceNumber(8)
@test NiceNumber(2, 3, 0) == NiceNumber(2)
@test NiceNumber(2, 0, 5) == NiceNumber(2)
@test NiceNumber(8) === NiceNumber(8, 0, 0)
@test NiceNumber(2, 3, 4) === NiceNumber(8)
@test NiceNumber(2, 3, 0) === NiceNumber(2)
@test NiceNumber(2, 0, 5) === NiceNumber(2)
@test NiceNumber(0, 1, 1 // 5) === NiceNumber(0, 1 // 5, 5)
end

n = NiceNumber(2, 3, 5)
m = NiceNumber(5, -3, 5)
k = NiceNumber(8, 4, 3)

@testset "Basic Arithmetic" begin
@test n + m == NiceNumber(7)
@test n + m === NiceNumber(7)
@test_broken n + k
@test n - m == NiceNumber(-3, 6, 5)
@test n - m === NiceNumber(-3, 6, 5)
@test_broken n - k
@test n * m == NiceNumber(-35, 9, 5)
@test n * m === NiceNumber(-35, 9, 5)
@test_broken n * k
@test n / m == NiceNumber(-11 // 4, -21 // 20, 5)
@test n / m === NiceNumber(-11 // 4, -21 // 20, 5)
@test_broken n / k
end

@testset "Scalar Arithmetic" begin
@test +n == n
@test -n == NiceNumber(-2, -3, 5)
@test 4 + n == n + 4 == NiceNumber(6, 3, 5)
@test 4 - n == -(n - 4) == NiceNumber(2, -3, 5)
@test 3 * n == n * 3 == NiceNumber(6, 9, 5)
@test n / 3 == inv(3 / n) == NiceNumber(2 // 3, 1, 5)
@test +n === n
@test -n === NiceNumber(-2, -3, 5)
@test 4 + n === n + 4 === NiceNumber(6, 3, 5)
@test 4 - n === -(n - 4) === NiceNumber(2, -3, 5)
@test 3 * n === n * 3 === NiceNumber(6, 9, 5)
@test n / 3 === inv(3 / n) === NiceNumber(2 // 3, 1, 5)
@test sqrt(NiceNumber(9)) === NiceNumber(3)
end

@testset "Comparisons" begin
@test NiceNumber(7) < NiceNumber(42)
@test NiceNumber(7) < NiceNumber(7, 1, 2)
@test NiceNumber(5, 1, 2) < 7
@test NiceNumber(5, 1, 2) > 5
@test NiceNumber(13, 3, 7) == 13 + 3 * 7
end

@testset "Conversion" begin
@test float(NiceNumber(13, 3, 7)) == 13 + 3 * 7
@test NiceNumber(n) == n
@test float(NiceNumber(13, 3, 7)) == 13 + 3 * 7
@test Float64(NiceNumber(13, 3, 7)) == 13 + 3 * 7
end

@testset "Linear Algebra" begin
@test true
end

@testset "Misc" begin
@test isrational(NiceNumber(139 // 7, 0, 17))
@test isinteger(NiceNumber(12))
@test one(n) == one(NiceNumber) == NiceNumber(1)
@test zero(n) == zero(NiceNumber) == NiceNumber(0)
@test isfinite(NiceNumber(12))
@test !isfinite(NiceNumber(1 // 0, 7, 7))
@test !isfinite(NiceNumber(7, 1 // 0, 7))
@test one(n) === one(NiceNumber) === NiceNumber(1)
@test zero(n) === zero(NiceNumber) === NiceNumber(0)
end
end

0 comments on commit bf8dd0a

Please sign in to comment.