Full code below working nicely now for any number of knots with @hendri54’s method:
using ElasticArrays
# Computes all possible knot locations on a dataset with `il` number of points, for a minimum segment length of `ilsegmin` and `nknots` number of knots.
function allknots(il::Int, ilsegmin::Int, nknots::Int)
# Initialize first knot combination
knots = ElasticArray{Int}(undef, nknots, 1) # Create data storage structure for knots
j = 1 # Possible knot location counter
knots[1] = 1
for n = 2:nknots - 1
knots[n] = knots[n - 1] + ilsegmin - 1
end
knots[nknots] = il
# Ensure first knot combination is possible
if (nknots < 2) || (knots[nknots] - knots[nknots - 1] < ilsegmin)
println("No possible knots with the given parameters.")
return knots = ElasticArray{Int}(undef, nknots, 0)
end
# Determine all remaining knot combinations
function incrementknot(il::Int, ilsegmin::Int, nknots::Int, k::Int=nknots - 2)
while knots[nknots - k, j] < il - k * ilsegmin + k # While current knot not yet at maximum location
if k > 1
incrementknot(il, ilsegmin, nknots, k - 1) # Call function recursively to obtain inner while loops
elseif k < 1
throw(ArgumentError("k must be a counting number"))
end
j += 1 # Increment possible knot counter
append!(knots, knots[:, j - 1]) # Create new knot combination same as last knot combination except...
knots[nknots - k, j] += 1 # increment current knot and
for kk = k - 1:-1:1 # reset all downstream knots
knots[nknots - kk, j] = knots[nknots - (kk + 1), j] + ilsegmin - 1
end
end
return knots
end
incrementknot(il, ilsegmin, nknots)
return knots
end
# Test
for n = 1:7
display(allknots(12, 3, n))
end