Skip to content
Snippets Groups Projects
Verified Commit ff0eed50 authored by Lucas Ondel Yang's avatar Lucas Ondel Yang
Browse files

pretty print epsilon arcs

parent 2c867164
Branches
Tags
No related merge requests found
......@@ -16,34 +16,41 @@ begin
using Revise
Pkg.develop(path="..")
Pkg.develop(path="../../sparsesemimodules.jl")
using FiniteStateAutomata
Pkg.add("Semirings")
using Semirings
using LinearAlgebra
end
# ╔═╡ 2b8f46d1-08a5-479a-8261-7dc6f662563a
K = ProbSemiring{Float64}
# ╔═╡ 76451939-8cd8-4996-b6da-7ed3e3a758c3
K = LogSemiring{Float64}
# ╔═╡ b0f12741-f4b1-48f5-bf75-756b55d99975
md"""## Closure"""
# ╔═╡ 5ea5e692-1e92-4799-b355-f19c35645341
A = FST(
K,
# ╔═╡ fc2aedf5-3050-4120-a138-efd10be3994d
T = TransitionMatrix(
K,
3,
[
(0, 1, K(2)),
(1, 1, K(2)),
(0, 2, K(3)),
(1, 2, K(3)),
(2, 3, K(4)),
(3, 3, K(4))
],
],
[(1, 1, K(2))],
[(1, 2, K(2))],
[(1, 2, K(3)), (2, 3, K(3))]
);
# ╔═╡ 5ea5e692-1e92-4799-b355-f19c35645341
A = FST(
K,
[(1, K(5))],
T,
[(2, K(5)), (3, K(5))],
["a" => "p", "b" => "q", "c" => "r"],
# infactors = [(1, 1, K(2))],
......@@ -52,9 +59,6 @@ A = FST(
# [2, []]
)
# ╔═╡ 74dbf4f7-076e-452f-9b05-4f306606eaea
FiniteStateAutomata.MatrixPowerSum(T(A))
# ╔═╡ 2e4cee38-1cf9-499b-8ec8-5f92e0286b4e
closure(A)
......@@ -122,9 +126,8 @@ Iterators.map(x -> 2x, [1, 2, 3]) |> typeof
# ╔═╡ Cell order:
# ╠═e2560be8-f3f9-11ed-0754-e3e1572c751d
# ╠═2b8f46d1-08a5-479a-8261-7dc6f662563a
# ╠═74dbf4f7-076e-452f-9b05-4f306606eaea
# ╠═76451939-8cd8-4996-b6da-7ed3e3a758c3
# ╟─b0f12741-f4b1-48f5-bf75-756b55d99975
# ╠═fc2aedf5-3050-4120-a138-efd10be3994d
# ╠═5ea5e692-1e92-4799-b355-f19c35645341
# ╠═2e4cee38-1cf9-499b-8ec8-5f92e0286b4e
# ╠═de8cc675-45d6-4d7b-84b1-b93dcfdccebf
......
......@@ -5,34 +5,34 @@ module FiniteStateAutomata
using LinearAlgebra
using ChainRulesCore
using SparseArrays
#using SparseSemimodules
using Semirings
Base.oneunit(K::Type{<:Semiring}) = one(K)
export
# concrete types
FST,
DenseFST,
TransitionMatrix,
FST
#DenseFST,
# Accessors / properties
α,
T,
ω,
ρ,
λ,
nstates,
nedges,
accessible,
coaccessible,
#α,
#T,
#ω,
#ρ,
#λ,
#nstates,
#nedges,
#accessible,
#coaccessible,
# FST operations
W,
Π₁,
Π₂,
closure,
determinize,
renorm
#W,
#Π₁,
#Π₂,
#closure,
#determinize,
#renorm
# statemap,
# connect,
......@@ -42,19 +42,19 @@ export
# propagate,
# renorm
include("spuvmatrix.jl")
include("transitionmatrix.jl")
include("abstractfst.jl")
include("fst.jl")
#include("dense_fsa.jl")
include("totalweight.jl")
include("project.jl")
include("reverse.jl")
include("union.jl")
include("cat.jl")
include("closure.jl")
include("determinize.jl")
include("renorm.jl")
#include("totalweight.jl")
#include("project.jl")
#include("reverse.jl")
#include("union.jl")
#include("cat.jl")
#include("closure.jl")
#include("determinize.jl")
#include("renorm.jl")
#include("kron.jl")
#include("statemap.jl")
......
......@@ -116,7 +116,8 @@ function dot_write(io::IO, A::AbstractFST; highlights = [], hcolor = "blue")
println(io, "rankdir=LR;")
dot_write_nodes(io, T(A), ω(A), ρ(A))
dot_write_initedges(io, α(A), λ(A))
dot_write_edges(io, T(A), ρ(A), λ(A))
dot_write_transmat(io, T(A), λ(A))
#dot_write_edges(io, T(A), ρ(A), λ(A))
if ! isempty(highlights)
println(io, join(highlights, ","), " [style=\"bold\", color=\"$hcolor\"];")
......@@ -124,8 +125,53 @@ function dot_write(io::IO, A::AbstractFST; highlights = [], hcolor = "blue")
println(io, "}")
end
function dot_write_transmat(io::IO, A::TransitionMatrix, λ::AbstractVector)
Q = size(A.S, 1)
I, J, V = findnz(A.S)
for (i, j, v) in zip(I, J, V)
_dot_write_edge(io, i, j, λ[j], v)
end
I, J, V = findnz(A.U)
for (i, j, v) in zip(I, J, V)
_dot_write_edge(io, i, Q+j, "ϵ", v)
end
I, J, V = findnz(A.E)
for (i, j, v) in zip(I, J, V)
_dot_write_edge(io, Q+i, Q+j, "ϵ", v)
end
I, J, V = findnz(A.V)
for (i, j, v) in zip(I, J, V)
_dot_write_edge(io, Q+i, j, λ[j], v)
end
end
function dot_write_edge(io, src, dst, label, weight)
if isone(weight)
println(io, "$src -> $dst [label=\"", label, "\"];")
else
style = iszero(weight) ? "style=invis" : ""
val = typeof(weight) <: AbstractFloat ? round(weight, digits=3) : weight
println(io, "$src -> $dst [label=\"", label, "/", weight, "\"", style, "];")
end
end
function dot_write_edge(io, src, dst, label::Pair, weight)
if isone(weight)
println(io, "$src -> $dst [label=\"", label[1], ":", label[2], "\"];")
else
style = iszero(weight) ? "style=invis" : ""
val = typeof(weight) <: AbstractFloat ? round(weight, digits=3) : weight
println(io, "$src -> $dst [label=\"", label[1], ":", label[2], "/", weight, "\" ", style, "];")
end
end
function dot_write_nodes(io::IO, T, ω, ρ)
println(io, join(0:size(T, 1), ","), " [shape=\"circle\"];")
Q, P = size(T.S, 1), size(T.E, 1)
println(io, join(0:Q+P, ","), " [shape=\"circle\"];")
if iszero(ρ)
println(io, "0 [style=\"bold\"];")
......@@ -152,53 +198,10 @@ function dot_write_initedges(io::IO, α, λ)
end
end
function dot_write_edges(io, T, ρ, λ)
function dot_write_edges(io, T::MatrixPowerSum, ρ, λ)
I, J, V = findnz(T)
for (i, j, w) in zip(I, J, V)
dot_write_edge(io, i, j, λ[j], w)
end
end
function dot_write_edges(io, T::SPUV, ρ, λ)
Q = size(T, 1)
K = size(T.U, 2)
println(io, join((Q+1):(Q+K), ","), " [shape=\"circle\"];")
for i in 1:K
n = Q + i
println(io, "$(n) [label=\"$n\"];")
end
I, J, V = findnz(T.U)
for (i, j, w) in zip(I, J, V)
dot_write_edge(io, i, Q + j, "ϵ", w)
end
I, J, V = findnz(T.V)
for (i, j, w) in zip(I, J, V)
dot_write_edge(io, Q + i, j, λ[j], w)
end
dot_write_edges(io, T.S, ρ, λ)
end
function dot_write_edge(io, src, dst, label::Pair, weight)
if isone(weight)
println(io, "$src -> $dst [label=\"", label[1], ":", label[2], "\"];")
else
style = iszero(weight) ? "style=invis" : ""
val = typeof(weight) <: AbstractFloat ? round(weight, digits=3) : weight
println(io, "$src -> $dst [label=\"", label[1], ":", label[2], "/", weight, "\" ", style, "];")
end
end
function dot_write_edge(io, src, dst, label, weight)
if isone(weight)
println(io, "$src -> $dst [label=\"", label, "\"];")
else
style = iszero(weight) ? "style=invis" : ""
val = typeof(weight) <: AbstractFloat ? round(weight, digits=3) : weight
println(io, "$src -> $dst [label=\"", label, "/", weight, "\"", style, "];")
end
end
......@@ -13,7 +13,7 @@ Generic Finite State Automaton.
"""
struct FST{K,L} <: AbstractFST{K,L}
α::AbstractVector{K}
T::AbstractMatrix{K}
T::TransitionMatrix{K}
ω::AbstractVector{K}
ρ::K
λ::AbstractVector{L}
......@@ -21,31 +21,23 @@ end
FST(A::AbstractFST) = FST(α(A), T(A), ω(A), ρ(A), λ(A))
function FST(K, arcs, finalweights, statelabels, ϵweight = zero(K))
I_α, V_α = Int[], K[]
I_T, J_T, V_T = Int[], Int[], K[]
for (src, dest, weight) in arcs
if src == 0
push!(I_α, dest)
push!(V_α, weight)
else
push!(I_T, src)
push!(J_T, dest)
push!(V_T, weight)
end
end
I_ω, V_ω = Int[], K[]
for (state, weight) in finalweights
push!(I_ω, state)
push!(V_ω, weight)
# Returns a `Q` vector from a list of tuple `(i, v)`.`K` is element
# type of the matrix.
function _spv_from_list(K, Q, tuples)
I, V = Int[], K[]
for (i, v) in tuples
push!(I, i)
push!(V, v)
end
sparsevec(I, V, Q)
end
function FST(K, initweights, transmat, finalweights, statelabels, ϵweight = zero(K))
Q = length(statelabels)
FST(
sparsevec(I_α, V_α, Q),
sparse(I_T, J_T, V_T, Q, Q),
sparsevec(I_ω, V_ω, Q),
_spv_from_list(K, Q, initweights),
transmat,
_spv_from_list(K, Q, finalweights),
ϵweight,
statelabels
)
......
......@@ -11,7 +11,7 @@ function Base.:*(xᵀ::Transpose{K, AbstractVector{K}}, M::MatrixPowerSum{K}) wh
uₙᵀ = xᵀ
i = 0
while nnz(parent(uₙᵀ)) > 0
i >= size(M, 1) || throw(ArgumentError("matrix `M` is not nilpotent"))
i >= size(M, 1) || throw(ArgumentError("matrix is not nilpotent"))
uₙᵀ = uₙᵀ * T(A)
end
uₙᵀ
......@@ -21,7 +21,7 @@ function Base.:*(M::MatrixPowerSum{K}, x::AbstractVector{K}) where K
vₙ = x
i = 0
while nnz(vₙ) > 0
i >= size(M, 1) || throw(ArgumentError("matrix `M` is not nilpotent"))
i >= size(M, 1) || throw(ArgumentError("matrix is not nilpotent"))
vₙ = T(A) * vₙ
end
vₙ
......@@ -29,20 +29,48 @@ end
#= Factorized matrix =#
struct FactorizedMatrix{K} <: AbstractMatrix{K}
# Returns a `Q` x `P` sparse matrix from a list of arcs.
# An arc is defined by a triplet `(i, j, v)`. `K` is element type
# of the matrix.
function _spm_from_list(K, Q, P, arcs)
I, J, V = Int[], Int[], K[]
for (src, dest, weight) in arcs
push!(I, src)
push!(J, dest)
push!(V, weight)
end
sparse(I, J, V, Q, P)
end
struct TransitionMatrix{K} <: AbstractMatrix{K}
S::AbstractMatrix{K}
U::AbstractMatrix{K}
E::AbstractMatrix{K}
V::AbstractMatrix{K}
end
Base.size(M::FactorizedMatrix) = size(M.S)
function TransitionMatrix(K, Q, direct_arcs, in_factors, factors, out_factors)
S = _spm_from_list(K, Q, Q, direct_arcs)
function Base.:*(xᵀ::Transpose{K, AbstractVector{K}}, M::FactorizedMatrix{K}) where K
xᵀ * M.S + (xᵀ * M.U) * M.V
# Number of factors.
P = max(
maximum(t -> t[2], in_factors),
maximum(t -> max(t[1], t[2]), factors),
maximum(t -> t[1], out_factors)
)
U = _spm_from_list(K, Q, P, in_factors)
E = _spm_from_list(K, P, P, factors)
V = _spm_from_list(K, P, Q, out_factors)
TransitionMatrix(S, U, E, V)
end
function Base.:*(M::FactorizedMatrix{K}, x::AbstractVector{K}) where K
Base.size(M::TransitionMatrix) = size(M.S)
Base.:*(xᵀ::Transpose{K, AbstractVector{K}}, M::TransitionMatrix{K}) where K =
xᵀ * M.S + (xᵀ * M.U) * M.V
Base.:*(M::TransitionMatrix{K}, x::AbstractVector{K}) where K =
M.S * x + M.U * (M.V * x)
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment