Repository: hyrodium/BasicBSpline.jl
Pull request #119 (2021-12-28 05:03:14)

Rename `Knots` to `KnotVector`


Patch:
diff --git a/README.md b/README.md
index 9f8bfbd4..93fb5c50 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ using BasicBSpline
 using Plots
 gr()
 
-k = Knots([0.00,1.50,2.50,5.50,8.00,9.00,9.50,10.0])
+k = KnotVector([0.00,1.50,2.50,5.50,8.00,9.00,9.50,10.0])
 P0 = BSplineSpace(0,k) # 0th degree piecewise polynomial space
 P1 = BSplineSpace(1,k) # 1st degree piecewise polynomial space
 P2 = BSplineSpace(2,k) # 2nd degree piecewise polynomial space
@@ -81,7 +81,7 @@ using BasicBSpline
 using ExportNURBS
 
 p = 2 # degree of polynomial
-k = Knots(1:8) # knot vector
+k = KnotVector(1:8) # knot vector
 P = BSplineSpace(p,k) # B-spline space
 rand_a = [rand(2) for i in 1:dim(P), j in 1:dim(P)]
 a = [[2*i-6.5,2*j-6.5] for i in 1:dim(P), j in 1:dim(P)] + rand_a # random generated control points
@@ -93,7 +93,7 @@ save_png("2dim.png", M) # save image
 ### Refinement
 #### h-refinemnet
 ```julia
-k₊=[Knots(3.3,4.2),Knots(3.8,3.2,5.3)] # additional knots
+k₊=[KnotVector(3.3,4.2),KnotVector(3.8,3.2,5.3)] # additional knots
 M′ = refinement(M,k₊=k₊) # refinement of B-spline manifold
 save_png("2dim_h-refinement.png", M′) # save image
 ```
@@ -116,8 +116,8 @@ Note that this shape and the last shape are identical.
 ```julia
 p1 = 2
 p2 = 2
-k1 = Knots(-10:10)+p1*Knots(-10,10)
-k2 = Knots(-10:10)+p2*Knots(-10,10)
+k1 = KnotVector(-10:10)+p1*KnotVector(-10,10)
+k2 = KnotVector(-10:10)+p2*KnotVector(-10,10)
 P1 = FastBSplineSpace(p1, k1)
 P2 = FastBSplineSpace(p2, k2)
 
@@ -134,8 +134,8 @@ If the knots span is too coarse, the approximation will be coarse.
 ```julia
 p1 = 2
 p2 = 2
-k1 = Knots(-10:5:10)+p1*Knots(-10,10)
-k2 = Knots(-10:5:10)+p2*Knots(-10,10)
+k1 = KnotVector(-10:5:10)+p1*KnotVector(-10,10)
+k2 = KnotVector(-10:5:10)+p2*KnotVector(-10,10)
 P1 = FastBSplineSpace(p1, k1)
 P2 = FastBSplineSpace(p2, k2)
 
@@ -150,7 +150,7 @@ save_png("fitting_coarse.png", M, unitlength=50, up=10, down=-10, left=-10, righ
 ### Draw smooth vector graphics
 ```julia
 p = 3
-k = Knots(range(-2π,2π,length=8))+p*Knots(-2π,2π)
+k = KnotVector(range(-2π,2π,length=8))+p*KnotVector(-2π,2π)
 P = FastBSplineSpace(p, k)
 
 f(u) = [u,sin(u)]
diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl
index 3f13abeb..0b6d54bb 100644
--- a/benchmark/benchmarks.jl
+++ b/benchmark/benchmarks.jl
@@ -8,7 +8,7 @@ const SUITE = BenchmarkGroup()
 Random.seed!(42)
 
 p = 3
-k = Knots(rand(100)) + (p+1) * Knots(0,1)
+k = KnotVector(rand(100)) + (p+1) * KnotVector(0,1)
 P = FastBSplineSpace(p,k)
 i = 1
 t = 0.02
@@ -16,14 +16,14 @@ t = 0.02
 SUITE["fast-bsplinebasis"] = @benchmarkable bsplinebasis(i,P,t)
 
 p1 = 2
-k1 = Knots(rand(3)) + (p1 + 1) * Knots([0, 1])
+k1 = KnotVector(rand(3)) + (p1 + 1) * KnotVector([0, 1])
 P1 = FastBSplineSpace(p1, k1)
 n1 = dim(P1)
 a = [Point(i1, rand()) for i1 in 1:n1]
 M = BSplineCurve([P1], a)
 
 p1′ = p1 + 1
-k1′ = k1 + unique(k1) + Knots(rand(2))
+k1′ = k1 + unique(k1) + KnotVector(rand(2))
 P1′ = FastBSplineSpace(p1′, k1′)
 M′ = refinement(M, [P1′])
 
diff --git a/docs/src/benchmark.md b/docs/src/benchmark.md
index 8c374022..e3f449ea 100644
--- a/docs/src/benchmark.md
+++ b/docs/src/benchmark.md
@@ -79,7 +79,7 @@ knotvector = sort(rand(10)) # Vector{Float64} with 10 elements
 p = 3
 i = 1
 t = 0.2
-k = Knots(knotvector)
+k = KnotVector(knotvector)
 P = BSplineSpace(p,k)
 @benchmark bsplinebasis(i,P,t)
 ```
@@ -97,7 +97,7 @@ knotvector = sort(rand(10)) # Vector{Float64} with 10 elements
 p = 3
 i = 1
 t = 0.2
-k = Knots(knotvector)
+k = KnotVector(knotvector)
 P = FastBSplineSpace(p,k)
 @benchmark bsplinebasis(i,P,t)
 ```
diff --git a/docs/src/bsplineexport.jl b/docs/src/bsplineexport.jl
index 1162f236..b95fa721 100644
--- a/docs/src/bsplineexport.jl
+++ b/docs/src/bsplineexport.jl
@@ -6,7 +6,7 @@ Random.seed!(2)
 
 ## 1-dim B-spline manifold
 p = 2 # degree of polynomial
-k = Knots(1:12) # knot vector
+k = KnotVector(1:12) # knot vector
 P = FastBSplineSpace(p, k) # B-spline space
 a = [[i-5, 3*sin(i^2)] for i in 1:dim(P)] # control points
 M = BSplineCurve([P], a) # Define B-spline manifold
@@ -14,7 +14,7 @@ save_png("docs/src/img/1dim.png", M, unitlength = 50)
 
 ## 2-dim B-spline manifold
 p = 2 # degree of polynomial
-k = Knots(1:8) # knot vector
+k = KnotVector(1:8) # knot vector
 P = BSplineSpace(p, k) # B-spline space
 rand_a = [rand(2) for i in 1:dim(P), j in 1:dim(P)]
 a = [[2 * i - 6.5, 2 * j - 6.5] for i in 1:dim(P), j in 1:dim(P)] + rand_a # random generated control points
@@ -22,7 +22,7 @@ M = BSplineManifold([P, P], a) # Define B-spline manifold
 save_png("docs/src/img/2dim.png", M, unitlength = 50)
 
 ## h-Refinement
-k₊ = [Knots(3.3, 4.2), Knots(3.8, 3.2, 5.3)]
+k₊ = [KnotVector(3.3, 4.2), KnotVector(3.8, 3.2, 5.3)]
 M′ = refinement(M, k₊ = k₊)
 save_png("docs/src/img/2dim_h-refinement.png", M′, unitlength = 50)
 
@@ -44,8 +44,8 @@ save("docs/src/img/2dim_makie.png", scene)
 ## Fitting
 p1 = 2
 p2 = 2
-k1 = Knots(-10:10) + p1 * Knots(-10, 10)
-k2 = Knots(-10:10) + p2 * Knots(-10, 10)
+k1 = KnotVector(-10:10) + p1 * KnotVector(-10, 10)
+k2 = KnotVector(-10:10) + p2 * KnotVector(-10, 10)
 P1 = FastBSplineSpace(p1, k1)
 P2 = FastBSplineSpace(p2, k2)
 
@@ -58,8 +58,8 @@ save_png("docs/src/img/fitting.png", M, unitlength = 50, up = 10, down = -10, le
 ## Coarse fitting
 p1 = 2
 p2 = 2
-k1 = Knots(-10:5:10) + p1 * Knots(-10, 10)
-k2 = Knots(-10:5:10) + p2 * Knots(-10, 10)
+k1 = KnotVector(-10:5:10) + p1 * KnotVector(-10, 10)
+k2 = KnotVector(-10:5:10) + p2 * KnotVector(-10, 10)
 P1 = FastBSplineSpace(p1, k1)
 P2 = FastBSplineSpace(p2, k2)
 
@@ -71,7 +71,7 @@ save_png("docs/src/img/fitting_coarse.png", M, unitlength = 50, up = 10, down =
 
 ## Sine curve
 p = 3
-k = Knots(range(-2π, 2π, length = 8)) + p * Knots(-2π, 2π)
+k = KnotVector(range(-2π, 2π, length = 8)) + p * KnotVector(-2π, 2π)
 P = FastBSplineSpace(p, k)
 
 f(u) = [u, sin(u)]
diff --git a/docs/src/bsplineplots.jl b/docs/src/bsplineplots.jl
index f6ceb875..c4771c09 100644
--- a/docs/src/bsplineplots.jl
+++ b/docs/src/bsplineplots.jl
@@ -4,43 +4,43 @@ gr()
 
 ##
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace(p, k)
 plot([t -> bsplinebasis₊₀(P, i, t) for i in 1:dim(P)], 1, 8, ylims = (0, 1))
 savefig("docs/src/img/bsplinebasisplot.png")
 
 ##
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace(p, k)
 plot([t -> bsplinebasis′₊₀(P, i, t) for i in 1:dim(P)], 1, 8)
 savefig("docs/src/img/bsplinebasisderivativeplot.png")
 
 ##
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace(p, k)
 plot(t -> sum(bsplinebasis₊₀(P, i, t) for i in 1:dim(P)), 1, 8, ylims = (0, 1))
 savefig("docs/src/img/sumofbsplineplot.png")
 
 ##
 p = 2
-k = Knots(1:8) + p * Knots([1, 8])
+k = KnotVector(1:8) + p * KnotVector([1, 8])
 P = BSplineSpace(p, k)
 plot(t -> sum(bsplinebasis₊₀(P, i, t) for i in 1:dim(P)), 1, 8, ylims = (0, 1))
 savefig("docs/src/img/sumofbsplineplot2.png")
 
 ##
 p = 2
-k = Knots(1:8) + p * Knots([1, 8])
+k = KnotVector(1:8) + p * KnotVector([1, 8])
 P = BSplineSpace(p, k)
 plot(t -> sum(bsplinebasis(P, i, t) for i in 1:dim(P)), 1, 8, ylims = (0, 1))
 savefig("docs/src/img/sumofbsplineplot3.png")
 
 ##
-P1 = BSplineSpace(1, Knots([1, 3, 5, 8]))
-P2 = BSplineSpace(1, Knots([1, 3, 5, 6, 8, 9]))
-P3 = BSplineSpace(2, Knots([1, 1, 3, 3, 5, 5, 8, 8]))
+P1 = BSplineSpace(1, KnotVector([1, 3, 5, 8]))
+P2 = BSplineSpace(1, KnotVector([1, 3, 5, 6, 8, 9]))
+P3 = BSplineSpace(2, KnotVector([1, 1, 3, 3, 5, 5, 8, 8]))
 plot([t -> bsplinebasis₊₀(P1, i, t) for i in 1:dim(P1)], 1, 9, ylims = (0, 1))
 savefig("docs/src/img/bsplineplotP1.png")
 plot([t -> bsplinebasis₊₀(P2, i, t) for i in 1:dim(P2)], 1, 9, ylims = (0, 1))
@@ -72,7 +72,7 @@ savefig("docs/src/img/subbsplineplot2.png")
 
 ##
 p = 3
-k = Knots([0.00, 1.50, 2.50, 5.50, 8.00, 9.00, 9.50, 10.0])
+k = KnotVector([0.00, 1.50, 2.50, 5.50, 8.00, 9.00, 9.50, 10.0])
 P0 = FastBSplineSpace(0, k)
 P1 = FastBSplineSpace(1, k)
 P2 = FastBSplineSpace(2, k)
diff --git a/docs/src/math.md b/docs/src/math.md
index ea6098ff..7c3c76d9 100644
--- a/docs/src/math.md
+++ b/docs/src/math.md
@@ -31,35 +31,35 @@ using BasicBSpline
 [TODO: fig]
 
 ```@docs
-Knots
+KnotVector
 ```
 
 ```@docs
-Knots(knot::Real)
+KnotVector(knot::Real)
 ```
 
 ```@docs
-length(k::Knots)
+length(k::KnotVector)
 ```
 
 Although a knot vector is **not** a vector in linear algebra, but we introduce **additional operator** ``+``.
 
 ```@docs
-Base.:+(k1::Knots{T}, k2::Knots{T}) where T
+Base.:+(k1::KnotVector{T}, k2::KnotVector{T}) where T
 ```
 
 And **product operator** ``\cdot``.
 
 ```@docs
-*(n::Integer, k::Knots)
+*(n::Integer, k::KnotVector)
 ```
 
 ```@docs
-unique(k::Knots)
+unique(k::KnotVector)
 ```
 
 ```@docs
-𝔫(k::Knots, t::Real)
+𝔫(k::KnotVector, t::Real)
 ```
 
 
@@ -108,7 +108,7 @@ Note that each element of the space ``\mathcal{P}[p,k]`` is a piecewise polynomi
 
 ```@repl math
 p = 2
-k = Knots([1,3,5,6,8,9])
+k = KnotVector([1,3,5,6,8,9])
 BSplineSpace{p}(k)
 ```
 
@@ -129,7 +129,7 @@ The B-spline space is a linear space, and if a B-spline space is proper, its dim
 ```
 
 ```@repl math
-dim(BSplineSpace{2}(Knots([1,3,5,6,8,9])))
+dim(BSplineSpace{2}(KnotVector([1,3,5,6,8,9])))
 ```
 
 ```@docs
@@ -163,7 +163,7 @@ dim
 ```@repl math
 using Plots
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace{p}(k)
 plot([t->bsplinebasis₊₀(P,i,t) for i in 1:dim(P)], 1, 8, ylims=(0,1))
 ```
@@ -186,7 +186,7 @@ You can choose the first terms in different ways.
 ```@repl math
 using Plots
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace{p}(k)
 plot([t->bsplinebasis₋₀(P,i,t) for i in 1:dim(P)], 1, 8, ylims=(0,1))
 ```
@@ -204,7 +204,7 @@ plot([t->bsplinebasis₋₀(P,i,t) for i in 1:dim(P)], 1, 8, ylims=(0,1))
 
 ```@repl math
 i = 2
-k = Knots([5,12,13,13,14])
+k = KnotVector([5,12,13,13,14])
 p = 2
 P = BSplineSpace{p}(k)
 bsplinesupport(P) # [5..13, 12..14]
@@ -226,7 +226,7 @@ bsplinesupport(P,i) # 12..14
 ```@repl math
 using Plots
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace{p}(k)
 plot([t->bsplinebasis′₊₀(P,i,t) for i in 1:dim(P)], 1, 8, ylims=(0,1))
 ```
@@ -245,7 +245,7 @@ plot([t->bsplinebasis′₊₀(P,i,t) for i in 1:dim(P)], 1, 8, ylims=(0,1))
 ```@repl math
 using Plots
 p = 2
-k = Knots(1:8)
+k = KnotVector(1:8)
 P = BSplineSpace{p}(k)
 plot(t->sum(bsplinebasis₊₀(P,i,t) for i in 1:dim(P)), 1, 8, ylims=(0,1))
 ```
@@ -257,7 +257,7 @@ To satisfy the partition of unity on whole interval ``[1,8]``, sometimes more kn
 ```@repl math
 using Plots
 p = 2
-k = Knots(1:8) + p * Knots([1,8])
+k = KnotVector(1:8) + p * KnotVector([1,8])
 P = BSplineSpace{p}(k)
 plot(t->sum(bsplinebasis₊₀(P,i,t) for i in 1:dim(P)), 1, 8, ylims=(0,1))
 ```
@@ -282,7 +282,7 @@ Therefore, to satisfy partition of unity on closed interval ``[k_{p+1}, k_{l-p}]
 ```@repl math
 using Plots
 p = 2
-k = Knots(1:8) + p * Knots([1,8])
+k = KnotVector(1:8) + p * KnotVector([1,8])
 P = BSplineSpace{p}(k)
 plot(t->sum(bsplinebasis(P,i,t) for i in 1:dim(P)), 1, 8, ylims=(0,1))
 ```
@@ -302,9 +302,9 @@ plot(t->sum(bsplinebasis(P,i,t) for i in 1:dim(P)), 1, 8, ylims=(0,1))
 (as linear subspace..)
 
 ```@repl math
-P1 = BSplineSpace{1}(Knots([1,3,5,8]))
-P2 = BSplineSpace{1}(Knots([1,3,5,6,8,9]))
-P3 = BSplineSpace{2}(Knots([1,1,3,3,5,5,8,8]))
+P1 = BSplineSpace{1}(KnotVector([1,3,5,8]))
+P2 = BSplineSpace{1}(KnotVector([1,3,5,6,8,9]))
+P3 = BSplineSpace{2}(KnotVector([1,1,3,3,5,5,8,8]))
 P1 ⊆ P2 # true
 P1 ⊆ P3 # true
 P2 ⊆ P3 # false
@@ -315,9 +315,9 @@ Here are plots of the B-spline basis functions of the spaces `P1`, `P2`, `P3`.
 
 ```@repl math
 using Plots
-P1 = BSplineSpace{1}(Knots([1,3,5,8]))
-P2 = BSplineSpace{1}(Knots([1,3,5,6,8,9]))
-P3 = BSplineSpace{2}(Knots([1,1,3,3,5,5,8,8]))
+P1 = BSplineSpace{1}(KnotVector([1,3,5,8]))
+P2 = BSplineSpace{1}(KnotVector([1,3,5,6,8,9]))
+P3 = BSplineSpace{2}(KnotVector([1,1,3,3,5,5,8,8]))
 plot(
     plot([t->bsplinebasis₊₀(P1,i,t) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
     plot([t->bsplinebasis₊₀(P2,i,t) for i in 1:dim(P2)], 1, 9, ylims=(0,1), legend=false),
@@ -383,8 +383,8 @@ B-spline manifold is a parametric representation of a shape.
 We will also write ``\bm{p}(t^1,\dots,t^d; \bm{a})``, ``\bm{p}(t^1,\dots,t^d)``, ``\bm{p}(t; \bm{a})`` or ``\bm{p}(t)`` for simplicity.
 
 ```@repl math
-P1 = BSplineSpace{1}(Knots([0,0,1,1]))
-P2 = BSplineSpace{1}(Knots([1,1,2,3,3]))
+P1 = BSplineSpace{1}(KnotVector([0,0,1,1]))
+P2 = BSplineSpace{1}(KnotVector([1,1,2,3,3]))
 n1 = dim(P1) # 2
 n2 = dim(P2) # 3
 a = [[i, j] for i in 1:n1, j in 1:n2]  # n1 × n2 array of d̂ array.
@@ -396,7 +396,7 @@ M = BSplineManifold([P1, P2], a)
 ```@repl math
 ## 1-dim B-spline manifold
 p = 2 # degree of polynomial
-k = Knots(1:12) # knot vector
+k = KnotVector(1:12) # knot vector
 P = BSplineSpace{p}(k) # B-spline space
 a = [[i-5, 3*sin(i^2)] for i in 1:dim(P)] # control points
 M = BSplineCurve([P], a) # Define B-spline manifold
@@ -408,7 +408,7 @@ save_png("1dim.png", M, unitlength = 50)
 ### B-spline surface
 ```@repl math
 p = 2 # degree of polynomial
-k = Knots(1:8) # knot vector
+k = KnotVector(1:8) # knot vector
 P = BSplineSpace{p}(k) # B-spline space
 rand_a = [rand(2) for i in 1:dim(P), j in 1:dim(P)]
 a = [[2*i-6.5,2*j-6.5] for i in 1:dim(P), j in 1:dim(P)] + rand_a # random generated control points
@@ -444,7 +444,7 @@ save("2dim_makie.png", scene)
 Insert additional knots to knot vector.
 
 ```@repl math
-k₊=[Knots(3.3,4.2),Knots(3.8,3.2,5.3)] # additional knots
+k₊=[KnotVector(3.3,4.2),KnotVector(3.8,3.2,5.3)] # additional knots
 M′ = refinement(M,k₊=k₊) # refinement of B-spline manifold
 save_png("2dim_h-refinement.png", M′) # save image
 ```
@@ -473,8 +473,8 @@ Least squares method.
 ```@repl math
 p1 = 2
 p2 = 2
-k1 = Knots(-10:10)+p1*Knots(-10,10)
-k2 = Knots(-10:10)+p2*Knots(-10,10)
+k1 = KnotVector(-10:10)+p1*KnotVector(-10,10)
+k2 = KnotVector(-10:10)+p2*KnotVector(-10,10)
 P1 = BSplineSpace{p1}(k1)
 P2 = BSplineSpace{p2}(k2)
 
diff --git a/src/BasicBSpline.jl b/src/BasicBSpline.jl
index d594ebaa..65a62d94 100644
--- a/src/BasicBSpline.jl
+++ b/src/BasicBSpline.jl
@@ -4,7 +4,7 @@ using LinearAlgebra
 using IntervalSets
 using FastGaussQuadrature
 
-export Knots, BSplineSpace, dim, ⊑, ⊒, ⋢, ⋣, ≃
+export KnotVector, BSplineSpace, dim, ⊑, ⊒, ⋢, ⋣, ≃
 export BSplineDerivativeSpace
 export BSplineManifold, CustomBSplineManifold
 export bsplinebasis₊₀, bsplinebasis₋₀, bsplinebasis
@@ -18,7 +18,7 @@ export 𝔫
 export AbstractBSplineManifold, AbstractBSplineSpace
 export fittingcontrolpoints
 
-include("_Knots.jl")
+include("_KnotVector.jl")
 include("_BSplineSpace.jl")
 include("_BSplineBasis.jl")
 include("_DerivativeSpace.jl")
diff --git a/src/_BSplineSpace.jl b/src/_BSplineSpace.jl
index 54a2a205..3aa27f59 100644
--- a/src/_BSplineSpace.jl
+++ b/src/_BSplineSpace.jl
@@ -9,10 +9,10 @@ Construct B-spline space from given polynominal degree and knot vector.
 ```
 """
 struct BSplineSpace{p, T<:Real} <: AbstractBSplineSpace{p,T}
-    knots::Knots{T}
-    global unsafe_bsplinespace(::Val{p}, k::Knots{T}) where {p,T} = new{p,T}(k)
+    knots::KnotVector{T}
+    global unsafe_bsplinespace(::Val{p}, k::KnotVector{T}) where {p,T} = new{p,T}(k)
 end
-function BSplineSpace{p}(k::Knots) where p
+function BSplineSpace{p}(k::KnotVector) where p
     # TOOD: add error handling like this:
     # throw(DomainError(p, "degree of polynominal must be non-negative"))
     unsafe_bsplinespace(Val{p}(), k)
@@ -111,10 +111,10 @@ Check if given B-spline space is proper.
 
 # Examples
 ```jldoctest
-julia> isproper(BSplineSpace{2}(Knots([1,3,5,6,8,9])))
+julia> isproper(BSplineSpace{2}(KnotVector([1,3,5,6,8,9])))
 true
 
-julia> isproper(BSplineSpace{1}(Knots([1,3,3,3,8,9])))
+julia> isproper(BSplineSpace{1}(KnotVector([1,3,3,3,8,9])))
 false
 ```
 """
@@ -170,7 +170,7 @@ end
 """
 Expand B-spline space with given additional degree and knots.
 """
-function expandspace(P::BSplineSpace{p,T}; p₊::Integer=0, k₊::Knots{T}=Knots{T}()) where {p,T}
+function expandspace(P::BSplineSpace{p,T}; p₊::Integer=0, k₊::KnotVector{T}=KnotVector{T}()) where {p,T}
     k = knots(P)
     k0 = unique(k[1+p:end-p])
     p′ = p + p₊
diff --git a/src/_ChangeBasis.jl b/src/_ChangeBasis.jl
index d8f5a766..4d75e9d3 100644
--- a/src/_ChangeBasis.jl
+++ b/src/_ChangeBasis.jl
@@ -141,11 +141,11 @@ function _changebasis_I(P::BSplineSpace{p,T}, P′::BSplineSpace{p′,T})::Matri
     k′ = knots(P′)
     p₊ = p′ - p
 
-    _P = BSplineSpace{p}(k[1+p:end-p] + p * Knots(k[1+p], k[end-p]))
+    _P = BSplineSpace{p}(k[1+p:end-p] + p * KnotVector(k[1+p], k[end-p]))
     # if dim(_P) ≠ dim(P)
     #     error("dim(_P)≠dim(P)")
     # end
-    _P′ = BSplineSpace{p′}(k′[1+p′:end-p′] + p′ * Knots(k′[1+p′], k′[end-p′]))
+    _P′ = BSplineSpace{p′}(k′[1+p′:end-p′] + p′ * KnotVector(k′[1+p′], k′[end-p′]))
     # if dim(_P′) ≠ dim(P′)
     #     error("dim(_P′)≠dim(P′)")
     # end
diff --git a/src/_Knots.jl b/src/_KnotVector.jl
similarity index 52%
rename from src/_Knots.jl
rename to src/_KnotVector.jl
index dbfa7133..35cdfa62 100644
--- a/src/_Knots.jl
+++ b/src/_KnotVector.jl
@@ -1,6 +1,6 @@
-# Knots
+# KnotVector
 
-abstract type AbstractKnots{T<:Real} end
+abstract type AbstractKnotVector{T<:Real} end
 
 @doc raw"""
 Construct knot vector from given array.
@@ -10,50 +10,50 @@ k=(k_1,\dots,k_l)
 
 # Examples
 ```jldoctest
-julia> k = Knots([1,2,3])
-Knots([1.0, 2.0, 3.0])
+julia> k = KnotVector([1,2,3])
+KnotVector([1.0, 2.0, 3.0])
 
-julia> k = Knots(1:3)
-Knots([1.0, 2.0, 3.0])
+julia> k = KnotVector(1:3)
+KnotVector([1.0, 2.0, 3.0])
 ```
 """
-struct Knots{T} <: AbstractKnots{T}
+struct KnotVector{T} <: AbstractKnotVector{T}
     vector::Vector{T}
     global unsafe_knots(::Type{T}, v) where T = new{T}(v)
 end
-Knots{T}(v::AbstractVector) where T = unsafe_knots(T,sort(v))
-Knots(v::AbstractVector{T}) where {T<:Real} = unsafe_knots(float(T),sort(v))
+KnotVector{T}(v::AbstractVector) where T = unsafe_knots(T,sort(v))
+KnotVector(v::AbstractVector{T}) where {T<:Real} = unsafe_knots(float(T),sort(v))
 
 @doc raw"""
 Construct knot vector from given real numbers.
 
 # Examples
 ```jldoctest
-julia> k = Knots(1,2,3)
-Knots([1.0, 2.0, 3.0])
+julia> k = KnotVector(1,2,3)
+KnotVector([1.0, 2.0, 3.0])
 
-julia> k = Knots()
-Knots([])
+julia> k = KnotVector()
+KnotVector([])
 ```
 """
-function Knots(knots::T...) where T<:Real
+function KnotVector(knots::T...) where T<:Real
     return unsafe_knots(float(T), sort!(collect(knots)))
 end
-function Knots{T}(knots::Real...) where T<:Real
+function KnotVector{T}(knots::Real...) where T<:Real
     return unsafe_knots(T, sort!(collect(knots)))
 end
-Knots() = unsafe_knots(Float64, Float64[])
+KnotVector() = unsafe_knots(Float64, Float64[])
 
-function Base.show(io::IO, k::Knots)
+function Base.show(io::IO, k::KnotVector)
     if k.vector == Float64[]
-        print(io, "Knots([])")
+        print(io, "KnotVector([])")
     else
-        print(io, "Knots($(k.vector))")
+        print(io, "KnotVector($(k.vector))")
     end
 end
 
-Base.zero(::Type{<:Knots}) = Knots()
-Base.:(==)(k₁::Knots, k₂::Knots) = (k₁.vector == k₂.vector)
+Base.zero(::Type{<:KnotVector}) = KnotVector()
+Base.:(==)(k₁::KnotVector, k₂::KnotVector) = (k₁.vector == k₂.vector)
 
 @doc raw"""
 Sum of knot vectors
@@ -70,17 +70,17 @@ For example, ``(1,2,3,5)+(4,5,8)=(1,2,3,4,5,5,8)``.
 
 # Examples
 ```jldoctest
-julia> k1 = Knots(1,2,3,5);
+julia> k1 = KnotVector(1,2,3,5);
 
-julia> k2 = Knots(4,5,8);
+julia> k2 = KnotVector(4,5,8);
 
 julia> k1 + k2
-Knots([1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 8.0])
+KnotVector([1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 8.0])
 ```
 """
-Base.:+(k1::Knots{T}, k2::Knots{T}) where T = unsafe_knots(T,sort!(vcat(k1.vector,k2.vector)))
+Base.:+(k1::KnotVector{T}, k2::KnotVector{T}) where T = unsafe_knots(T,sort!(vcat(k1.vector,k2.vector)))
 
-# TODO: add a method for Knots{Int} + Knots{Float64}
+# TODO: add a method for KnotVector{Int} + KnotVector{Float64}
 
 @doc raw"""
 Product of integer and knot vector
@@ -95,15 +95,15 @@ For example, ``2\cdot (1,2,2,5)=(1,1,2,2,2,2,5,5)``.
 
 # Examples
 ```jldoctest
-julia> k = Knots(1,2,2,5);
+julia> k = KnotVector(1,2,2,5);
 
 julia> 2 * k
-Knots([1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 5.0, 5.0])
+KnotVector([1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 5.0, 5.0])
 ```
 """
-function Base.:*(p₊::Integer, k::Knots)
+function Base.:*(p₊::Integer, k::KnotVector)
     if p₊ == 0
-        return zero(Knots)
+        return zero(KnotVector)
     elseif p₊ > 0
         return sum(k for _ in 1:p₊)
     else
@@ -111,25 +111,25 @@ function Base.:*(p₊::Integer, k::Knots)
     end
 end
 
-Base.in(r::Real, k::Knots) = in(r, k.vector)
-Base.getindex(k::Knots, i::Integer) = k.vector[i]
-Base.getindex(k::Knots, v::AbstractVector{<:Integer}) = Knots(k.vector[v])
+Base.in(r::Real, k::KnotVector) = in(r, k.vector)
+Base.getindex(k::KnotVector, i::Integer) = k.vector[i]
+Base.getindex(k::KnotVector, v::AbstractVector{<:Integer}) = KnotVector(k.vector[v])
 
 @doc raw"""
 Length of knot vector
 
 # Examples
 ```jldoctest
-julia> k = Knots(1,2,3,5);
+julia> k = KnotVector(1,2,3,5);
 
 julia> length(k)
 4
 ```
 """
-Base.length(k::Knots) = length(k.vector)
+Base.length(k::KnotVector) = length(k.vector)
 
-Base.firstindex(k::Knots) = 1
-Base.lastindex(k::Knots) = length(k)
+Base.firstindex(k::KnotVector) = 1
+Base.lastindex(k::KnotVector) = length(k)
 
 @doc raw"""
 Unique elements of knot vector.
@@ -145,19 +145,19 @@ For example, ``\widehat{(1,2,2,3)}=(1,2,3)``.
 
 # Examples
 ```jldoctest
-julia> k = Knots([1,2,2,3]);
+julia> k = KnotVector([1,2,2,3]);
 
 julia> unique(k)
-Knots([1.0, 2.0, 3.0])
+KnotVector([1.0, 2.0, 3.0])
 ```
 """
-Base.unique(k::Knots) = Knots(unique(k.vector))
-Base.unique!(k::Knots) = Knots(unique!(k.vector))
-Base.iterate(k::Knots) = iterate(k.vector)
-Base.iterate(k::Knots, i::Integer) = iterate(k.vector, i)
-Base.searchsortedfirst(k::Knots,t) = searchsortedfirst(k.vector,t)
-Base.searchsortedlast(k::Knots,t) = searchsortedlast(k.vector,t)
-Base.searchsorted(k::Knots,t) = searchsorted(k.vector,t)
+Base.unique(k::KnotVector) = KnotVector(unique(k.vector))
+Base.unique!(k::KnotVector) = KnotVector(unique!(k.vector))
+Base.iterate(k::KnotVector) = iterate(k.vector)
+Base.iterate(k::KnotVector, i::Integer) = iterate(k.vector, i)
+Base.searchsortedfirst(k::KnotVector,t) = searchsortedfirst(k.vector,t)
+Base.searchsortedlast(k::KnotVector,t) = searchsortedlast(k.vector,t)
+Base.searchsorted(k::KnotVector,t) = searchsorted(k.vector,t)
 
 @doc raw"""
 Check a inclusive relation ship ``k\subset k'``.
@@ -166,7 +166,7 @@ Check a inclusive relation ship ``k\subset k'``.
 (1,2,5) \nsubseteq (1,2,3,4)
 ```
 """
-function Base.issubset(k::Knots, k′::Knots)
+function Base.issubset(k::KnotVector, k′::KnotVector)
     v = k′.vector
     l = length(v)
     i = 0
@@ -188,7 +188,7 @@ For given knot vector ``k``, the following function ``\mathfrak{n}_k:\mathbb{R}\
 For example, if ``k=(1,2,2,3)``, then ``\mathfrak{n}_k(0.3)=0``, ``\mathfrak{n}_k(1)=1``, ``\mathfrak{n}_k(2)=2``.
 
 ```jldoctest
-julia> k = Knots([1,2,2,3]);
+julia> k = KnotVector([1,2,2,3]);
 
 julia> 𝔫(k,0.3)
 0
@@ -200,7 +200,7 @@ julia> 𝔫(k,2.0)
 2
 ```
 """
-function 𝔫(k::Knots, t::Real)
+function 𝔫(k::KnotVector, t::Real)
     # for small case, this is faster
     # return count(==(t), k.vector)
 
diff --git a/src/_Refinement.jl b/src/_Refinement.jl
index 5334ffd5..5ead6b35 100644
--- a/src/_Refinement.jl
+++ b/src/_Refinement.jl
@@ -77,7 +77,7 @@ end
 @doc raw"""
 Refinement of B-spline manifold with additional degree and knots.
 """
-function refinement(M::BSplineManifold{Dim}; p₊::Union{Nothing,NTuple{Dim,Int}}=nothing, k₊::Union{Nothing,NTuple{Dim,Knots{T}}}=nothing) where {Dim, T}
+function refinement(M::BSplineManifold{Dim}; p₊::Union{Nothing,NTuple{Dim,Int}}=nothing, k₊::Union{Nothing,NTuple{Dim,KnotVector{T}}}=nothing) where {Dim, T}
     Ps = bsplinespaces(M)
     if isnothing(p₊)
         p₊ = tuple(zeros(Int, Dim)...)
@@ -85,7 +85,7 @@ function refinement(M::BSplineManifold{Dim}; p₊::Union{Nothing,NTuple{Dim,Int}
         throw(DimensionMismatch())
     end
     if isnothing(k₊)
-        k₊ = tuple(zeros(Knots, Dim)...)
+        k₊ = tuple(zeros(KnotVector, Dim)...)
     elseif length(Ps) ≠ length(k₊)
         throw(DimensionMismatch())
     end
@@ -98,7 +98,7 @@ end
 @doc raw"""
 Refinement of B-spline manifold with additional degree and knots.
 """
-function refinement(M::CustomBSplineManifold; p₊::Union{Nothing,NTuple{Dim,Int}}=nothing, k₊::Union{Nothing,NTuple{Dim,Knots{T}}}=nothing) where {Dim, T}
+function refinement(M::CustomBSplineManifold; p₊::Union{Nothing,NTuple{Dim,Int}}=nothing, k₊::Union{Nothing,NTuple{Dim,KnotVector{T}}}=nothing) where {Dim, T}
     Ps = collect(bsplinespaces(M))
     d = length(Ps)
     if isnothing(p₊)
@@ -107,7 +107,7 @@ function refinement(M::CustomBSplineManifold; p₊::Union{Nothing,NTuple{Dim,Int
         throw(DimensionMismatch())
     end
     if isnothing(k₊)
-        k₊ = zeros(Knots, d)
+        k₊ = zeros(KnotVector, d)
     elseif length(Ps) ≠ length(k₊)
         throw(DimensionMismatch())
     end


Test patch:
diff --git a/test/runtests.jl b/test/runtests.jl
index 4eaf00da..908dab5e 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -6,7 +6,7 @@ using Random
 using GeometryBasics
 
 @testset "BasicBSpline.jl" begin
-    include("test_Knots.jl")
+    include("test_KnotVector.jl")
     include("test_BSplineSpace.jl")
     include("test_BSplineBasis.jl")
     include("test_Derivative.jl")
diff --git a/test/test_BSplineBasis.jl b/test/test_BSplineBasis.jl
index 3002944d..265e6a1d 100644
--- a/test/test_BSplineBasis.jl
+++ b/test/test_BSplineBasis.jl
@@ -18,7 +18,7 @@ end
         Random.seed!(42)
 
         v = rand(10)
-        k = Knots(v) + (p+1)*Knots(0, 1) + Knots(v[2], v[3])
+        k = KnotVector(v) + (p+1)*KnotVector(0, 1) + KnotVector(v[2], v[3])
         P = BSplineSpace{p}(k)
         n = dim(P)
 
@@ -63,7 +63,7 @@ end
     @testset "bsplinebasisall" begin
         Random.seed!(42)
 
-        k = Knots(rand(10).-1) + Knots(rand(10)) + Knots(rand(10).+1)
+        k = KnotVector(rand(10).-1) + KnotVector(rand(10)) + KnotVector(rand(10).+1)
         ts = rand(10)
 
         for p in 0:5
diff --git a/test/test_BSplineManifold.jl b/test/test_BSplineManifold.jl
index 0a3d247e..c88ab1d2 100644
--- a/test/test_BSplineManifold.jl
+++ b/test/test_BSplineManifold.jl
@@ -22,7 +22,7 @@
         @testset "BSplineManifold-1dim" begin
             Random.seed!(42)
 
-            P1 = BSplineSpace{1}(Knots([0, 0, 1, 1]))
+            P1 = BSplineSpace{1}(KnotVector([0, 0, 1, 1]))
             n1 = dim(P1) # 2
             ax = [i for i in 1:n1]
             ay = [rand() for i in 1:n1]
@@ -30,9 +30,9 @@
             M = BSplineManifold((P1,), a)
             @test dim(M) == 1
 
-            P1′ = BSplineSpace{2}(Knots([-2, 0, 0, 1, 1, 2]))
+            P1′ = BSplineSpace{2}(KnotVector([-2, 0, 0, 1, 1, 2]))
             p₊ = (1,)
-            k₊ = (Knots(0.3),)
+            k₊ = (KnotVector(0.3),)
 
             @test P1 ⊑ P1′
 
@@ -48,15 +48,15 @@
         @testset "CustomBSplineManifold-1dim" begin
             Random.seed!(42)
 
-            P1 = BSplineSpace{1}(Knots([0, 0, 1, 1]))
+            P1 = BSplineSpace{1}(KnotVector([0, 0, 1, 1]))
             n1 = dim(P1) # 2
             a = [Point(i, rand()) for i in 1:n1]  # n1 × n2 array of d̂-dim vector.
             M = CustomBSplineManifold((P1,), a)
             @test dim(M) == 1
 
-            P1′ = BSplineSpace{2}(Knots([-2, 0, 0, 1, 1, 2]))
+            P1′ = BSplineSpace{2}(KnotVector([-2, 0, 0, 1, 1, 2]))
             p₊ = (1,)
-            k₊ = (Knots(),)
+            k₊ = (KnotVector(),)
 
             @test P1 ⊑ P1′
 
@@ -74,8 +74,8 @@
         @testset "BSplineManifold-2dim" begin
             Random.seed!(42)
 
-            P1 = BSplineSpace{1}(Knots([0, 0, 1, 1]))
-            P2 = BSplineSpace{1}(Knots([1, 1, 2, 3, 3]))
+            P1 = BSplineSpace{1}(KnotVector([0, 0, 1, 1]))
+            P2 = BSplineSpace{1}(KnotVector([1, 1, 2, 3, 3]))
             n1 = dim(P1) # 2
             n2 = dim(P2) # 3
             rand_a = [rand(2) for i in 1:n1, j in 1:n2]
@@ -83,10 +83,10 @@
             M = BSplineManifold((P1, P2), arrayofvector2array(a))
             @test dim(M) == 2
 
-            P1′ = BSplineSpace{2}(Knots([-2, 0, 0, 1, 1, 2]))
-            P2′ = BSplineSpace{1}(Knots([-3, 1, 2, 1.45, 3, 4]))
+            P1′ = BSplineSpace{2}(KnotVector([-2, 0, 0, 1, 1, 2]))
+            P2′ = BSplineSpace{1}(KnotVector([-3, 1, 2, 1.45, 3, 4]))
             p₊ = (1, 0)
-            k₊ = (Knots(), Knots(1.45))
+            k₊ = (KnotVector(), KnotVector(1.45))
 
             @test P1 ⊑ P1′
             @test P2 ⊑ P2′
@@ -103,18 +103,18 @@
         @testset "CustomBSplineManifold-2dim" begin
             Random.seed!(42)
 
-            P1 = BSplineSpace{1}(Knots([0, 0, 1, 1]))
-            P2 = BSplineSpace{1}(Knots([1, 1, 2, 3, 3]))
+            P1 = BSplineSpace{1}(KnotVector([0, 0, 1, 1]))
+            P2 = BSplineSpace{1}(KnotVector([1, 1, 2, 3, 3]))
             n1 = dim(P1) # 2
             n2 = dim(P2) # 3
             a = [Point(i, j) for i in 1:n1, j in 1:n2]  # n1 × n2 array of d̂-dim vector.
             M = CustomBSplineManifold((P1, P2), a)
             @test dim(M) == 2
 
-            P1′ = BSplineSpace{2}(Knots([0, 0, 0, 1, 1, 1]))
-            P2′ = BSplineSpace{1}(Knots([1, 1, 2, 1.45, 3, 3]))
+            P1′ = BSplineSpace{2}(KnotVector([0, 0, 0, 1, 1, 1]))
+            P2′ = BSplineSpace{1}(KnotVector([1, 1, 2, 1.45, 3, 3]))
             p₊ = (1, 0)
-            k₊ = (Knots(), Knots(1.45))
+            k₊ = (KnotVector(), KnotVector(1.45))
 
             @test P1 ⊆ P1′
             @test P2 ⊆ P2′
diff --git a/test/test_BSplineSpace.jl b/test/test_BSplineSpace.jl
index 3416e76b..fca58143 100644
--- a/test/test_BSplineSpace.jl
+++ b/test/test_BSplineSpace.jl
@@ -1,37 +1,37 @@
 @testset "BSplineSpace" begin
     Random.seed!(42)
 
-    P1 = BSplineSpace{2}(Knots([1, 3, 5, 6, 8, 9]))
+    P1 = BSplineSpace{2}(KnotVector([1, 3, 5, 6, 8, 9]))
     @test bsplinesupport(P1, 2) == 3..8
     @test dim(P1) == 3
     @test properdim(P1) == 3
     @test isproper(P1) == true
 
-    P2 = BSplineSpace{1}(Knots([1, 3, 3, 3, 8, 9]))
+    P2 = BSplineSpace{1}(KnotVector([1, 3, 3, 3, 8, 9]))
     @test isproper(P2) == false
     @test properdim(P2) == 3
 
     i = 2
-    k = Knots([5, 12, 13, 13, 14])
+    k = KnotVector([5, 12, 13, 13, 14])
     p = 2
     P = BSplineSpace{p}(k)
     @test bsplinesupport(P) == [5..13, 12..14]
     @test bsplinesupport(P, i) == 12..14
 
-    @test isproper(BSplineSpace{2}(Knots([1, 3, 5, 6, 8, 9])))
-    @test !isproper(BSplineSpace{1}(Knots([1, 3, 3, 3, 8, 9])))
+    @test isproper(BSplineSpace{2}(KnotVector([1, 3, 5, 6, 8, 9])))
+    @test !isproper(BSplineSpace{1}(KnotVector([1, 3, 3, 3, 8, 9])))
 
-    @test dim(BSplineSpace{2}(Knots([1, 3, 5, 6, 8, 9]))) == 3
+    @test dim(BSplineSpace{2}(KnotVector([1, 3, 5, 6, 8, 9]))) == 3
 
-    P1 = BSplineSpace{1}(Knots([1, 3, 5, 8]))
-    P2 = BSplineSpace{1}(Knots([1, 3, 5, 6, 8, 9]))
-    P3 = BSplineSpace{2}(Knots([1, 1, 3, 3, 5, 5, 8, 8]))
+    P1 = BSplineSpace{1}(KnotVector([1, 3, 5, 8]))
+    P2 = BSplineSpace{1}(KnotVector([1, 3, 5, 6, 8, 9]))
+    P3 = BSplineSpace{2}(KnotVector([1, 1, 3, 3, 5, 5, 8, 8]))
     @test P1 ⊆ P2
     @test P1 ⊆ P3
     @test P2 ⊈ P3
 
-    P4 = BSplineSpace{1}(Knots([1, 2, 3, 4, 5]))
-    P5 = BSplineSpace{2}(Knots([-1, 0.3, 2, 3, 3, 4, 5.2, 6]))
+    P4 = BSplineSpace{1}(KnotVector([1, 2, 3, 4, 5]))
+    P5 = BSplineSpace{2}(KnotVector([-1, 0.3, 2, 3, 3, 4, 5.2, 6]))
     @test P4 ⊑ P4
     @test P4 ⊑ P5
     @test P5 ⊒ P4
diff --git a/test/test_ChangeBasis.jl b/test/test_ChangeBasis.jl
index 58282ea5..9462b289 100644
--- a/test/test_ChangeBasis.jl
+++ b/test/test_ChangeBasis.jl
@@ -2,9 +2,9 @@
     ε = 1e-14
     Random.seed!(42)
 
-    P1 = BSplineSpace{1}(Knots([1, 3, 5, 8]))
-    P2 = BSplineSpace{1}(Knots([1, 3, 5, 6, 8, 9]))
-    P3 = BSplineSpace{2}(Knots([1, 1, 3, 3, 5, 5, 8, 8]))
+    P1 = BSplineSpace{1}(KnotVector([1, 3, 5, 8]))
+    P2 = BSplineSpace{1}(KnotVector([1, 3, 5, 6, 8, 9]))
+    P3 = BSplineSpace{2}(KnotVector([1, 1, 3, 3, 5, 5, 8, 8]))
     @test P1 ⊆ P2
     @test P1 ⊆ P3
     @test P2 ⊈ P3
@@ -21,8 +21,8 @@
 
     p4 = 1
     p5 = 2
-    P4 = BSplineSpace{p4}(Knots([1, 2, 3, 4, 5]))
-    P5 = BSplineSpace{p5}(Knots([-1, 0.3, 2, 3, 3, 4, 5.2, 6]))
+    P4 = BSplineSpace{p4}(KnotVector([1, 2, 3, 4, 5]))
+    P5 = BSplineSpace{p5}(KnotVector([-1, 0.3, 2, 3, 3, 4, 5.2, 6]))
     @test P4 ⊑ P4
     @test P4 ⊑ P5
     @test P5 ⊒ P4
diff --git a/test/test_Derivative.jl b/test/test_Derivative.jl
index 16c9222d..b00bb31f 100644
--- a/test/test_Derivative.jl
+++ b/test/test_Derivative.jl
@@ -7,7 +7,7 @@
     # Not sure why this @testset doesn't work fine.
     # @testset "$(p)-th degree basis" for p in 0:p_max
     for p in 0:p_max
-        k = Knots(rand(20)) + (p+1)*Knots(0,1)
+        k = KnotVector(rand(20)) + (p+1)*KnotVector(0,1)
         P = BSplineSpace{p}(k)
         P0 = BSplineDerivativeSpace{0}(P)
         for t in ts, i in 1:dim(P)
@@ -63,7 +63,7 @@
     @testset "bsplinebasisall" begin
         Random.seed!(42)
 
-        k = Knots(rand(10).-1) + Knots(rand(10)) + Knots(rand(10).+1)
+        k = KnotVector(rand(10).-1) + KnotVector(rand(10)) + KnotVector(rand(10).+1)
         ts = rand(10)
 
         for p in 0:5
diff --git a/test/test_Fitting.jl b/test/test_Fitting.jl
index 32943dd0..cf3f49a8 100644
--- a/test/test_Fitting.jl
+++ b/test/test_Fitting.jl
@@ -5,13 +5,13 @@
         Random.seed!(42)
 
         p1 = 2
-        k1 = Knots(rand(3)) + (p1 + 1) * Knots([0, 1])
+        k1 = KnotVector(rand(3)) + (p1 + 1) * KnotVector([0, 1])
         P1 = BSplineSpace{p1}(k1)
         n1 = dim(P1)
         a_org = [Point(i1, rand()) for i1 in 1:n1]
         M = CustomBSplineManifold((P1,), a_org)
 
-        P1′ = expandspace(P1, p₊=1, k₊=Knots(rand(2)))
+        P1′ = expandspace(P1, p₊=1, k₊=KnotVector(rand(2)))
 
         M′ = refinement(M, (P1′,))
         a_ref = controlpoints(M′)
@@ -27,13 +27,13 @@
         Random.seed!(42)
 
         p1 = 2
-        k1 = Knots(rand(3)) + Knots([0, 1]) + p1 * Knots([-rand(), 1 + rand()])
+        k1 = KnotVector(rand(3)) + KnotVector([0, 1]) + p1 * KnotVector([-rand(), 1 + rand()])
         P1 = BSplineSpace{p1}(k1)
         n1 = dim(P1)
         a_org = [Point(i1, rand()) for i1 in 1:n1]
         M = CustomBSplineManifold((P1,), a_org)
 
-        P1′ = expandspace(P1, p₊=1, k₊=Knots(rand(2)))
+        P1′ = expandspace(P1, p₊=1, k₊=KnotVector(rand(2)))
 
         M′ = refinement(M, (P1′,))
         a_ref = controlpoints(M′)
@@ -47,18 +47,18 @@
         Random.seed!(42)
 
         p1 = 2
-        k1 = Knots(rand(3)) + (p1 + 1) * Knots([0, 1])
+        k1 = KnotVector(rand(3)) + (p1 + 1) * KnotVector([0, 1])
         P1 = BSplineSpace{p1}(k1)
         n1 = dim(P1)
         p2 = 1
-        k2 = Knots(rand(4)) + (p2 + 1) * Knots([0, 1])
+        k2 = KnotVector(rand(4)) + (p2 + 1) * KnotVector([0, 1])
         P2 = BSplineSpace{p2}(k2)
         n2 = dim(P2)
         a_org = [Point(i1, i2, rand()) for i1 in 1:n1, i2 in 1:n2]
         M = CustomBSplineManifold((P1, P2), a_org)
 
-        P1′ = expandspace(P1, p₊=1, k₊=Knots(rand(2)))
-        P2′ = expandspace(P2, p₊=1, k₊=Knots(rand(2)))
+        P1′ = expandspace(P1, p₊=1, k₊=KnotVector(rand(2)))
+        P2′ = expandspace(P2, p₊=1, k₊=KnotVector(rand(2)))
 
         M′ = refinement(M, (P1′, P2′))
         a_ref = controlpoints(M′)
@@ -74,18 +74,18 @@
         Random.seed!(42)
 
         p1 = 2
-        k1 = Knots(rand(3)) + Knots([0, 1]) + p1 * Knots([-rand(), 1 + rand()])
+        k1 = KnotVector(rand(3)) + KnotVector([0, 1]) + p1 * KnotVector([-rand(), 1 + rand()])
         P1 = BSplineSpace{p1}(k1)
         n1 = dim(P1)
         p2 = 1
-        k2 = Knots(rand(4)) + Knots([0, 1]) + p2 * Knots([-rand(), 1 + rand()])
+        k2 = KnotVector(rand(4)) + KnotVector([0, 1]) + p2 * KnotVector([-rand(), 1 + rand()])
         P2 = BSplineSpace{p2}(k2)
         n2 = dim(P2)
         a_org = [Point(i1, i2, rand()) for i1 in 1:n1, i2 in 1:n2]
         M = CustomBSplineManifold((P1, P2), a_org)
 
-        P1′ = expandspace(P1, p₊=1, k₊=Knots(rand(2)))
-        P2′ = expandspace(P2, p₊=1, k₊=Knots(rand(2)))
+        P1′ = expandspace(P1, p₊=1, k₊=KnotVector(rand(2)))
+        P2′ = expandspace(P2, p₊=1, k₊=KnotVector(rand(2)))
 
         M′ = refinement(M, (P1′, P2′))
         a_ref = controlpoints(M′)
@@ -98,23 +98,23 @@
         Random.seed!(42)
 
         p1 = 2
-        k1 = Knots(rand(3)) + (p1 + 1) * Knots([0, 1])
+        k1 = KnotVector(rand(3)) + (p1 + 1) * KnotVector([0, 1])
         P1 = BSplineSpace{p1}(k1)
         n1 = dim(P1)
         p2 = 1
-        k2 = Knots(rand(4)) + (p2 + 1) * Knots([0, 1])
+        k2 = KnotVector(rand(4)) + (p2 + 1) * KnotVector([0, 1])
         P2 = BSplineSpace{p2}(k2)
         n2 = dim(P2)
         p3 = 2
-        k3 = Knots(rand(5)) + (p3 + 1) * Knots([0, 1])
+        k3 = KnotVector(rand(5)) + (p3 + 1) * KnotVector([0, 1])
         P3 = BSplineSpace{p3}(k3)
         n3 = dim(P3)
         a_org = [Point(i1, i2, i3, rand()) for i1 in 1:n1, i2 in 1:n2, i3 in 1:n3]
         M = CustomBSplineManifold((P1, P2, P3), a_org)
 
-        P1′ = expandspace(P1, p₊=1, k₊=Knots(rand(2)))
-        P2′ = expandspace(P2, p₊=1, k₊=Knots(rand(2)))
-        P3′ = expandspace(P3, p₊=1, k₊=Knots(rand(2)))
+        P1′ = expandspace(P1, p₊=1, k₊=KnotVector(rand(2)))
+        P2′ = expandspace(P2, p₊=1, k₊=KnotVector(rand(2)))
+        P3′ = expandspace(P3, p₊=1, k₊=KnotVector(rand(2)))
 
         M′ = refinement(M, (P1′, P2′, P3′))
         a_ref = controlpoints(M′)
@@ -130,23 +130,23 @@
         Random.seed!(42)
 
         p1 = 2
-        k1 = Knots(rand(3)) + Knots([0, 1]) + p1 * Knots([-rand(), 1 + rand()])
+        k1 = KnotVector(rand(3)) + KnotVector([0, 1]) + p1 * KnotVector([-rand(), 1 + rand()])
         P1 = BSplineSpace{p1}(k1)
         n1 = dim(P1)
         p2 = 1
-        k2 = Knots(rand(4)) + Knots([0, 1]) + p1 * Knots([-rand(), 1 + rand()])
+        k2 = KnotVector(rand(4)) + KnotVector([0, 1]) + p1 * KnotVector([-rand(), 1 + rand()])
         P2 = BSplineSpace{p2}(k2)
         n2 = dim(P2)
         p3 = 2
-        k3 = Knots(rand(5)) + Knots([0, 1]) + p1 * Knots([-rand(), 1 + rand()])
+        k3 = KnotVector(rand(5)) + KnotVector([0, 1]) + p1 * KnotVector([-rand(), 1 + rand()])
         P3 = BSplineSpace{p3}(k3)
         n3 = dim(P3)
         a_org = [Point(i1, i2, i3, rand()) for i1 in 1:n1, i2 in 1:n2, i3 in 1:n3]
         M = CustomBSplineManifold((P1, P2, P3), a_org)
 
-        P1′ = expandspace(P1, p₊=1, k₊=Knots(rand(2)))
-        P2′ = expandspace(P2, p₊=1, k₊=Knots(rand(2)))
-        P3′ = expandspace(P3, p₊=1, k₊=Knots(rand(2)))
+        P1′ = expandspace(P1, p₊=1, k₊=KnotVector(rand(2)))
+        P2′ = expandspace(P2, p₊=1, k₊=KnotVector(rand(2)))
+        P3′ = expandspace(P3, p₊=1, k₊=KnotVector(rand(2)))
 
         M′ = refinement(M, (P1′, P2′, P3′))
         a_ref = controlpoints(M′)
diff --git a/test/test_KnotVector.jl b/test/test_KnotVector.jl
new file mode 100644
index 00000000..f887e595
--- /dev/null
+++ b/test/test_KnotVector.jl
@@ -0,0 +1,61 @@
+@testset "KnotVector" begin
+    k1 = KnotVector([1,2,3])
+    k2 = KnotVector([1,2,2,3])
+    k3 = KnotVector([2,4,5])
+    @testset "constructor" begin
+        @test k1 isa KnotVector{Float64}
+        @test k1 == KnotVector(1:3)::KnotVector{Float64}
+        @test k1 == KnotVector([1,3,2])::KnotVector{Float64}
+        @test k1 == KnotVector(1,2,3)::KnotVector{Float64}
+        @test k1 == KnotVector(1,3,2)::KnotVector{Float64}
+
+        @test KnotVector{Int}([1,2]) isa KnotVector{Int}
+        @test KnotVector{Int}(1,2) isa KnotVector{Int}
+    end
+
+    @testset "zeros" begin
+        @test KnotVector() == zero(KnotVector)
+        @test KnotVector() == 0*k1
+        @test KnotVector() == KnotVector(Float64[])
+    end
+
+    @testset "length" begin
+        @test length(KnotVector()) == 0
+        @test length(KnotVector([1,2,2,3])) == 4
+    end
+
+    @testset "addition, multiply" begin
+        @test KnotVector([-1,2,3]) + 2 * KnotVector([2,5]) == KnotVector([-1,2,2,2,3,5,5])
+        @test k1 + k3 == KnotVector([1,2,2,3,4,5])
+        @test 2 * KnotVector([2,3]) == KnotVector([2,2,3,3])
+    end
+
+    @testset "unique" begin
+        @test unique(k1) == k1
+        @test unique(k2) == k1
+    end
+
+    @testset "inclusive relation" begin
+        @test KnotVector([1,2,3])     ⊆ KnotVector([1,2,3])
+        @test KnotVector([1,2,3])     ⊇ KnotVector([1,2,3])
+        @test KnotVector([1,2,2,3])   ⊆ KnotVector([1,2,2,3,5])
+        @test KnotVector([1,2,2,3])   ⊈ KnotVector([1,2,3,5])
+        @test KnotVector([1,2,2,3,5]) ⊇ KnotVector([1,2,2,3])
+        @test KnotVector([1,2,3,5])   ⊉ KnotVector([1,2,2,3])
+    end
+
+    @testset "string" begin
+        k = KnotVector([1,2,2,3])
+        @test string(k) == "KnotVector([1.0, 2.0, 2.0, 3.0])"
+        @test string(KnotVector()) == "KnotVector([])"
+    end
+
+    @testset "other operators" begin
+        k = KnotVector([1,2,2,3])
+        @test 𝔫(k, 0.3) == 0
+        @test 𝔫(k, 1.0) == 1
+        @test 𝔫(k, 2.0) == 2
+        @test 1 ∈ k
+        @test 1.5 ∉ k
+    end
+end
diff --git a/test/test_Knots.jl b/test/test_Knots.jl
deleted file mode 100644
index e3f964e4..00000000
--- a/test/test_Knots.jl
+++ /dev/null
@@ -1,61 +0,0 @@
-@testset "Knots" begin
-    k1 = Knots([1,2,3])
-    k2 = Knots([1,2,2,3])
-    k3 = Knots([2,4,5])
-    @testset "constructor" begin
-        @test k1 isa Knots{Float64}
-        @test k1 == Knots(1:3)::Knots{Float64}
-        @test k1 == Knots([1,3,2])::Knots{Float64}
-        @test k1 == Knots(1,2,3)::Knots{Float64}
-        @test k1 == Knots(1,3,2)::Knots{Float64}
-
-        @test Knots{Int}([1,2]) isa Knots{Int}
-        @test Knots{Int}(1,2) isa Knots{Int}
-    end
-
-    @testset "zeros" begin
-        @test Knots() == zero(Knots)
-        @test Knots() == 0*k1
-        @test Knots() == Knots(Float64[])
-    end
-
-    @testset "length" begin
-        @test length(Knots()) == 0
-        @test length(Knots([1,2,2,3])) == 4
-    end
-
-    @testset "addition, multiply" begin
-        @test Knots([-1,2,3]) + 2 * Knots([2,5]) == Knots([-1,2,2,2,3,5,5])
-        @test k1 + k3 == Knots([1,2,2,3,4,5])
-        @test 2 * Knots([2,3]) == Knots([2,2,3,3])
-    end
-
-    @testset "unique" begin
-        @test unique(k1) == k1
-        @test unique(k2) == k1
-    end
-
-    @testset "inclusive relation" begin
-        @test Knots([1,2,3])     ⊆ Knots([1,2,3])
-        @test Knots([1,2,3])     ⊇ Knots([1,2,3])
-        @test Knots([1,2,2,3])   ⊆ Knots([1,2,2,3,5])
-        @test Knots([1,2,2,3])   ⊈ Knots([1,2,3,5])
-        @test Knots([1,2,2,3,5]) ⊇ Knots([1,2,2,3])
-        @test Knots([1,2,3,5])   ⊉ Knots([1,2,2,3])
-    end
-
-    @testset "string" begin
-        k = Knots([1,2,2,3])
-        @test string(k) == "Knots([1.0, 2.0, 2.0, 3.0])"
-        @test string(Knots()) == "Knots([])"
-    end
-
-    @testset "other operators" begin
-        k = Knots([1,2,2,3])
-        @test 𝔫(k, 0.3) == 0
-        @test 𝔫(k, 1.0) == 1
-        @test 𝔫(k, 2.0) == 2
-        @test 1 ∈ k
-        @test 1.5 ∉ k
-    end
-end