I'm very new to topology. Suppose I want to create a 1/2/3 dim manifold, and project it onto a 10 dimensional space. How should I do that? I went through the website https://juliamanifolds.github.io/Manifolds.jl/v0.1/interface.html#
And my current code is like
using ManifoldsBase, LinearAlgebra, Test
import ManifoldsBase: check_point, check_vector, manifold_dimension, exp!, inner, representation_size, get_embedding
import Base: show
"""
ScaledSphere{N} <: AbstractDecoratorManifold{ℝ}
Define an `N`-sphere of radius `r`. Construct by `ScaledSphere(radius,n)`.
"""
struct ScaledSphere{N} <: AbstractDecoratorManifold{ManifoldsBase.ℝ} where {N}
radius::Float64
end
ScaledSphere(radius, n) = ScaledSphere{n}(radius)
Base.show(io::IO, M::ScaledSphere{n}) where {n} = print(io, "ScaledSphere($(M.radius),$n)")
S = ScaledSphere(1.5, 2)
I can only find how to project a point onto a tangent vector, but what about project a point/circle/sphere onto the 10-dimensional space?
Related
I am seeing that Julia explicitly does NOT do classes... and I should instead embrace mutable structs.. am I going down the correct path here?? I diffed my trivial example against an official flux library but cannot gather how do I reference self like a python object.. is the cleanest way to simply pass the type as a parameter in the function??
Python
# Dense Layer
class Layer_Dense
def __init__(self, n_inputs, n_neurons):
self.weights = 0.01 * np.random.randn(n_inputs, n_neurons)
self.biases = np.zeros((1, n_neurons))
def forward(self, inputs):
pass
My JuliaLang version so far
mutable struct LayerDense
num_inputs::Int64
num_neurons::Int64
weights
biases
end
function forward(layer::LayerDense, inputs)
layer.weights = 0.01 * randn(layer.num_inputs, layer.num_neurons)
layer.biases = zeros((1, layer.num_neurons))
end
The flux libraries version of a dense layer... which looks very different to me.. and I do not know what they're doing or why.. like where is the forward pass call, is it here in flux just named after the layer Dense???
source : https://github.com/FluxML/Flux.jl/blob/b78a27b01c9629099adb059a98657b995760b617/src/layers/basic.jl#L71-L111
struct Dense{F, M<:AbstractMatrix, B}
weight::M
bias::B
σ::F
function Dense(W::M, bias = true, σ::F = identity) where {M<:AbstractMatrix, F}
b = create_bias(W, bias, size(W,1))
new{F,M,typeof(b)}(W, b, σ)
end
end
function Dense(in::Integer, out::Integer, σ = identity;
initW = nothing, initb = nothing,
init = glorot_uniform, bias=true)
W = if initW !== nothing
Base.depwarn("keyword initW is deprecated, please use init (which similarly accepts a funtion like randn)", :Dense)
initW(out, in)
else
init(out, in)
end
b = if bias === true && initb !== nothing
Base.depwarn("keyword initb is deprecated, please simply supply the bias vector, bias=initb(out)", :Dense)
initb(out)
else
bias
end
return Dense(W, b, σ)
end
This is an equivalent of your Python code in Julia:
mutable struct Layer_Dense
weights::Matrix{Float64}
biases::Matrix{Float64}
Layer_Dense(n_inputs::Integer, n_neurons::Integer) =
new(0.01 * randn(n_inputs, n_neurons),
zeros((1, n_neurons)))
end
forward(ld::Layer_Dense, inputs) = nothing
What is important here:
here I create an inner constructor only, as outer constructor is not needed; as opposed in the Flux.jl code you have linked the Dense type defines both inner and outer constructors
in python forward function does not do anything, so I copied it in Julia (your Julia code worked a bit differently); note that instead of self one should pass an instance of the object to the function as the first argument (and add ::Layer_Dense type signature so that Julia knows how to correctly dispatch it)
similarly in Python you store only weights and biases in the class, I have reflected this in the Julia code; note, however, that for performance reasons it is better to provide an explicit type of these two fields of Layer_Dense struct
like where is the forward pass call
In the code you have shared only constructors of Dense object are defined. However, in the lines below here and here the Dense type is defined to be a functor.
Functors are explained here (in general) and in here (more specifically for your use case)
Trying to understand parametric types and the new function available for inner methods. The manual states "special function available to inner constructors which created a new object of the type". See the section of the manual on new here and the section of the manual on inner constructor methods here.
Consider an inner method designed to calculate the sum of x, where x could be, say, a vector or a tuple, and is given the parametric type T. A natural thing to want is for the type of the elements of x to be inherited by their sum s. I don't seem to need new for that, correct?
struct M{T}
x::T
s
function M(x)
s = sum(x)
x,s
end
end
julia> M([1,2,3])
([1, 2, 3], 6)
julia> M([1.,2.,3.])
([1.0, 2.0, 3.0], 6.0)
julia> typeof(M([1.,2.,3.]))
Tuple{Vector{Float64}, Float64}
Edit: Correction! I intended to have the last line of the inner constructor be M(x,s)... It's still an interesting question, so I won't correct it. How does M(x,s) differ from new{typeof(x)}(x,s)?
One usage of new I have seen is in combination with typeof(), something like:
struct M{T}
x::T
s
function M(x)
s = sum(x)
new{typeof(x)}(x,s)
end
end
julia> M([1,2,3])
M{Vector{Int64}}([1, 2, 3], 6)
julia> M([1.,2.,3.])
M{Vector{Float64}}([1.0, 2.0, 3.0], 6.0)
What if wanted to constrain s to the same type as x? That is, for instance, if x is a vector, then s should be a vector (in this case, a vector of one element). How would I do that? If I replace the last line of the inner constructor with x, new{typeof(x)}(s), I get the understandable error:
MethodError: Cannot `convert` an object of type Int64 to an object of type Vector{Int64}
Here are the rules:
If you are writing an outer constructor for a type M, the constructor should return an instance of M by eventually calling the inner constructor, like this: M(<args>).
If you are writing an inner constructor, this will override the default inner constructor. So you must return an instance of M by calling new(<args>).
The new "special function" exists to allow the construction of a type that doesn't have a constructor yet. Observe the following example:
julia> struct A
x::Int
function A(x)
A(x)
end
end
julia> A(4)
ERROR: StackOverflowError:
Stacktrace:
[1] A(::Int64) at ./REPL[3]:4 (repeats 79984 times)
This is a circular definition of the constructor for A, which results in a stack overflow. You cannot pull yourself up by your bootstraps, so Julia provides the new function as a way to circumvent this problem.
You should provide the new function with a number of arguments equal to the number of fields in your struct. Note that the new function will attempt to convert the types of its inputs to match the declared types of the fields of your struct:
julia> struct B
x::Float64
B(x) = new(x)
end
julia> B(5)
B(5.0)
julia> B('a')
B(97.0)
julia> B("a")
ERROR: MethodError: Cannot `convert` an object of type String to an object
of type Float64
(The inner constructor for B above is exactly the same as the default inner constructor.)
When you're defining parametric types, the new function must be provided with a number of parameters equal to the number of parameters for your type (and in the same order), analogously to the default inner constructor for parametric types. First observe how the default inner constructor for parametric types is used:
julia> struct Foo{T}
x::T
end
julia> Foo{String}("a")
Foo{String}("a")
Now if you were writing an inner constructor for Foo, instead of writing Foo{T}(x) inside the constructor, you would replace the Foo with new, like this: new{T}(x).
You might need typeof to help define the constructor, but often you don't. Here's one way you could define your M type:
struct M{I, T}
x::I
s::T
function M(x::I) where I
s = sum(x)
new{I, typeof(s)}(x, s)
end
end
I'm using typeof here so that I could be any iterable type that returns numbers:
julia> typeof(M(1:3))
M{UnitRange{Int64},Int64}
julia> g = (rand() for _ in 1:10)
Base.Generator{UnitRange{Int64},var"#5#6"}(var"#5#6"(), 1:10)
julia> typeof(M(g))
M{Base.Generator{UnitRange{Int64},var"#5#6"},Float64}
Note that providing the parameters for your type is required when you are using new inside an inner constructor for a parametric type:
julia> struct C{T}
x::Int
C(x) = new(x)
end
ERROR: syntax: too few type parameters specified in "new{...}" around REPL[6]:1
Remember, a constructor is designed to construct something. Specifically, the constructor M is designed to construct a value of type M. Your example constructor
struct M{T}
x::T
s
function M(x)
s = sum(x)
x,s
end
end
means that the result of evaluating the expression M([1 2 3]) is a tuple, not an instance of M. If I encountered such a constructor in the wild, I'd assume it was a bug and report it. new is the internal magic that allows you to actually construct a value of type M.
It's a matter of abstraction. If you just want a tuple in the first place, then forget about the structure called M and just define a function m at module scope that returns a tuple. But if you intend to treat this as a special data type, potentially for use with dynamic dispatch but even just for self-documentation purposes, then your constructor should return a value of type M.
Say I want to define a promote_rule() for a type that has multiple parametric types, for example for type MyType:
abstract type State end
struct Open<:State end
struct Closed<:State end
struct MyType{T,S<:State}
x::T
state::S
end
Is there a way to define a promote_rule() which only promotes the first type and not the second, for example:
myFloat = MyType(1.0, Open()) # MyType{Float64, Open}
myInt = MyType(2, Closed()) # MyType{Int64, Closed}
promote(myFloat, myInt)
# (MyType{Float64, Open}, MyType{Float64, Closed})
By definition, the result of a promotion is one common type. So while you can just recursively promote the Ts, you have to resort to a common supertype for the Ss if you want to keep them as is. Simply using State would be a valid choice, but a Union leads to a bit more fine-grained results:
julia> Base.promote_rule(::Type{MyType{T1, S1}}, ::Type{MyType{T2, S2}}) where {T1, T2, S1, S2} = MyType{promote_type(T1, T2), <:Union{S1, S2}}
julia> promote_type(MyType{Int, Closed}, MyType{Float64, Closed})
MyType{Float64,#s12} where #s12<:Closed
julia> promote_type(MyType{Int, Closed}, MyType{Float64, Open})
MyType{Float64,#s12} where #s12<:Union{Closed, Open}
You still have to define the respective convert methods for promote to work, of course; specifically, one ignoring the state type:
julia> Base.convert(::Type{<:MyType{T}}, m::MyType) where {T} = MyType(convert(T, m.x), m.state)
julia> promote(myFloat, myInt)
(MyType{Float64,Open}(1.0, Open()), MyType{Float64,Closed}(2.0, Closed()))
But be sure to test all kinds of combinations really well. Promotion and conversion is really fiddly and hard to get right the first time, in my experience.
For two objects A and B we could previously get the vector [A*A, A*B] with the code A .* [A, B]. From the deprecation warnings in Julia 0.7, it seems that the new way to do this is to use a reference of the first A. So it becomes Ref(A) .* [A,B].
It doesn't seem that there is a strong link between references and broadcasting operations. What is the link here and why is using a Reference preferred (by the deprecation warnings at least)?
Minimal Working Example
import Base.*
struct example
num::Int
end
function *(lhs::example, rhs::example)
return example(lhs.num * rhs.num)
end
A = example(2)
B = example(4)
# Previously this could be done as follows.
A .* [A, B]
# Now we need to use Refs
Ref(A) .* [A, B]
I will here refer to the main case of Ref, that is when you pass it one argument (there are also other subtypes of Ref but they are not relevant for us here).
Writing Ref(x) creates a mutable wrapper around object x. The wrapper is a very simple RefValue type defined in the following way:
mutable struct RefValue{T} <: Ref{T}
x::T
RefValue{T}() where {T} = new()
RefValue{T}(x) where {T} = new(x)
end
Now why it is useful, because Ref has defined the following utility functions:
eltype(x::Type{<:Ref{T}}) where {T} = #isdefined(T) ? T : Any
size(x::Ref) = ()
axes(x::Ref) = ()
length(x::Ref) = 1
ndims(x::Ref) = 0
ndims(::Type{<:Ref}) = 0
iterate(r::Ref) = (r[], nothing)
iterate(r::Ref, s) = nothing
IteratorSize(::Type{<:Ref}) = HasShape{0}()
which means that it can be used in broadcasting as only objects that have axes defined and support indexing can be used with broadcast.
Fortunately it is easy to avoid writing Ref(A) all the time.
Just define:
Base.broadcastable(e::example) = Ref(e)
and the machinery of broadcast will work again as Base.broadcastable is called on each argument of broadcast.
More details about customizing broadcasting can be found here https://docs.julialang.org/en/v1/manual/interfaces/#man-interfaces-broadcasting.
I'm new to elm, but not new to functional programming so this error is both frustrating and embarrassing. I wrote a 50 line elm program but I get these elusive type errors. In short, could someone find the type error in this code!!!!
You can paste this code right into the online elm editor.
import Mouse
import Window
--Model
type Tracker = {x:Int, y:Int, th:Float}
tracker:Tracker
tracker = {x=100, y=100, th=0.0}
trkS:Signal Tracker
trkS = constant tracker
dir: Tracker -> (Int, Int) -> (Int,Int) -> Float
dir t (x',y') (w',h') =
let (x,y) = toFloatT (x',y')
(w,h) = toFloatT (w',h')
(dx, dy) = (x - w/2, h/2 - y)
in (atan2 (dy - (toFloat t.y)) (dx - (toFloat t.x)))
dirS:Signal Float
dirS = lift3 dir trkS Mouse.position Window.dimensions
changeV: Float -> Tracker -> Tracker
changeV theta t =
{t | th <- theta }
moveTracker: Int -> Tracker -> Tracker
moveTracker time' t =
let time = toFloat time'
x' = (toFloat t.x) + 3 * time *(cos t.th)
y' = (toFloat t.y) + 3 * time *(sin t.th)
in {t | x <- round x'
, y <- round y'}
step:(Int, Float) -> Tracker -> Tracker
step (dt, dir) = moveTracker dt . changeV dir
render (w',h') trk =
let (w,h) = (toFloat w', toFloat h')
in collage w' h'
[ngon 3 20 |> filled green
|> move (trk.x, trk.y)
, asText (trk.th) |> toForm]
input:Signal (Int,Float)
input =
let delta = lift (round . (\t -> t/20)) (fps 25)
in sampleOn delta (lift2 (,) delta dirS)
main =
lift2 render Window.dimensions (foldp step tracker input)
--Helper functions
toFloatT (x,y) = (toFloat x, toFloat y)
roundF = toFloat . round
The order of actual and expected
I put your code in the online editor and it gave me a lot of expected/actual is Int/Float errors. I think that's something that can be improved, but that's for the mailing list.
What you should know is that the expected/actual types that the compiler tells you about can sometimes be reversed, at least to some peoples intuitions.
Debugging the problem
To debug this problem I first read and tried to understand your code. The code is simple enough, but the goal of the program wasn't immediately clear to me. Anyway that way I didn't spot anything out of the ordinary. I focussed specifically on the code line in main where the compiler said the type error was, but that didn't seem the source of the problem.
Adding type annotations
So I went ahead and added type annotations to the functions that didn't have any yet. Usually the compiler can give you a better pinpointed position when you add more type annotations.
I added:
render: (Int,Int) -> Tracker -> Element
main : Signal Element
toFloatT: (Int,Int) -> (Float,Float)
roundF: Float -> Float
The problem
The compiler was then able to tell me that the error was in the render function. There I noticed that you made floating point values of the window dimensions and didn't use them, and after that used the integers x and y of the Tracker in a tuple in move. And there lies the error, because move takes a tuple of floating points.
The solution
So when you use the following adapted render function, things compile:
render: (Int,Int) -> Tracker -> Element
render (w',h') trk =
let trkPos = toFloatT (trk.x, trk.y)
in collage w' h'
[ngon 3 20 |> filled green
|> move trkPos
, asText (trk.th) |> toForm]
I hope by showing you my way of debugging this type error, you can more easily find a solution next time.
TL;DR
The problem is the render function: you give the move function a tuple of Ints in stead of the tuple of Floats it expects. The fixed and compiling code can be found here.