Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finset algs #2

Merged
merged 17 commits into from
Mar 5, 2024
15 changes: 11 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ version = "0.0.1"

[deps]
AlgebraicDynamics = "5fd6ff03-a254-427e-8840-ba658f502e32"
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
BlockDiagonals = "0a1fb500-61f7-11e9-3c65-f5ef3456f9f0"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"

[compat]
Catlab = "^0.15"
julia = "1.9"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
7 changes: 6 additions & 1 deletion src/AlgebraicOptimization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
"""
module AlgebraicOptimization

include("OpenProblems.jl")
include("FinSetAlgebras.jl")
include("Optimizers.jl")
include("Objectives.jl")
include("OpenFlowGraphs.jl")
#include("OpenProblems.jl")
#include("FlowGraphs.jl")

end
144 changes: 144 additions & 0 deletions src/Experiments.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using NLsolve
using LinearAlgebra
using ForwardDiff
using Catlab

function node_incidence_matrix(g::Graph)
V = nv(g)
E = ne(g)
A = zeros(V,E)
for (v,e) in Iterators.product(1:V, 1:E)
if src(g, e) == tgt(g, e) && tgt(g, e) == v
continue
elseif src(g,e) == v
A[v,e] = 1
elseif tgt(g,e) == v
A[v,e] = -1

Check warning on line 16 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L6-L16

Added lines #L6 - L16 were not covered by tests
end
end
return A

Check warning on line 19 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L18-L19

Added lines #L18 - L19 were not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do this in linear time with

A = zeros(V,E)
for e in parts(g, :E) 
  A[src(e),e] = 1
  A[tgt(e),e] = -1
end

end

N_subprob = 10
A1 = node_incidence_matrix(wheel_graph(Graph, N_subprob))
A2 = A1
A3 = A1







function draw2(n::Int)
a = rand(1:n)
b = rand(1:n-1)
b += (b >= a)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wat?

What process are you trying to sample from?

return a, b

Check warning on line 37 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L33-L37

Added lines #L33 - L37 were not covered by tests
end

function random_column(length::Int)
a,b = draw2(length)
res = zeros(length)
res[a] = 1
res[b] = -1
return res

Check warning on line 45 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L40-L45

Added lines #L40 - L45 were not covered by tests
end

E = 50
V = 30
num_sources = 5
num_sinks = 5

A = hcat([random_column(V) for i in 1:E]...)

f(x) = x^2

Check warning on line 55 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L55

Added line #L55 was not covered by tests

b = zeros(V)

for i in 1:num_sources
src_vertex = rand(1:V)
val = rand(1:0.01:10)
b[src_vertex] = val
end

for i in 1:num_sinks
sink_vertex = rand(1:V)
val = rand(1:0.01:10)
b[sink_vertex] = -val
end
λ = randn(V)
total_L(x) = sum([f(x_i) for x_i in x]) + λ'*(A*x-b)

Check warning on line 71 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L71

Added line #L71 was not covered by tests

L(i) = x -> f(x) + λ'*(A[:,i]*x - b)

Check warning on line 73 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L73

Added line #L73 was not covered by tests

function grad_flow_L(x::Vector)
ForwardDiff.gradient(total_L, x)

Check warning on line 76 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L75-L76

Added lines #L75 - L76 were not covered by tests
end

function grad_flow_L(i::Int)
x -> ForwardDiff.derivative(L(i), x)

Check warning on line 80 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L79-L80

Added lines #L79 - L80 were not covered by tests
end

function grad_descent(f, x0, γ, max_iters, ϵ)
x_prev = x0
x_cur = x0
for i in 1:max_iters
x_cur = x_prev - γ*ForwardDiff.gradient(f, x_prev)
if norm(f(x_cur) - f(x_prev)) < ϵ

Check warning on line 88 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L83-L88

Added lines #L83 - L88 were not covered by tests
#println("Terminated in $i iterations.")
return x_cur

Check warning on line 90 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L90

Added line #L90 was not covered by tests
end
x_prev = x_cur
end
println("Did not converge.")
return x_cur

Check warning on line 95 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L92-L95

Added lines #L92 - L95 were not covered by tests
end

function grad_descent_1D(f, x0, γ, max_iters, ϵ)
x_prev = x0
x_cur = x0
for i in 1:max_iters
x_cur = x_prev - γ*ForwardDiff.derivative(f, x_prev)
if norm(f(x_cur) - f(x_prev)) < ϵ

Check warning on line 103 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L98-L103

Added lines #L98 - L103 were not covered by tests
#println("Terminated in $i iterations.")
return x_cur

Check warning on line 105 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L105

Added line #L105 was not covered by tests
end
x_prev = x_cur
end
println("Did not converge.")
return x_cur

Check warning on line 110 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L107-L110

Added lines #L107 - L110 were not covered by tests
end

sol_nl_total = nlsolve(grad_flow_L, repeat([10.0], E), iterations=1000000, xtol=0.01).zero
@time nlsolve(grad_flow_L, repeat([10.0], E), iterations=1000000, xtol=0.01)

function sol_nl(i::Int)
f = grad_flow_L(i)
sol = nlsolve(n_ary(f), [10.0], xtol=0.01)
return sol.zero[1]

Check warning on line 119 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L116-L119

Added lines #L116 - L119 were not covered by tests
end

sol_nl_distributed = zeros(E)
for i in 1:E
sol_nl_distributed[i]=sol_nl(i)
end

@time for i in 1:E
sol_nl(i)
end

sol_total = grad_descent(total_L, repeat([10.0], E), 0.1,100000, 0.0001)
@time grad_descent(total_L, repeat([10.0], E), 0.1,100000, 0.01)
sol(i) = grad_descent_1D(L(i), 10.0, 0.1, 100000, 0.01)

Check warning on line 133 in src/Experiments.jl

View check run for this annotation

Codecov / codecov/patch

src/Experiments.jl#L133

Added line #L133 was not covered by tests

sol_distributed = zeros(E)

for i in 1:E
sol_distributed[i] = sol(i)
end

@time for i in 1:E
sol(i)
end

214 changes: 214 additions & 0 deletions src/FinSetAlgebras.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
module FinSetAlgebras

export FinSetAlgebra, CospanAlgebra, Open, hom_map, laxator, data, portmap

using LinearAlgebra, SparseArrays
using Catlab
import Catlab: oapply, dom, Cospan

#abstract type AlgebraObject end

abstract type FinSetAlgebra{T} end # A finset algebra with object type T

#=function dom(X::T)::FinSet where T <: AlgebraObject
error("Domain not specified.")
end=#

#=function ob_map(::FinSetAlgebra{T}, N::FinSet)::T where T <: AlgebraObject
error("Object map not implemented.")
end=#

function hom_map(::FinSetAlgebra{T}, ϕ::FinFunction, X::T)::T where T
error("Morphism map not implemented.")

Check warning on line 22 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L21-L22

Added lines #L21 - L22 were not covered by tests
end

function laxator(::FinSetAlgebra{T}, Xs::Vector{T})::T where T
error("Laxator not implemented.")

Check warning on line 26 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L25-L26

Added lines #L25 - L26 were not covered by tests
end

function oapply(A::FinSetAlgebra{T}, ϕ::FinFunction, Xs::Vector{T})::T where T
return hom_map(A, ϕ, laxator(A, Xs))

Check warning on line 30 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L29-L30

Added lines #L29 - L30 were not covered by tests
end

# Example
function pullback_matrix(f::FinFunction)
n = length(dom(f))
sparse(1:n, f.(dom(f)), ones(Int,n), dom(f).n, codom(f).n)

Check warning on line 36 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L34-L36

Added lines #L34 - L36 were not covered by tests
end

pushforward_matrix(f::FinFunction) = pullback_matrix(f)'

Check warning on line 39 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L39

Added line #L39 was not covered by tests

#=struct FreeVector <: AlgebraObject
dim::FinSet
v::Vector{Float64}
end=#

#dom(v::FreeVector) = v.dim

struct Pushforward <: FinSetAlgebra{Vector{Float64}} end

dom(v::Vector{Float64}) = FinSet(length(v))

Check warning on line 50 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L50

Added line #L50 was not covered by tests

hom_map(::Pushforward, ϕ::FinFunction, v::Vector{Float64}) = pushforward_matrix(ϕ)*v

Check warning on line 52 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L52

Added line #L52 was not covered by tests


laxator(::Pushforward, Xs::Vector{Vector{Float64}}) = vcat(Xs...)

Check warning on line 55 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L55

Added line #L55 was not covered by tests

# UWD algebras from finset algebras
abstract type CospanAlgebra{T} end
#abstract type SimpleCospanAlgebra{T, A<:FinSetAlgebra{T}} <: CospanAlgebra{T} end

function hom_map(::CospanAlgebra{T}, ϕ::Cospan, X::T)::T where T
error("Morphism map not implemented.")

Check warning on line 62 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L61-L62

Added lines #L61 - L62 were not covered by tests
end

function laxator(::CospanAlgebra{T}, Xs::Vector{T})::T where T
error("Laxator not implemented.")

Check warning on line 66 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L65-L66

Added lines #L65 - L66 were not covered by tests
end


function oapply(A::CospanAlgebra{T}, ϕ::Cospan, Xs::Vector{T})::T where T
return hom_map(A, ϕ, laxator(A, Xs))

Check warning on line 71 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L70-L71

Added lines #L70 - L71 were not covered by tests
end


struct Open{T}
S::FinSet
o::T
m::FinFunction
Open{T}(S, o, m) where T =
S != codom(m) || dom(o) != S ? error("Invalid portmap.") : new(S, o, m)
end

data(obj::Open{T}) where T = obj.o
portmap(obj::Open{T}) where T = obj.m

Check warning on line 84 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L83-L84

Added lines #L83 - L84 were not covered by tests


function Open{T}(o::T) where T
Open{T}(domain(o), o, id(domain(o)))

Check warning on line 88 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L87-L88

Added lines #L87 - L88 were not covered by tests
end

dom(obj::Open{T}) where T = dom(obj.m)

Check warning on line 91 in src/FinSetAlgebras.jl

View check run for this annotation

Codecov / codecov/patch

src/FinSetAlgebras.jl#L91

Added line #L91 was not covered by tests

function hom_map(::CospanAlgebra{Open{T}}, A::FinSetAlgebra{T}, ϕ::Cospan, X::Open{T})::Open{T} where T
l = left(ϕ)
r = right(ϕ)
p = pushout(X.m, l)
pL = legs(p)[1]
pR = legs(p)[2]
return Open{T}(apex(p), hom_map(A, pL, X.o), compose(r,pR))
end

function laxator(::CospanAlgebra{Open{T}}, A::FinSetAlgebra{T}, Xs::Vector{Open{T}})::Open{T} where T
S = coproduct([X.S for X in Xs])
inclusions(i::Int) = legs(S)[i]
m = copair([compose(Xs[i].m, inclusions(i)) for i in 1:length(Xs)])
o = laxator(A, [X.o for X in Xs])
return Open{T}(apex(S), o, m)
end

function oapply(CA::CospanAlgebra{Open{T}}, FA::FinSetAlgebra{T}, ϕ::Cospan, Xs::Vector{Open{T}})::Open{T} where T
return hom_map(CA, FA, ϕ, laxator(CA, FA, Xs))
end

function uwd_to_cospan(d::AbstractUWD)
# Build the left leg
left_dom = vcat([length(ports(d, i)) for i in boxes(d)])
left_codom = njunctions(d)

#println(cp_dom)
ports_to_junctions = FinFunction[]
total_portmap = subpart(d, :junction)

for box in ports.([d], boxes(d))
push!(ports_to_junctions, FinFunction([total_portmap[p] for p in box], length(box), left_codom))
end
#println(ports_to_junctions)
#cp = CompositionPattern(cp_dom, cp_codom, ports_to_junctions)

left = copair(ports_to_junctions)
right = FinFunction(subpart(d, :outer_junction), left_codom)

return Cospan(left, right)
end

function oapply(CA::CospanAlgebra{Open{T}}, FA::FinSetAlgebra{T}, d::AbstractUWD, Xs::Vector{Open{T}})::Open{T} where T
return oapply(CA, FA, uwd_to_cospan(d), Xs)
end


end
#=
# Test example
struct UWDPushforward <: CospanAlgebra{Open{Vector{Float64}}} end

const OpenVector = Open{Vector{Float64}}

# UWD Interop
function uwd_to_cospan(d::AbstractUWD)
# Build the left leg
left_dom = vcat([length(ports(d, i)) for i in boxes(d)])
left_codom = njunctions(d)

#println(cp_dom)
ports_to_junctions = FinFunction[]
total_portmap = subpart(d, :junction)

for box in ports.([d], boxes(d))
push!(ports_to_junctions, FinFunction([total_portmap[p] for p in box], length(box), left_codom))
end
#println(ports_to_junctions)
#cp = CompositionPattern(cp_dom, cp_codom, ports_to_junctions)

left = copair(ports_to_junctions)
right = FinFunction(subpart(d, :outer_junction), left_codom)

return Cospan(left, right)
end

function oapply(CA::CospanAlgebra{Open{T}}, FA::FinSetAlgebra{T}, d::AbstractUWD, Xs::Vector{Open{T}})::Open{T} where T
return oapply(CA, FA, uwd_to_cospan(d), Xs)
end

# AlgebraicDynamics
struct System
state_space::FinSet
dynamics::Function # R^ss -> R^ss
end
(s::System)(x::Vector) = s.dynamics(x)
dom(s::System) = s.state_space

struct Dynam <: FinSetAlgebra{System} end

hom_map(::Dynam, ϕ::FinFunction, s::System) =
System(codom(ϕ), x->pushforward_matrix(ϕ)*s(pullback_matrix(ϕ)*x))

function laxator(::Dynam, Xs::Vector{System})
c = coproduct([dom(X) for X in Xs])
subsystems = [x -> X(pullback_matrix(l)*x) for (X,l) in zip(Xs, legs(c))]
function parallel_dynamics(x)
res = Vector{Vector}(undef, length(Xs)) # Initialize storage for results
Threads.@threads for i = 1:length(Xs)
res[i] = subsystems[i](x)
end
return vcat(res...)
end
return System(apex(c), parallel_dynamics)
end

struct UWDDynam <: CospanAlgebra{Open{System}} end # Turn Dynam into a UWD algebra in one line!

A = rand(-1.0:.01:1.0, 5,5)
B = rand(-1.0:.01:1.0, 3,3)
C = rand(-1.0:.01:1.0, 4,4)

γ = 0.1
s1 = System(FinSet(5), x->x +γ*A*x)
s2 = System(FinSet(3), x->x + γ*B*x)
s3 = System(FinSet(4), x->x + γ*C*x)

ϕ = FinFunction([1,2,3,4,5,2,3,6,3,6,7,8])

s = oapply(Dynam(), ϕ, [s1,s2,s3])=#

#end
Loading
Loading