text:
function ComputeFCFV_o2(mesh, se, Tdir, tau, o2)
    nen   = 3
    ae    = zeros(mesh.nel)
    be    = zeros(mesh.nel)
    be_o2 = zeros(mesh.nel,nen)
    ze    = zeros(mesh.nel,2)
    pe    = zeros(mesh.nel,mesh.nf_el,nen)
    me    = zeros(mesh.nel,nen,nen)
    mei   = zeros(mesh.nel,nen,nen)
    N     = zeros(mesh.nel,mesh.nf_el,nen)
    dj    = zeros(mesh.nel,mesh.nf_el,nen)
    rj    = zeros(mesh.nel,mesh.nf_el,nen)

    # Assemble FCFV elements
    @tturbo for iel=1:mesh.nel

        be[iel] = be[iel] + (o2==0)*mesh.vole[iel]*se[iel]

        for ifac=1:mesh.nf_el

            nodei = mesh.e2f[iel,ifac]
            bc    = mesh.bc[nodei]
            dAi   = mesh.dA[iel,ifac]
            ni_x  = mesh.n_x[iel,ifac]
            ni_y  = mesh.n_y[iel,ifac]
            taui  = StabParam(tau*mesh.ke[iel],dAi,mesh.vole[iel],mesh.type)                              # Stabilisation parameter for the face

            N[iel,ifac,1] = 1.0
            N[iel,ifac,2] = mesh.xf[nodei] - mesh.xc[iel]
            N[iel,ifac,3] = mesh.yf[nodei] - mesh.yc[iel]

            pe[iel,ifac,1] = 1.0
            pe[iel,ifac,2] = mesh.xf[nodei] - mesh.xc[iel]
            pe[iel,ifac,3] = mesh.yf[nodei] - mesh.yc[iel]

            # Assemble
            ze[iel,1] += (bc==1) * dAi*ni_x*Tdir[nodei]  # Dirichlet
            ze[iel,2] += (bc==1) * dAi*ni_y*Tdir[nodei]  # Dirichlet
            ae[iel]   +=           dAi*taui
            be[iel]   += (bc==1) *  (o2==0) * dAi*taui*Tdir[nodei]  # Dirichlet

        end
    end

    if o2==1 # The remaining of this function is only done if second order FCFV is used

        # me matrix
        @tturbo for iel=1:mesh.nel
            for ifac=1:mesh.nf_el

                nodei = mesh.e2f[iel,ifac]
                bc    = mesh.bc[nodei]
                dAi   = mesh.dA[iel,ifac]
                taui  = StabParam(tau*mesh.ke[iel],dAi,mesh.vole[iel],mesh.type)

                for in=1:nen
                    dj[iel,ifac,in] =  dAi * N[iel,ifac,in] * Tdir[nodei]
                    rj[iel,ifac,in] =  dAi * N[iel,ifac,in]
                    for jn=1:nen
                        me[iel,in,jn] += pe[iel,ifac,jn] * taui * dAi * N[iel,ifac,in]
                    end
                end
            end
        end

        # Inverse of me matrix
        cf11 =  1.0; cf12 =-1.0; cf13 =  1.0;
        cf21 = -1.0; cf22 = 1.0; cf23 = -1.0;
        cf31 =  1.0; cf32 =-1.0; cf33 =  1.0;
        @tturbo for iel=1:mesh.nel
            for ifac=1:mesh.nf_el
                Mm11 = me[iel,2,2] * me[iel,3,3] - me[iel,2,3] * me[iel,3,2]
                Mm12 = me[iel,2,1] * me[iel,3,3] - me[iel,2,3] * me[iel,3,1]
                Mm13 = me[iel,2,1] * me[iel,3,2] - me[iel,2,2] * me[iel,3,1]
                Mm21 = me[iel,1,2] * me[iel,3,3] - me[iel,1,3] * me[iel,3,2]
                Mm22 = me[iel,1,1] * me[iel,3,3] - me[iel,1,3] * me[iel,3,1]
                Mm23 = me[iel,1,1] * me[iel,3,2] - me[iel,1,2] * me[iel,3,1]
                Mm31 = me[iel,1,2] * me[iel,2,3] - me[iel,1,3] * me[iel,2,2]
                Mm32 = me[iel,1,1] * me[iel,2,3] - me[iel,1,3] * me[iel,2,1]
                Mm33 = me[iel,1,1] * me[iel,2,2] - me[iel,1,2] * me[iel,2,1]
                Ad11 = cf11*Mm11; Ad12 = cf21*Mm21; Ad13 = cf31*Mm31;
                Ad21 = cf12*Mm12; Ad22 = cf22*Mm22; Ad23 = cf32*Mm32;
                Ad31 = cf13*Mm13; Ad32 = cf23*Mm23; Ad33 = cf33*Mm33;
                DetM = me[iel,1,1] * Mm11 - me[iel,1,2]*Mm12 + me[iel,1,3]*Mm13
                mei[iel,1,1] = 1.0/DetM*Ad11; mei[iel,1,2] = 1.0/DetM*Ad12; mei[iel,1,3] = 1.0/DetM*Ad13;
                mei[iel,2,1] = 1.0/DetM*Ad21; mei[iel,2,2] = 1.0/DetM*Ad22; mei[iel,2,3] = 1.0/DetM*Ad23;
                mei[iel,3,1] = 1.0/DetM*Ad31; mei[iel,3,2] = 1.0/DetM*Ad32; mei[iel,3,3] = 1.0/DetM*Ad33;
            end
        end

        # Assembly of b vector
        @tturbo for iel=1:mesh.nel

            be_o2[iel,1] = mesh.vole[iel]*se[iel]

            for ifac=1:mesh.nf_el

                nodei = mesh.e2f[iel,ifac]
                bc    = mesh.bc[nodei]
                dAi   = mesh.dA[iel,ifac]
                taui  = StabParam(tau*mesh.ke[iel],dAi,mesh.vole[iel],mesh.type)                              # Stabilisation parameter for the face

                for in=1:nen
                    be_o2[iel,in] += (bc==1) * taui * dj[iel,ifac,in]
                end

            end
        end
    end
    return ae, be, be_o2, ze, pe, mei, pe, rj
end

#--------------------------------------------------------------------#

function ComputeElementValues_o2(mesh, uh, ae, be, be_o2, ze, rj, mei, Tdir, tau, o2)
    nen         = 3
    ue          = zeros(mesh.nel)
    ue1         = zeros(mesh.nel, nen);
    ue2         = zeros(mesh.nel, nen);
    qx          = zeros(mesh.nel);
    qy          = zeros(mesh.nel);

    @tturbo for iel=1:mesh.nel

        ue[iel]  =  (o2==0) * be[iel]/ae[iel]
        for in=1:nen
            ue1[iel,in]  =  (o2==1) * be_o2[iel,in]
        end

        qx[iel]  = -mesh.ke[iel]/mesh.vole[iel]*ze[iel,1]
        qy[iel]  = -mesh.ke[iel]/mesh.vole[iel]*ze[iel,2]

        for ifac=1:mesh.nf_el

            # Face
            nodei = mesh.e2f[iel,ifac]
            bc    = mesh.bc[nodei]
            dAi   = mesh.dA[iel,ifac]
            ni_x  = mesh.n_x[iel,ifac]
            ni_y  = mesh.n_y[iel,ifac]
            taui  = StabParam(tau*mesh.ke[iel],dAi,mesh.vole[iel],mesh.type)      # Stabilisation parameter for the face

            # First order
            O1 = (bc!=1) & (o2==0)
            ue[iel] += O1 * dAi*taui*uh[mesh.e2f[iel, ifac]]/ae[iel]
            # Second order
            O2       = (bc!=1) & (o2==1)
            for in=1:nen
                ue1[iel,in] += O2 * taui*rj[iel,ifac,in]*uh[mesh.e2f[iel, ifac]]
            end
            qx[iel] -= (bc!=1) *  mesh.ke[iel]/mesh.vole[iel]*dAi*ni_x*uh[mesh.e2f[iel, ifac]]
            qy[iel] -= (bc!=1) *  mesh.ke[iel]/mesh.vole[iel]*dAi*ni_y*uh[mesh.e2f[iel, ifac]]
        end
        # inv(me) * ue
        ue2[iel,1] = (o2==1) * (mei[iel,1,1] * ue1[iel,1] + mei[iel,1,2] * ue1[iel,2] + mei[iel,1,3] * ue1[iel,3])
        ue2[iel,2] = (o2==1) * (mei[iel,2,1] * ue1[iel,1] + mei[iel,2,2] * ue1[iel,2] + mei[iel,2,3] * ue1[iel,3])
        ue2[iel,3] = (o2==1) * (mei[iel,3,1] * ue1[iel,1] + mei[iel,3,2] * ue1[iel,2] + mei[iel,3,3] * ue1[iel,3])
    end

    if o2==1 ue .= ue2[:,1] end # extract first values of the ue solution vector (linear function evaluated at cell centroid)

    return ue, qx, qy
end

#--------------------------------------------------------------------#

function ElementAssemblyLoop_o2(mesh, ae, be, be_o2, ze, mei, pe, rj, Tdir, Tneu, tau, o2)
    # Assemble element matrices and rhs
    f    = zeros(mesh.nf);
    Kv   = zeros(mesh.nel, mesh.nf_el, mesh.nf_el)
    fv   = zeros(mesh.nel, mesh.nf_el)

    @tturbo for iel=1:mesh.nel

        for ifac=1:mesh.nf_el

            nodei = mesh.e2f[iel,ifac]
            bci   = mesh.bc[nodei]
            dAi   = mesh.dA[iel,ifac]
            ni_x  = mesh.n_x[iel,ifac]
            ni_y  = mesh.n_y[iel,ifac]
            taui  = StabParam(tau*mesh.ke[iel],dAi,mesh.vole[iel], mesh.type)

            for jfac=1:mesh.nf_el

                nodej = mesh.e2f[iel,jfac]
                bcj   = mesh.bc[nodej]
                dAj   = mesh.dA[iel,jfac]
                nj_x  = mesh.n_x[iel,jfac]
                nj_y  = mesh.n_y[iel,jfac]
                tauj  = StabParam(tau*mesh.ke[iel],dAj,mesh.vole[iel], mesh.type)

                # Delta
                del = 0.0 + (ifac==jfac)*1.0

                # Element matrix
                nitnj = ni_x*nj_x + ni_y*nj_y;
                res1  = 1.0/ae[iel] * dAj
                # inv(me) * dj
                meid1 = mei[iel,1,1] * rj[iel,jfac,1] + mei[iel,1,2] * rj[iel,jfac,2] + mei[iel,1,3] * rj[iel,jfac,3]
                meid2 = mei[iel,2,1] * rj[iel,jfac,1] + mei[iel,2,2] * rj[iel,jfac,2] + mei[iel,2,3] * rj[iel,jfac,3]
                meid3 = mei[iel,3,1] * rj[iel,jfac,1] + mei[iel,3,2] * rj[iel,jfac,2] + mei[iel,3,3] * rj[iel,jfac,3]
                # pe' * inv(me) * dj
                res2   =  (pe[iel,ifac,1] * meid1 + pe[iel,ifac,2] * meid2 + pe[iel,ifac,3] * meid3)
                res   = (o2==0) * res1 + (o2==1) * res2
                Ke_ij =-dAi * (res * taui*tauj - mesh.ke[iel]/mesh.vole[iel]*dAj*nitnj - taui*del);
                yes   = (bci!=1) & (bcj!=1)
                Kv[iel,ifac,jfac] = yes * Ke_ij
            end
            # RHS
            Xi     = 0.0 + (bci==2)*1.0;
            ti     = Tneu[nodei]
            nitze  = ni_x*ze[iel,1] + ni_y*ze[iel,2]
            res1    = 1.0/ae[iel]*be[iel]
            # inv(me) * be
            meid1  = mei[iel,1,1] * be_o2[iel,1] + mei[iel,1,2] * be_o2[iel,2] + mei[iel,1,3] * be_o2[iel,3]
            meid2  = mei[iel,2,1] * be_o2[iel,1] + mei[iel,2,2] * be_o2[iel,2] + mei[iel,2,3] * be_o2[iel,3]
            meid3  = mei[iel,3,1] * be_o2[iel,1] + mei[iel,3,2] * be_o2[iel,2] + mei[iel,3,3] * be_o2[iel,3]
            res2   = (pe[iel,ifac,1] * meid1 + pe[iel,ifac,2] * meid2 + pe[iel,ifac,3] * meid3)
            res    = (o2==0) * res1 + (o2==1) * res2
            fe_i   = (bci!=1) * -dAi * (mesh.ke[iel]/mesh.vole[iel]*nitze - ti*Xi - res*taui)
            fv[iel,ifac] += (bci!=1) * fe_i
            # Dirichlet nodes
            Kv[iel,ifac,ifac] += (bci==1) * 1.0
            fv[iel,ifac]      += (bci==1) * Tdir[nodei]
        end
        # if iel==1
        #     println(Kv[iel,:,:])
        #     println(fv[iel,:])
        # end
    end
    return Kv, fv
end


text:
for m in [BabyPOMDP(), SimpleGridWorld()]
    ts = transition_matrices(m)
    for a in actions(m)
        @test a in keys(ts)
        t = ts[a]
        @test t isa AbstractMatrix
        for i in size(t, 1)
            @test sum(t[i, :]) ≈ 1.0
        end
    end

    rs = reward_vectors(m)
    for a in actions(m)
        @test a in keys(rs)
        r = rs[a]
        @test r isa AbstractVector
        @test r == POMDPModelTools.policy_reward_vector(m, FunctionPolicy(s->a))
    end
end

ext: jl


text:
##### Base interpolations (do not require intermediate / nested computations)

export interp!

function interp! end

interp!(A::T, B::T, grid::Grid) where {T <: AbstractField} = (A .= B)

#####
##### CellCenter <-> CellFace
#####

function interp!(cent::CellCenter, face::CellFace{dim}, grid::Grid) where {dim}
    FT = eltype(cent)
    @inbounds for (Ipre, i, Ipost) in sweep(cent, dim)
        cent[Ipre, i, Ipost] = FT(0.5)*face[Ipre, i, Ipost] +
                               FT(0.5)*face[Ipre, i+1, Ipost]
    end
    nothing
end

function interp!(face::CellFace{dim}, cent::CellCenter, grid::Grid) where {dim}
    iR = over_points(grid.c[dim], Boundary(), Vertex1D())
    @inbounds for (Ipre, i, Ipost) in sweep(cent, dim, iR)
        D = grid.c[dim].interp.diag[i-1]
        U = grid.c[dim].interp.upper[i-1]
        face[Ipre, i, Ipost] = D*cent[Ipre, i-1, Ipost] + U*cent[Ipre, i, Ipost]
    end
    nothing
end

#####
##### CellCorner <-> CellEdge
#####

function interp!(corn::CellCorner, edge::CellEdge{dim}, grid::Grid) where {dim}
    iR = over_points(grid.c[dim], Boundary(), Vertex1D())
    @inbounds for (Ipre, i, Ipost) in sweep(corn, dim, iR)
        D = grid.c[dim].interp.diag[i-1]
        U = grid.c[dim].interp.upper[i-1]
        corn[Ipre, i, Ipost] = D*edge[Ipre, i-1, Ipost] + U*edge[Ipre, i, Ipost]
    end
    nothing
end

function interp!(edge::CellEdge{dim}, corn::CellCorner, grid::Grid) where {dim}
    FT = eltype(corn)
    @inbounds for (Ipre, i, Ipost) in sweep(edge, dim)
        edge[Ipre, i, Ipost] = FT(0.5)*corn[Ipre, i, Ipost] +
                               FT(0.5)*corn[Ipre, i+1, Ipost]
    end
    nothing
end

#####
##### CellFace{facedim} <-> CellEdge{edgedim}, facedim ≠ edgedim
#####

function interp!(face::CellFace{facedim}, edge::CellEdge{edgedim}, grid::Grid) where {facedim,edgedim}
    FT = eltype(edge)
    interp_dim = orthog(facedim, edgedim)
    @inbounds for (Ipre, i, Ipost) in sweep(face, interp_dim)
        face[Ipre, i, Ipost] = FT(0.5)*edge[Ipre, i, Ipost] +
                               FT(0.5)*edge[Ipre, i+1, Ipost]
    end
    nothing
end

function interp!(edge::CellEdge{edgedim}, face::CellFace{facedim}, grid::Grid) where {facedim,edgedim}
    interp_dim = orthog(facedim, edgedim)
    iR = over_points(grid.c[interp_dim], Boundary(), Vertex1D())
    @inbounds for (Ipre, i, Ipost) in sweep(edge, interp_dim, iR)
        D = grid.c[interp_dim].interp.diag[i-1]
        U = grid.c[interp_dim].interp.upper[i-1]
        edge[Ipre, i, Ipost] = D*face[Ipre, i-1, Ipost] + U*face[Ipre, i, Ipost]
    end
    nothing
end


text:
function solve(i::ElementaryPathInstance{T}, ::DynamicProgramming) where {T}
    return solve(i, BellmanFordAlgorithm())
end

function solve(i::ElementaryPathInstance{T}, ::BellmanFordAlgorithm) where {T}
    # Assumption: no positive-cost cycle in the graph.
    V = Dict{T, Float64}()
    S = Dict{T, Vector{Edge{T}}}()

    # Initialise.
    for v in vertices(i.graph)
        V[v] = -Inf
        S[v] = Edge{T}[]
    end
    V[i.src] = 0.0

    # Dynamic part.
    for _ in 1:ne(i.graph)
        changes = false # Stop the algorithm as soon as it no more makes progress.

        for e in edges(i.graph)
            u, v = src(e), dst(e)
            w = i.rewards[Edge(u, v)]

            # If using the solution to the currently explored subproblem would
            # lead to a cycle, skip it.
            if any(src(e) == v for e in S[u])
                continue
            end

            # Compute the maximum: is passing through w advantageous?
            if V[u] + w > V[v]
                V[v] = V[u] + w
                S[v] = vcat(S[u], Edge(u, v))

                changes = true
            end
        end

        if !changes
            break
        end
    end

    # Checking existence of negative-cost cycle.
    for e in edges(i.graph)
        u, v = src(e), dst(e)
        w = i.rewards[Edge(u, v)]

        if V[u] + w > V[v]
            @warn(
                "The graph contains a positive-cost cycle around edge $(u) -> $(v)."
            )
        end
    end

    return ElementaryPathSolution(i, S[i.dst], S)
end


text:
#=

# tf.keras.applications.EfficientNetB0:
# Downloading data from https://storage.googleapis.com/keras-applications/efficientnetb0.h5 => ~/.keras/models

>>> model = keras.applications.EfficientNetB0(weights='imagenet')
>>> model.summary()
Model: "efficientnetb0"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            [(None, 224, 224, 3) 0
__________________________________________________________________________________________________
rescaling (Rescaling)           (None, 224, 224, 3)  0           input_1[0][0]
__________________________________________________________________________________________________
normalization (Normalization)   (None, 224, 224, 3)  7           rescaling[0][0]
__________________________________________________________________________________________________
stem_conv_pad (ZeroPadding2D)   (None, 225, 225, 3)  0           normalization[0][0]
__________________________________________________________________________________________________
stem_conv (Conv2D)              (None, 112, 112, 32) 864         stem_conv_pad[0][0]
__________________________________________________________________________________________________
stem_bn (BatchNormalization)    (None, 112, 112, 32) 128         stem_conv[0][0]
__________________________________________________________________________________________________
stem_activation (Activation)    (None, 112, 112, 32) 0           stem_bn[0][0]
__________________________________________________________________________________________________
block1a_dwconv (DepthwiseConv2D (None, 112, 112, 32) 288         stem_activation[0][0]
__________________________________________________________________________________________________
block1a_bn (BatchNormalization) (None, 112, 112, 32) 128         block1a_dwconv[0][0]
__________________________________________________________________________________________________
block1a_activation (Activation) (None, 112, 112, 32) 0           block1a_bn[0][0]
__________________________________________________________________________________________________
block1a_se_squeeze (GlobalAvera (None, 32)           0           block1a_activation[0][0]
__________________________________________________________________________________________________
block1a_se_reshape (Reshape)    (None, 1, 1, 32)     0           block1a_se_squeeze[0][0]
__________________________________________________________________________________________________
block1a_se_reduce (Conv2D)      (None, 1, 1, 8)      264         block1a_se_reshape[0][0]
__________________________________________________________________________________________________
block1a_se_expand (Conv2D)      (None, 1, 1, 32)     288         block1a_se_reduce[0][0]
__________________________________________________________________________________________________
block1a_se_excite (Multiply)    (None, 112, 112, 32) 0           block1a_activation[0][0]
                                                                 block1a_se_expand[0][0]
__________________________________________________________________________________________________
block1a_project_conv (Conv2D)   (None, 112, 112, 16) 512         block1a_se_excite[0][0]
__________________________________________________________________________________________________
block1a_project_bn (BatchNormal (None, 112, 112, 16) 64          block1a_project_conv[0][0]
__________________________________________________________________________________________________
block2a_expand_conv (Conv2D)    (None, 112, 112, 96) 1536        block1a_project_bn[0][0]
__________________________________________________________________________________________________
block2a_expand_bn (BatchNormali (None, 112, 112, 96) 384         block2a_expand_conv[0][0]
__________________________________________________________________________________________________
block2a_expand_activation (Acti (None, 112, 112, 96) 0           block2a_expand_bn[0][0]
__________________________________________________________________________________________________
block2a_dwconv_pad (ZeroPadding (None, 113, 113, 96) 0           block2a_expand_activation[0][0]
__________________________________________________________________________________________________
block2a_dwconv (DepthwiseConv2D (None, 56, 56, 96)   864         block2a_dwconv_pad[0][0]
__________________________________________________________________________________________________
block2a_bn (BatchNormalization) (None, 56, 56, 96)   384         block2a_dwconv[0][0]
__________________________________________________________________________________________________
block2a_activation (Activation) (None, 56, 56, 96)   0           block2a_bn[0][0]
__________________________________________________________________________________________________
block2a_se_squeeze (GlobalAvera (None, 96)           0           block2a_activation[0][0]
__________________________________________________________________________________________________
block2a_se_reshape (Reshape)    (None, 1, 1, 96)     0           block2a_se_squeeze[0][0]
__________________________________________________________________________________________________
block2a_se_reduce (Conv2D)      (None, 1, 1, 4)      388         block2a_se_reshape[0][0]
__________________________________________________________________________________________________
block2a_se_expand (Conv2D)      (None, 1, 1, 96)     480         block2a_se_reduce[0][0]
__________________________________________________________________________________________________
block2a_se_excite (Multiply)    (None, 56, 56, 96)   0           block2a_activation[0][0]
                                                                 block2a_se_expand[0][0]
__________________________________________________________________________________________________
block2a_project_conv (Conv2D)   (None, 56, 56, 24)   2304        block2a_se_excite[0][0]
__________________________________________________________________________________________________
block2a_project_bn (BatchNormal (None, 56, 56, 24)   96          block2a_project_conv[0][0]
__________________________________________________________________________________________________
block2b_expand_conv (Conv2D)    (None, 56, 56, 144)  3456        block2a_project_bn[0][0]
__________________________________________________________________________________________________
block2b_expand_bn (BatchNormali (None, 56, 56, 144)  576         block2b_expand_conv[0][0]
__________________________________________________________________________________________________
block2b_expand_activation (Acti (None, 56, 56, 144)  0           block2b_expand_bn[0][0]
__________________________________________________________________________________________________
block2b_dwconv (DepthwiseConv2D (None, 56, 56, 144)  1296        block2b_expand_activation[0][0]
__________________________________________________________________________________________________
block2b_bn (BatchNormalization) (None, 56, 56, 144)  576         block2b_dwconv[0][0]
__________________________________________________________________________________________________
block2b_activation (Activation) (None, 56, 56, 144)  0           block2b_bn[0][0]
__________________________________________________________________________________________________
block2b_se_squeeze (GlobalAvera (None, 144)          0           block2b_activation[0][0]
__________________________________________________________________________________________________
block2b_se_reshape (Reshape)    (None, 1, 1, 144)    0           block2b_se_squeeze[0][0]
__________________________________________________________________________________________________
block2b_se_reduce (Conv2D)      (None, 1, 1, 6)      870         block2b_se_reshape[0][0]
__________________________________________________________________________________________________
block2b_se_expand (Conv2D)      (None, 1, 1, 144)    1008        block2b_se_reduce[0][0]
__________________________________________________________________________________________________
block2b_se_excite (Multiply)    (None, 56, 56, 144)  0           block2b_activation[0][0]
                                                                 block2b_se_expand[0][0]
__________________________________________________________________________________________________
block2b_project_conv (Conv2D)   (None, 56, 56, 24)   3456        block2b_se_excite[0][0]
__________________________________________________________________________________________________
block2b_project_bn (BatchNormal (None, 56, 56, 24)   96          block2b_project_conv[0][0]
__________________________________________________________________________________________________
block2b_drop (Dropout)          (None, 56, 56, 24)   0           block2b_project_bn[0][0]
__________________________________________________________________________________________________
block2b_add (Add)               (None, 56, 56, 24)   0           block2b_drop[0][0]
                                                                 block2a_project_bn[0][0]
__________________________________________________________________________________________________
block3a_expand_conv (Conv2D)    (None, 56, 56, 144)  3456        block2b_add[0][0]
__________________________________________________________________________________________________
block3a_expand_bn (BatchNormali (None, 56, 56, 144)  576         block3a_expand_conv[0][0]
__________________________________________________________________________________________________
block3a_expand_activation (Acti (None, 56, 56, 144)  0           block3a_expand_bn[0][0]
__________________________________________________________________________________________________
block3a_dwconv_pad (ZeroPadding (None, 59, 59, 144)  0           block3a_expand_activation[0][0]
__________________________________________________________________________________________________
block3a_dwconv (DepthwiseConv2D (None, 28, 28, 144)  3600        block3a_dwconv_pad[0][0]
__________________________________________________________________________________________________
block3a_bn (BatchNormalization) (None, 28, 28, 144)  576         block3a_dwconv[0][0]
__________________________________________________________________________________________________
block3a_activation (Activation) (None, 28, 28, 144)  0           block3a_bn[0][0]
__________________________________________________________________________________________________
block3a_se_squeeze (GlobalAvera (None, 144)          0           block3a_activation[0][0]
__________________________________________________________________________________________________
block3a_se_reshape (Reshape)    (None, 1, 1, 144)    0           block3a_se_squeeze[0][0]
__________________________________________________________________________________________________
block3a_se_reduce (Conv2D)      (None, 1, 1, 6)      870         block3a_se_reshape[0][0]
__________________________________________________________________________________________________
block3a_se_expand (Conv2D)      (None, 1, 1, 144)    1008        block3a_se_reduce[0][0]
__________________________________________________________________________________________________
block3a_se_excite (Multiply)    (None, 28, 28, 144)  0           block3a_activation[0][0]
                                                                 block3a_se_expand[0][0]
__________________________________________________________________________________________________
block3a_project_conv (Conv2D)   (None, 28, 28, 40)   5760        block3a_se_excite[0][0]
__________________________________________________________________________________________________
block3a_project_bn (BatchNormal (None, 28, 28, 40)   160         block3a_project_conv[0][0]
__________________________________________________________________________________________________
block3b_expand_conv (Conv2D)    (None, 28, 28, 240)  9600        block3a_project_bn[0][0]
__________________________________________________________________________________________________
block3b_expand_bn (BatchNormali (None, 28, 28, 240)  960         block3b_expand_conv[0][0]
__________________________________________________________________________________________________
block3b_expand_activation (Acti (None, 28, 28, 240)  0           block3b_expand_bn[0][0]
__________________________________________________________________________________________________
block3b_dwconv (DepthwiseConv2D (None, 28, 28, 240)  6000        block3b_expand_activation[0][0]
__________________________________________________________________________________________________
block3b_bn (BatchNormalization) (None, 28, 28, 240)  960         block3b_dwconv[0][0]
__________________________________________________________________________________________________
block3b_activation (Activation) (None, 28, 28, 240)  0           block3b_bn[0][0]
__________________________________________________________________________________________________
block3b_se_squeeze (GlobalAvera (None, 240)          0           block3b_activation[0][0]
__________________________________________________________________________________________________
block3b_se_reshape (Reshape)    (None, 1, 1, 240)    0           block3b_se_squeeze[0][0]
__________________________________________________________________________________________________
block3b_se_reduce (Conv2D)      (None, 1, 1, 10)     2410        block3b_se_reshape[0][0]
__________________________________________________________________________________________________
block3b_se_expand (Conv2D)      (None, 1, 1, 240)    2640        block3b_se_reduce[0][0]
__________________________________________________________________________________________________
block3b_se_excite (Multiply)    (None, 28, 28, 240)  0           block3b_activation[0][0]
                                                                 block3b_se_expand[0][0]
__________________________________________________________________________________________________
block3b_project_conv (Conv2D)   (None, 28, 28, 40)   9600        block3b_se_excite[0][0]
__________________________________________________________________________________________________
block3b_project_bn (BatchNormal (None, 28, 28, 40)   160         block3b_project_conv[0][0]
__________________________________________________________________________________________________
block3b_drop (Dropout)          (None, 28, 28, 40)   0           block3b_project_bn[0][0]
__________________________________________________________________________________________________
block3b_add (Add)               (None, 28, 28, 40)   0           block3b_drop[0][0]
                                                                 block3a_project_bn[0][0]
__________________________________________________________________________________________________
block4a_expand_conv (Conv2D)    (None, 28, 28, 240)  9600        block3b_add[0][0]
__________________________________________________________________________________________________
block4a_expand_bn (BatchNormali (None, 28, 28, 240)  960         block4a_expand_conv[0][0]
__________________________________________________________________________________________________
block4a_expand_activation (Acti (None, 28, 28, 240)  0           block4a_expand_bn[0][0]
__________________________________________________________________________________________________
block4a_dwconv_pad (ZeroPadding (None, 29, 29, 240)  0           block4a_expand_activation[0][0]
__________________________________________________________________________________________________
block4a_dwconv (DepthwiseConv2D (None, 14, 14, 240)  2160        block4a_dwconv_pad[0][0]
__________________________________________________________________________________________________
block4a_bn (BatchNormalization) (None, 14, 14, 240)  960         block4a_dwconv[0][0]
__________________________________________________________________________________________________
block4a_activation (Activation) (None, 14, 14, 240)  0           block4a_bn[0][0]
__________________________________________________________________________________________________
block4a_se_squeeze (GlobalAvera (None, 240)          0           block4a_activation[0][0]
__________________________________________________________________________________________________
block4a_se_reshape (Reshape)    (None, 1, 1, 240)    0           block4a_se_squeeze[0][0]
__________________________________________________________________________________________________
block4a_se_reduce (Conv2D)      (None, 1, 1, 10)     2410        block4a_se_reshape[0][0]
__________________________________________________________________________________________________
block4a_se_expand (Conv2D)      (None, 1, 1, 240)    2640        block4a_se_reduce[0][0]
__________________________________________________________________________________________________
block4a_se_excite (Multiply)    (None, 14, 14, 240)  0           block4a_activation[0][0]
                                                                 block4a_se_expand[0][0]
__________________________________________________________________________________________________
block4a_project_conv (Conv2D)   (None, 14, 14, 80)   19200       block4a_se_excite[0][0]
__________________________________________________________________________________________________
block4a_project_bn (BatchNormal (None, 14, 14, 80)   320         block4a_project_conv[0][0]
__________________________________________________________________________________________________
block4b_expand_conv (Conv2D)    (None, 14, 14, 480)  38400       block4a_project_bn[0][0]
__________________________________________________________________________________________________
block4b_expand_bn (BatchNormali (None, 14, 14, 480)  1920        block4b_expand_conv[0][0]
__________________________________________________________________________________________________
block4b_expand_activation (Acti (None, 14, 14, 480)  0           block4b_expand_bn[0][0]
__________________________________________________________________________________________________
block4b_dwconv (DepthwiseConv2D (None, 14, 14, 480)  4320        block4b_expand_activation[0][0]
__________________________________________________________________________________________________
block4b_bn (BatchNormalization) (None, 14, 14, 480)  1920        block4b_dwconv[0][0]
__________________________________________________________________________________________________
block4b_activation (Activation) (None, 14, 14, 480)  0           block4b_bn[0][0]
__________________________________________________________________________________________________
block4b_se_squeeze (GlobalAvera (None, 480)          0           block4b_activation[0][0]
__________________________________________________________________________________________________
block4b_se_reshape (Reshape)    (None, 1, 1, 480)    0           block4b_se_squeeze[0][0]
__________________________________________________________________________________________________
block4b_se_reduce (Conv2D)      (None, 1, 1, 20)     9620        block4b_se_reshape[0][0]
__________________________________________________________________________________________________
block4b_se_expand (Conv2D)      (None, 1, 1, 480)    10080       block4b_se_reduce[0][0]
__________________________________________________________________________________________________
block4b_se_excite (Multiply)    (None, 14, 14, 480)  0           block4b_activation[0][0]
                                                                 block4b_se_expand[0][0]
__________________________________________________________________________________________________
block4b_project_conv (Conv2D)   (None, 14, 14, 80)   38400       block4b_se_excite[0][0]
__________________________________________________________________________________________________
block4b_project_bn (BatchNormal (None, 14, 14, 80)   320         block4b_project_conv[0][0]
__________________________________________________________________________________________________
block4b_drop (Dropout)          (None, 14, 14, 80)   0           block4b_project_bn[0][0]
__________________________________________________________________________________________________
block4b_add (Add)               (None, 14, 14, 80)   0           block4b_drop[0][0]
                                                                 block4a_project_bn[0][0]
__________________________________________________________________________________________________
block4c_expand_conv (Conv2D)    (None, 14, 14, 480)  38400       block4b_add[0][0]
__________________________________________________________________________________________________
block4c_expand_bn (BatchNormali (None, 14, 14, 480)  1920        block4c_expand_conv[0][0]
__________________________________________________________________________________________________
block4c_expand_activation (Acti (None, 14, 14, 480)  0           block4c_expand_bn[0][0]
__________________________________________________________________________________________________
block4c_dwconv (DepthwiseConv2D (None, 14, 14, 480)  4320        block4c_expand_activation[0][0]
__________________________________________________________________________________________________
block4c_bn (BatchNormalization) (None, 14, 14, 480)  1920        block4c_dwconv[0][0]
__________________________________________________________________________________________________
block4c_activation (Activation) (None, 14, 14, 480)  0           block4c_bn[0][0]
__________________________________________________________________________________________________
block4c_se_squeeze (GlobalAvera (None, 480)          0           block4c_activation[0][0]
__________________________________________________________________________________________________
block4c_se_reshape (Reshape)    (None, 1, 1, 480)    0           block4c_se_squeeze[0][0]
__________________________________________________________________________________________________
block4c_se_reduce (Conv2D)      (None, 1, 1, 20)     9620        block4c_se_reshape[0][0]
__________________________________________________________________________________________________
block4c_se_expand (Conv2D)      (None, 1, 1, 480)    10080       block4c_se_reduce[0][0]
__________________________________________________________________________________________________
block4c_se_excite (Multiply)    (None, 14, 14, 480)  0           block4c_activation[0][0]
                                                                 block4c_se_expand[0][0]
__________________________________________________________________________________________________
block4c_project_conv (Conv2D)   (None, 14, 14, 80)   38400       block4c_se_excite[0][0]
__________________________________________________________________________________________________
block4c_project_bn (BatchNormal (None, 14, 14, 80)   320         block4c_project_conv[0][0]
__________________________________________________________________________________________________
block4c_drop (Dropout)          (None, 14, 14, 80)   0           block4c_project_bn[0][0]
__________________________________________________________________________________________________
block4c_add (Add)               (None, 14, 14, 80)   0           block4c_drop[0][0]
                                                                 block4b_add[0][0]
__________________________________________________________________________________________________
block5a_expand_conv (Conv2D)    (None, 14, 14, 480)  38400       block4c_add[0][0]
__________________________________________________________________________________________________
block5a_expand_bn (BatchNormali (None, 14, 14, 480)  1920        block5a_expand_conv[0][0]
__________________________________________________________________________________________________
block5a_expand_activation (Acti (None, 14, 14, 480)  0           block5a_expand_bn[0][0]
__________________________________________________________________________________________________
block5a_dwconv (DepthwiseConv2D (None, 14, 14, 480)  12000       block5a_expand_activation[0][0]
__________________________________________________________________________________________________
block5a_bn (BatchNormalization) (None, 14, 14, 480)  1920        block5a_dwconv[0][0]
__________________________________________________________________________________________________
block5a_activation (Activation) (None, 14, 14, 480)  0           block5a_bn[0][0]
__________________________________________________________________________________________________
block5a_se_squeeze (GlobalAvera (None, 480)          0           block5a_activation[0][0]
__________________________________________________________________________________________________
block5a_se_reshape (Reshape)    (None, 1, 1, 480)    0           block5a_se_squeeze[0][0]
__________________________________________________________________________________________________
block5a_se_reduce (Conv2D)      (None, 1, 1, 20)     9620        block5a_se_reshape[0][0]
__________________________________________________________________________________________________
block5a_se_expand (Conv2D)      (None, 1, 1, 480)    10080       block5a_se_reduce[0][0]
__________________________________________________________________________________________________
block5a_se_excite (Multiply)    (None, 14, 14, 480)  0           block5a_activation[0][0]
                                                                 block5a_se_expand[0][0]
__________________________________________________________________________________________________
block5a_project_conv (Conv2D)   (None, 14, 14, 112)  53760       block5a_se_excite[0][0]
__________________________________________________________________________________________________
block5a_project_bn (BatchNormal (None, 14, 14, 112)  448         block5a_project_conv[0][0]
__________________________________________________________________________________________________
block5b_expand_conv (Conv2D)    (None, 14, 14, 672)  75264       block5a_project_bn[0][0]
__________________________________________________________________________________________________
block5b_expand_bn (BatchNormali (None, 14, 14, 672)  2688        block5b_expand_conv[0][0]
__________________________________________________________________________________________________
block5b_expand_activation (Acti (None, 14, 14, 672)  0           block5b_expand_bn[0][0]
__________________________________________________________________________________________________
block5b_dwconv (DepthwiseConv2D (None, 14, 14, 672)  16800       block5b_expand_activation[0][0]
__________________________________________________________________________________________________
block5b_bn (BatchNormalization) (None, 14, 14, 672)  2688        block5b_dwconv[0][0]
__________________________________________________________________________________________________
block5b_activation (Activation) (None, 14, 14, 672)  0           block5b_bn[0][0]
__________________________________________________________________________________________________
block5b_se_squeeze (GlobalAvera (None, 672)          0           block5b_activation[0][0]
__________________________________________________________________________________________________
block5b_se_reshape (Reshape)    (None, 1, 1, 672)    0           block5b_se_squeeze[0][0]
__________________________________________________________________________________________________
block5b_se_reduce (Conv2D)      (None, 1, 1, 28)     18844       block5b_se_reshape[0][0]
__________________________________________________________________________________________________
block5b_se_expand (Conv2D)      (None, 1, 1, 672)    19488       block5b_se_reduce[0][0]
__________________________________________________________________________________________________
block5b_se_excite (Multiply)    (None, 14, 14, 672)  0           block5b_activation[0][0]
                                                                 block5b_se_expand[0][0]
__________________________________________________________________________________________________
block5b_project_conv (Conv2D)   (None, 14, 14, 112)  75264       block5b_se_excite[0][0]
__________________________________________________________________________________________________
block5b_project_bn (BatchNormal (None, 14, 14, 112)  448         block5b_project_conv[0][0]
__________________________________________________________________________________________________
block5b_drop (Dropout)          (None, 14, 14, 112)  0           block5b_project_bn[0][0]
__________________________________________________________________________________________________
block5b_add (Add)               (None, 14, 14, 112)  0           block5b_drop[0][0]
                                                                 block5a_project_bn[0][0]
__________________________________________________________________________________________________
block5c_expand_conv (Conv2D)    (None, 14, 14, 672)  75264       block5b_add[0][0]
__________________________________________________________________________________________________
block5c_expand_bn (BatchNormali (None, 14, 14, 672)  2688        block5c_expand_conv[0][0]
__________________________________________________________________________________________________
block5c_expand_activation (Acti (None, 14, 14, 672)  0           block5c_expand_bn[0][0]
__________________________________________________________________________________________________
block5c_dwconv (DepthwiseConv2D (None, 14, 14, 672)  16800       block5c_expand_activation[0][0]
__________________________________________________________________________________________________
block5c_bn (BatchNormalization) (None, 14, 14, 672)  2688        block5c_dwconv[0][0]
__________________________________________________________________________________________________
block5c_activation (Activation) (None, 14, 14, 672)  0           block5c_bn[0][0]
__________________________________________________________________________________________________
block5c_se_squeeze (GlobalAvera (None, 672)          0           block5c_activation[0][0]
__________________________________________________________________________________________________
block5c_se_reshape (Reshape)    (None, 1, 1, 672)    0           block5c_se_squeeze[0][0]
__________________________________________________________________________________________________
block5c_se_reduce (Conv2D)      (None, 1, 1, 28)     18844       block5c_se_reshape[0][0]
__________________________________________________________________________________________________
block5c_se_expand (Conv2D)      (None, 1, 1, 672)    19488       block5c_se_reduce[0][0]
__________________________________________________________________________________________________
block5c_se_excite (Multiply)    (None, 14, 14, 672)  0           block5c_activation[0][0]
                                                                 block5c_se_expand[0][0]
__________________________________________________________________________________________________
block5c_project_conv (Conv2D)   (None, 14, 14, 112)  75264       block5c_se_excite[0][0]
__________________________________________________________________________________________________
block5c_project_bn (BatchNormal (None, 14, 14, 112)  448         block5c_project_conv[0][0]
__________________________________________________________________________________________________
block5c_drop (Dropout)          (None, 14, 14, 112)  0           block5c_project_bn[0][0]
__________________________________________________________________________________________________
block5c_add (Add)               (None, 14, 14, 112)  0           block5c_drop[0][0]
                                                                 block5b_add[0][0]
__________________________________________________________________________________________________
block6a_expand_conv (Conv2D)    (None, 14, 14, 672)  75264       block5c_add[0][0]
__________________________________________________________________________________________________
block6a_expand_bn (BatchNormali (None, 14, 14, 672)  2688        block6a_expand_conv[0][0]
__________________________________________________________________________________________________
block6a_expand_activation (Acti (None, 14, 14, 672)  0           block6a_expand_bn[0][0]
__________________________________________________________________________________________________
block6a_dwconv_pad (ZeroPadding (None, 17, 17, 672)  0           block6a_expand_activation[0][0]
__________________________________________________________________________________________________
block6a_dwconv (DepthwiseConv2D (None, 7, 7, 672)    16800       block6a_dwconv_pad[0][0]
__________________________________________________________________________________________________
block6a_bn (BatchNormalization) (None, 7, 7, 672)    2688        block6a_dwconv[0][0]
__________________________________________________________________________________________________
block6a_activation (Activation) (None, 7, 7, 672)    0           block6a_bn[0][0]
__________________________________________________________________________________________________
block6a_se_squeeze (GlobalAvera (None, 672)          0           block6a_activation[0][0]
__________________________________________________________________________________________________
block6a_se_reshape (Reshape)    (None, 1, 1, 672)    0           block6a_se_squeeze[0][0]
__________________________________________________________________________________________________
block6a_se_reduce (Conv2D)      (None, 1, 1, 28)     18844       block6a_se_reshape[0][0]
__________________________________________________________________________________________________
block6a_se_expand (Conv2D)      (None, 1, 1, 672)    19488       block6a_se_reduce[0][0]
__________________________________________________________________________________________________
block6a_se_excite (Multiply)    (None, 7, 7, 672)    0           block6a_activation[0][0]
                                                                 block6a_se_expand[0][0]
__________________________________________________________________________________________________
block6a_project_conv (Conv2D)   (None, 7, 7, 192)    129024      block6a_se_excite[0][0]
__________________________________________________________________________________________________
block6a_project_bn (BatchNormal (None, 7, 7, 192)    768         block6a_project_conv[0][0]
__________________________________________________________________________________________________
block6b_expand_conv (Conv2D)    (None, 7, 7, 1152)   221184      block6a_project_bn[0][0]
__________________________________________________________________________________________________
block6b_expand_bn (BatchNormali (None, 7, 7, 1152)   4608        block6b_expand_conv[0][0]
__________________________________________________________________________________________________
block6b_expand_activation (Acti (None, 7, 7, 1152)   0           block6b_expand_bn[0][0]
__________________________________________________________________________________________________
block6b_dwconv (DepthwiseConv2D (None, 7, 7, 1152)   28800       block6b_expand_activation[0][0]
__________________________________________________________________________________________________
block6b_bn (BatchNormalization) (None, 7, 7, 1152)   4608        block6b_dwconv[0][0]
__________________________________________________________________________________________________
block6b_activation (Activation) (None, 7, 7, 1152)   0           block6b_bn[0][0]
__________________________________________________________________________________________________
block6b_se_squeeze (GlobalAvera (None, 1152)         0           block6b_activation[0][0]
__________________________________________________________________________________________________
block6b_se_reshape (Reshape)    (None, 1, 1, 1152)   0           block6b_se_squeeze[0][0]
__________________________________________________________________________________________________
block6b_se_reduce (Conv2D)      (None, 1, 1, 48)     55344       block6b_se_reshape[0][0]
__________________________________________________________________________________________________
block6b_se_expand (Conv2D)      (None, 1, 1, 1152)   56448       block6b_se_reduce[0][0]
__________________________________________________________________________________________________
block6b_se_excite (Multiply)    (None, 7, 7, 1152)   0           block6b_activation[0][0]
                                                                 block6b_se_expand[0][0]
__________________________________________________________________________________________________
block6b_project_conv (Conv2D)   (None, 7, 7, 192)    221184      block6b_se_excite[0][0]
__________________________________________________________________________________________________
block6b_project_bn (BatchNormal (None, 7, 7, 192)    768         block6b_project_conv[0][0]
__________________________________________________________________________________________________
block6b_drop (Dropout)          (None, 7, 7, 192)    0           block6b_project_bn[0][0]
__________________________________________________________________________________________________
block6b_add (Add)               (None, 7, 7, 192)    0           block6b_drop[0][0]
                                                                 block6a_project_bn[0][0]
__________________________________________________________________________________________________
block6c_expand_conv (Conv2D)    (None, 7, 7, 1152)   221184      block6b_add[0][0]
__________________________________________________________________________________________________
block6c_expand_bn (BatchNormali (None, 7, 7, 1152)   4608        block6c_expand_conv[0][0]
__________________________________________________________________________________________________
block6c_expand_activation (Acti (None, 7, 7, 1152)   0           block6c_expand_bn[0][0]
__________________________________________________________________________________________________
block6c_dwconv (DepthwiseConv2D (None, 7, 7, 1152)   28800       block6c_expand_activation[0][0]
__________________________________________________________________________________________________
block6c_bn (BatchNormalization) (None, 7, 7, 1152)   4608        block6c_dwconv[0][0]
__________________________________________________________________________________________________
block6c_activation (Activation) (None, 7, 7, 1152)   0           block6c_bn[0][0]
__________________________________________________________________________________________________
block6c_se_squeeze (GlobalAvera (None, 1152)         0           block6c_activation[0][0]
__________________________________________________________________________________________________
block6c_se_reshape (Reshape)    (None, 1, 1, 1152)   0           block6c_se_squeeze[0][0]
__________________________________________________________________________________________________
block6c_se_reduce (Conv2D)      (None, 1, 1, 48)     55344       block6c_se_reshape[0][0]
__________________________________________________________________________________________________
block6c_se_expand (Conv2D)      (None, 1, 1, 1152)   56448       block6c_se_reduce[0][0]
__________________________________________________________________________________________________
block6c_se_excite (Multiply)    (None, 7, 7, 1152)   0           block6c_activation[0][0]
                                                                 block6c_se_expand[0][0]
__________________________________________________________________________________________________
block6c_project_conv (Conv2D)   (None, 7, 7, 192)    221184      block6c_se_excite[0][0]
__________________________________________________________________________________________________
block6c_project_bn (BatchNormal (None, 7, 7, 192)    768         block6c_project_conv[0][0]
__________________________________________________________________________________________________
block6c_drop (Dropout)          (None, 7, 7, 192)    0           block6c_project_bn[0][0]
__________________________________________________________________________________________________
block6c_add (Add)               (None, 7, 7, 192)    0           block6c_drop[0][0]
                                                                 block6b_add[0][0]
__________________________________________________________________________________________________
block6d_expand_conv (Conv2D)    (None, 7, 7, 1152)   221184      block6c_add[0][0]
__________________________________________________________________________________________________
block6d_expand_bn (BatchNormali (None, 7, 7, 1152)   4608        block6d_expand_conv[0][0]
__________________________________________________________________________________________________
block6d_expand_activation (Acti (None, 7, 7, 1152)   0           block6d_expand_bn[0][0]
__________________________________________________________________________________________________
block6d_dwconv (DepthwiseConv2D (None, 7, 7, 1152)   28800       block6d_expand_activation[0][0]
__________________________________________________________________________________________________
block6d_bn (BatchNormalization) (None, 7, 7, 1152)   4608        block6d_dwconv[0][0]
__________________________________________________________________________________________________
block6d_activation (Activation) (None, 7, 7, 1152)   0           block6d_bn[0][0]
__________________________________________________________________________________________________
block6d_se_squeeze (GlobalAvera (None, 1152)         0           block6d_activation[0][0]
__________________________________________________________________________________________________
block6d_se_reshape (Reshape)    (None, 1, 1, 1152)   0           block6d_se_squeeze[0][0]
__________________________________________________________________________________________________
block6d_se_reduce (Conv2D)      (None, 1, 1, 48)     55344       block6d_se_reshape[0][0]
__________________________________________________________________________________________________
block6d_se_expand (Conv2D)      (None, 1, 1, 1152)   56448       block6d_se_reduce[0][0]
__________________________________________________________________________________________________
block6d_se_excite (Multiply)    (None, 7, 7, 1152)   0           block6d_activation[0][0]
                                                                 block6d_se_expand[0][0]
__________________________________________________________________________________________________
block6d_project_conv (Conv2D)   (None, 7, 7, 192)    221184      block6d_se_excite[0][0]
__________________________________________________________________________________________________
block6d_project_bn (BatchNormal (None, 7, 7, 192)    768         block6d_project_conv[0][0]
__________________________________________________________________________________________________
block6d_drop (Dropout)          (None, 7, 7, 192)    0           block6d_project_bn[0][0]
__________________________________________________________________________________________________
block6d_add (Add)               (None, 7, 7, 192)    0           block6d_drop[0][0]
                                                                 block6c_add[0][0]
__________________________________________________________________________________________________
block7a_expand_conv (Conv2D)    (None, 7, 7, 1152)   221184      block6d_add[0][0]
__________________________________________________________________________________________________
block7a_expand_bn (BatchNormali (None, 7, 7, 1152)   4608        block7a_expand_conv[0][0]
__________________________________________________________________________________________________
block7a_expand_activation (Acti (None, 7, 7, 1152)   0           block7a_expand_bn[0][0]
__________________________________________________________________________________________________
block7a_dwconv (DepthwiseConv2D (None, 7, 7, 1152)   10368       block7a_expand_activation[0][0]
__________________________________________________________________________________________________
block7a_bn (BatchNormalization) (None, 7, 7, 1152)   4608        block7a_dwconv[0][0]
__________________________________________________________________________________________________
block7a_activation (Activation) (None, 7, 7, 1152)   0           block7a_bn[0][0]
__________________________________________________________________________________________________
block7a_se_squeeze (GlobalAvera (None, 1152)         0           block7a_activation[0][0]
__________________________________________________________________________________________________
block7a_se_reshape (Reshape)    (None, 1, 1, 1152)   0           block7a_se_squeeze[0][0]
__________________________________________________________________________________________________
block7a_se_reduce (Conv2D)      (None, 1, 1, 48)     55344       block7a_se_reshape[0][0]
__________________________________________________________________________________________________
block7a_se_expand (Conv2D)      (None, 1, 1, 1152)   56448       block7a_se_reduce[0][0]
__________________________________________________________________________________________________
block7a_se_excite (Multiply)    (None, 7, 7, 1152)   0           block7a_activation[0][0]
                                                                 block7a_se_expand[0][0]
__________________________________________________________________________________________________
block7a_project_conv (Conv2D)   (None, 7, 7, 320)    368640      block7a_se_excite[0][0]
__________________________________________________________________________________________________
block7a_project_bn (BatchNormal (None, 7, 7, 320)    1280        block7a_project_conv[0][0]
__________________________________________________________________________________________________
top_conv (Conv2D)               (None, 7, 7, 1280)   409600      block7a_project_bn[0][0]
__________________________________________________________________________________________________
top_bn (BatchNormalization)     (None, 7, 7, 1280)   5120        top_conv[0][0]
__________________________________________________________________________________________________
top_activation (Activation)     (None, 7, 7, 1280)   0           top_bn[0][0]
__________________________________________________________________________________________________
avg_pool (GlobalAveragePooling2 (None, 1280)         0           top_activation[0][0]
__________________________________________________________________________________________________
top_dropout (Dropout)           (None, 1280)         0           avg_pool[0][0]
__________________________________________________________________________________________________
predictions (Dense)             (None, 1000)         1281000     top_dropout[0][0]
==================================================================================================
Total params: 5,330,571
Trainable params: 5,288,548
Non-trainable params: 42,023
__________________________________________________________________________________________________
>>>

julia> h5read("/home/dyuret/.keras/models/efficientnetb0.h5","/")
Dict{String, Any} with 240 entries:
  "block2a_project_conv" => Dict{String, Any}("block2a_project_conv"=>Dict{String, Any}("kernel:0"=>Float32[-0.378281 -0.364692 … -0.413038 0.633853; 0.37701 0.3736…
  "block6c_se_reshape"   => Dict{String, Any}()
  "block2a_se_reduce"    => Dict{String, Any}("block2a_se_reduce"=>Dict{String, Any}("bias:0"=>Float32[-0.00488274, 0.00683442, 0.00191372, 0.00740076], "kernel:0"=…
  "block4c_add"          => Dict{String, Any}()
  "block2b_project_bn"   => Dict{String, Any}("block2b_project_bn"=>Dict{String, Any}("gamma:0"=>Float32[4.58717, 4.10991, 5.67829, 1.22638, 3.81532, 1.37028, 7.770…
  "top_dropout"          => Dict{String, Any}()
  "block5a_se_excite"    => Dict{String, Any}()
  "block5b_bn"           => Dict{String, Any}("block5b_bn"=>Dict{String, Any}("gamma:0"=>Float32[1.82547, 1.70071, 1.8903, 1.82822, 1.67215, 1.08799, 2.36588, 0.822…
  "block7a_se_expand"    => Dict{String, Any}("block7a_se_expand"=>Dict{String, Any}("bias:0"=>Float32[0.0451559, 0.0518708, 0.0821558, 0.0960006, -0.0428952, 0.154…
  "block2b_expand_conv"  => Dict{String, Any}("block2b_expand_conv"=>Dict{String, Any}("kernel:0"=>Float32[-0.155422 -0.483489 … 0.0917838 0.0939072; 0.000241052 -0…
  "block6d_se_reshape"   => Dict{String, Any}()
  "block5a_dwconv"       => Dict{String, Any}("block5a_dwconv"=>Dict{String, Any}("depthwise_kernel:0"=>Float32[-0.0288111 0.0797575 … -0.0469304 -0.0214439]…
  "block2b_drop"         => Dict{String, Any}()
  "block4c_activation"   => Dict{String, Any}()
  ⋮                      => ⋮

>>> plot_model(model, show_shapes=True, show_layer_names=True, to_file='model.png')

=#


text:
function create_subclusters_labels!(labels::AbstractArray{Int64,2},points::AbstractArray{Float64,2},cluster_params::splittable_cluster_params)
    if size(labels,1) == 0
        return
    end
    lr_arr = zeros(length(labels), 2)
    log_likelihood!(lr_arr[:,1],points,cluster_params.cluster_params_l.distribution)
    log_likelihood!(lr_arr[:,2],points,cluster_params.cluster_params_r.distribution)
    lr_arr[:,1] .+= log(cluster_params.lr_weights[1])
    lr_arr[:,2] .+= log(cluster_params.lr_weights[2])
    sample_log_cat_array!(labels,lr_arr)
end

function sample_labels!(labels::AbstractArray{Int64,2},points::AbstractArray{Float64,2},clusters_samples::Dict,final::Bool)
    parr = zeros(length(labels), length(clusters_samples))
    for (k,v) in clusters_samples
        log_likelihood!((@view parr[:,k]),points,v)
    end
    sample_log_cat_array!(labels,parr,final)
end

function create_splittable_from_params(params::cluster_parameters, α::Float64)
    params_l = deepcopy(params)
    params_l.distribution = sample_distribution(params.posterior_hyperparams)
    params_r = deepcopy(params)
    params_r.distribution = sample_distribution(params.posterior_hyperparams)
    #params_l = cluster_parameters(params.distribution_hyper_params, sample_distribution(params.posterior_hyperparams), params.suff_stats, params.posterior_hyperparams)
    #params_r = cluster_parameters(params.distribution_hyper_params, sample_distribution(params.posterior_hyperparams), params.suff_stats, params.posterior_hyperparams)
    lr_weights = rand(Dirichlet([α / 2, α / 2]))
    return splittable_cluster_params(params,params_l,params_r,lr_weights, false, ones(20).*-Inf)
end

function merge_clusters_to_splittable(cpl::cluster_parameters,cpr::cluster_parameters, α::Float64)
    suff_stats = aggregate_suff_stats(cpl.suff_statistics,cpr.suff_statistics)
    posterior_hyperparams = calc_posterior(cpl.hyperparams, suff_stats)
    lr_weights = rand(Dirichlet([cpl.suff_statistics.N + (α / 2), cpr.suff_statistics.N + (α / 2)]))
    cp = cluster_parameters(cpl.hyperparams, cpl.distribution, suff_stats, posterior_hyperparams)
    return splittable_cluster_params(cp,cpl,cpr,lr_weights, false, ones(20).*-Inf)
end

function should_split!(should_split::AbstractArray{Float64,1}, cluster_params::splittable_cluster_params, α::Float64, final::Bool)

    cpl = cluster_params.cluster_params_l
    cpr = cluster_params.cluster_params_r
    cp = cluster_params.cluster_params
    if final || cpl.suff_statistics.N == 0 ||cpr.suff_statistics.N == 0
        should_split .= 0
        return
    end
    log_likihood_l = log_marginal_likelihood(cpl.hyperparams, cpl. posterior_hyperparams, cpl.suff_statistics)
    log_likihood_r = log_marginal_likelihood(cpr.hyperparams, cpr. posterior_hyperparams, cpr.suff_statistics)
    log_likihood = log_marginal_likelihood(cp.hyperparams, cp. posterior_hyperparams, cp.suff_statistics)
    log_HR = log(α) + logabsgamma(cpl.suff_statistics.N)[1] + log_likihood_l + logabsgamma(cpr.suff_statistics.N)[1] + log_likihood_r-(logabsgamma(cp.suff_statistics.N)[1] + log_likihood)
    if log_HR > log(rand())
        should_split .= 1
    end
end

function should_split!(cluster_params::splittable_cluster_params, α::Float64, final::Bool)

    cpl = cluster_params.cluster_params_l
    cpr = cluster_params.cluster_params_r
    cp = cluster_params.cluster_params
    if final || cpl.suff_statistics.N == 0 ||cpr.suff_statistics.N == 0
        should_split .= 0
        return
    end
    log_likihood_l = log_marginal_likelihood(cpl.hyperparams, cpl. posterior_hyperparams, cpl.suff_statistics)
    log_likihood_r = log_marginal_likelihood(cpr.hyperparams, cpr. posterior_hyperparams, cpr.suff_statistics)
    log_likihood = log_marginal_likelihood(cp.hyperparams, cp. posterior_hyperparams, cp.suff_statistics)
    log_HR = log(α) + logabsgamma(cpl.suff_statistics.N)[1] + log_likihood_l + logabsgamma(cpr.suff_statistics.N)[1] + log_likihood_r-(logabsgamma(cp.suff_statistics.N)[1] + log_likihood)
    # println(log_HR)
end

function update_splittable_cluster_params!(splittable_cluser::splittable_cluster_params,
        points::AbstractArray{Float64,2},
        sub_labels::AbstractArray{Int64,1},
        is_global::Bool,
        pts_to_groups = -1)
    cpl = splittable_cluser.cluster_params_l
    cpr = splittable_cluser.cluster_params_r
    cp = splittable_cluser.cluster_params
    if is_global
        cp.suff_statistics = create_sufficient_statistics(cp.hyperparams,cp.posterior_hyperparams, points, pts_to_groups)
        pts_gl = @view pts_to_groups[(@view (sub_labels .<= 2)[:])]
        pts_gr = @view pts_to_groups[(@view (sub_labels .> 2)[:])]
        cpl.suff_statistics = create_sufficient_statistics(cpl.hyperparams,cpl.posterior_hyperparams, (@view points[:,(@view (sub_labels .<= 2)[:])]),pts_gl)
        cpr.suff_statistics = create_sufficient_statistics(cpr.hyperparams,cpr.posterior_hyperparams, (@view points[:,(@view (sub_labels .> 2)[:])]),pts_gr)
    else
        cp.suff_statistics = create_sufficient_statistics(cp.hyperparams,cp.posterior_hyperparams, points)
        cpl.suff_statistics = create_sufficient_statistics(cpl.hyperparams,cpl.posterior_hyperparams, @view points[:,(@view (sub_labels .% 2 .== 1)[:])])
        cpr.suff_statistics = create_sufficient_statistics(cpr.hyperparams,cpr.posterior_hyperparams, @view points[:,(@view (sub_labels .% 2 .== 0)[:])])
    end
    cp.posterior_hyperparams = calc_posterior(cp.hyperparams, cp.suff_statistics)
    cpl.posterior_hyperparams = calc_posterior(cpl.hyperparams, cpl.suff_statistics)
    cpr.posterior_hyperparams = calc_posterior(cpr.hyperparams, cpr.suff_statistics)
end

function update_splittable_cluster_params(splittable_cluser::splittable_cluster_params,
        points::AbstractArray{Float64,2},
        sub_labels::AbstractArray{Int64,1},
        is_global::Bool,
        pts_to_groups = -1)
    cpl = splittable_cluser.cluster_params_l
    cpr = splittable_cluser.cluster_params_r
    cp = splittable_cluser.cluster_params
    # println(sum((@view (sub_labels .> 2)[:])))
    if is_global
        cp.suff_statistics = create_sufficient_statistics(cp.hyperparams,cp.posterior_hyperparams, points, pts_to_groups)
        pts_gl = @view pts_to_groups[(@view (sub_labels .<= 2)[:])]
        pts_gr = @view pts_to_groups[(@view (sub_labels .> 2)[:])]
        cpl.suff_statistics = create_sufficient_statistics(cpl.hyperparams, cpl.posterior_hyperparams, (@view points[:,(@view (sub_labels .<= 2)[:])]),pts_gl)
        cpr.suff_statistics = create_sufficient_statistics(cpr.hyperparams, cpr.posterior_hyperparams,(@view points[:,(@view (sub_labels .> 2)[:])]),pts_gr)
    else
        cp.suff_statistics = create_sufficient_statistics(cp.hyperparams,cp.posterior_hyperparams,points)
        cpl.suff_statistics = create_sufficient_statistics(cpl.hyperparams, cpl.posterior_hyperparams,@view points[:,(@view (sub_labels .% 2 .== 1)[:])])
        cpr.suff_statistics = create_sufficient_statistics(cpr.hyperparams, cpr.posterior_hyperparams,@view points[:,(@view (sub_labels .% 2 .== 0)[:])])
    end
    begin
        cp.posterior_hyperparams = calc_posterior(cp.hyperparams, cp.suff_statistics)
        cpl.posterior_hyperparams = calc_posterior(cpl.hyperparams, cpl.suff_statistics)
        cpr.posterior_hyperparams = calc_posterior(cpr.hyperparams, cpr.suff_statistics)
    end
    return splittable_cluser
end

function sample_cluster_params!(params::splittable_cluster_params, α::Float64, is_zero_dim = false)
    points_count = Vector{Float64}()
    params.cluster_params.distribution = sample_distribution(params.cluster_params.posterior_hyperparams)
    params.cluster_params_l.distribution = sample_distribution(params.cluster_params_l.posterior_hyperparams)
    params.cluster_params_r.distribution = sample_distribution(params.cluster_params_r.posterior_hyperparams)
    push!(points_count, params.cluster_params_l.suff_statistics.N)
    push!(points_count, params.cluster_params_r.suff_statistics.N)
    points_count .+= α/2
    params.lr_weights = rand(Dirichlet(points_count))
    log_likihood_l = log_marginal_likelihood(params.cluster_params_l.hyperparams,params.cluster_params_l.posterior_hyperparams, params.cluster_params_l.suff_statistics)
    log_likihood_r = log_marginal_likelihood(params.cluster_params_r.hyperparams,params.cluster_params_r.posterior_hyperparams, params.cluster_params_r.suff_statistics)

    # params.logsublikelihood_hist[1:4] = params.logsublikelihood_hist[2:5]
    # params.logsublikelihood_hist[5] = log_likihood_l + log_likihood_r
    # logsublikelihood_now = 0.0
    # for i=1:5
    #     logsublikelihood_now += params.logsublikelihood_hist[i] *0.20
    # end
    # if logsublikelihood_now != -Inf && logsublikelihood_now - params.logsublikelihood_hist[5] < 1e-2 # propogate abs change to other versions?
    #     params.splittable = true
    # end
    # println(split_delays)
    # logsublikelihood_now = (log_likihood_l+log_likihood_r) /  (params.cluster_params_l.suff_statistics.N+ params.cluster_params_r.suff_statistics.N)
    # if logsublikelihood_now - params.logsublikelihood_hist[1] < 0
    #     params.splittable = true
    # end
    # params.logsublikelihood_hist[1] = logsublikelihood_now
    #
    # if split_delays == false
    #     params.splittable = true
    # end
    params.logsublikelihood_hist[1:burnout_period-1] = params.logsublikelihood_hist[2:burnout_period]
    params.logsublikelihood_hist[burnout_period] = log_likihood_l + log_likihood_r
    logsublikelihood_now = 0.0

    for i=1:burnout_period
        logsublikelihood_now += params.logsublikelihood_hist[i] *(1/(burnout_period-0.1))
    end

    if logsublikelihood_now != -Inf && logsublikelihood_now - params.logsublikelihood_hist[burnout_period] < 1e-2 # propogate abs change to other versions?
        # println(params.logsublikelihood_hist)
        params.splittable = true
    end
    if is_zero_dim == true
        params.splittable = true
    end
    return params.cluster_params.suff_statistics.N
end

function sample_cluster_params!(params::splittable_cluster_params, α::Float64, counts::AbstractArray{Int64,1})
    points_count = [params.cluster_params_l.suff_statistics.N, params.cluster_params_r.suff_statistics.N]
    params.cluster_params.distribution = sample_distribution(params.cluster_params.posterior_hyperparams)
    params.cluster_params_l.distribution = sample_distribution(params.cluster_params_l.posterior_hyperparams)
    params.cluster_params_r.distribution = sample_distribution(params.cluster_params_r.posterior_hyperparams)
    points_count .+= α/2
    # println(points_count)
    params.lr_weights = rand(Dirichlet(points_count))
    log_likihood_l = log_marginal_likelihood(params.cluster_params_l.hyperparams,params.cluster_params_l.posterior_hyperparams, params.cluster_params_l.suff_statistics)
    log_likihood_r = log_marginal_likelihood(params.cluster_params_r.hyperparams,params.cluster_params_r.posterior_hyperparams, params.cluster_params_r.suff_statistics)

    # params.logsublikelihood_hist[1:4] = params.logsublikelihood_hist[2:5]
    # params.logsublikelihood_hist[5] = log_likihood_l + log_likihood_r
    # logsublikelihood_now = 0.0
    # for i=1:5
    #     logsublikelihood_now += params.logsublikelihood_hist[i] *0.20
    # end
    # if logsublikelihood_now != -Inf && logsublikelihood_now - params.logsublikelihood_hist[5] < 1e-2 # propogate abs change to other versions?
    #     params.splittable = true
    # end
    params.logsublikelihood_hist[1:burnout_period-1] = params.logsublikelihood_hist[2:burnout_period]
    params.logsublikelihood_hist[burnout_period] = log_likihood_l + log_likihood_r
    logsublikelihood_now = 0.0
    for i=1:burnout_period
        logsublikelihood_now += params.logsublikelihood_hist[i] *(1/(burnout_period-0.1))
    end

    if logsublikelihood_now != -Inf && logsublikelihood_now - params.logsublikelihood_hist[burnout_period] < 1e-2 # propogate abs change to other versions?
        # println(params.logsublikelihood_hist)
        params.splittable = true
    end
    return params.cluster_params.suff_statistics.N
end


text:
module NineML

export ODE, Assignment, Relation, Alias, OnEvent, OnCondition, Regime, Group, Population, Projection
export parse_ComponentClass, parse_Component, parse_Components
export eval_Relation, eval_Alias, eval_Regime, eval_Dynamics

using Base.Collections
using Graphs
using Sims
using LightXML
using Winston

typealias Time Float64

type ODE
    quantity:: Symbol
    freevars:: Array{Symbol}
    rhs:: Union(Float64,Symbol,Expr)
end

type Assignment
    quantity:: Symbol
    freevars:: Array{Symbol}
    rhs:: Union(Symbol,Expr)
end

type Alias
    quantity:: Symbol
    freevars:: Array{Symbol}
    rhs:: Expr
end

type Relation
    quantity:: Symbol
    argument:: Symbol
    freevars:: Array{Symbol}
    rhs:: Expr
end

type OnEvent
    quantity:: Symbol
    asgnsys:: Array{Any}
end

type OnCondition
    target_regime:: Union(Symbol,Nothing)
    trigger:: Expr
    event_quantity:: Symbol
    asgns:: Array{Any}
end

type Regime
    name:: Symbol
    odes:: Vector{ODE}
    asgns:: Vector{Assignment}
    events:: Vector{OnEvent}
    structuralEvents:: Vector{OnCondition}

end

type Population
    label:: Symbol
    n::Int64   # size
    proto::Sim   # prototype
end

type Component
    name:: Symbol
    parameterValues:: Dict{Symbol,Union(Float64,Expr)}
    initialValues:: Dict{Symbol,Union(Float64,Expr)}
end

type ComponentClass
    name:: Symbol
    parameters:: Vector{Symbol}
    states:: Vector{Symbol}
    ports:: Vector{Symbol}
    dynamics:: (Vector{Alias},Vector{Relation},Vector{Regime})
end

typealias Group Set{Population}

type Projection
    label   :: Symbol
    source  :: Group
    target  :: Group
    rule    :: Function
    weight  :: Function
    delay   :: Union (Function, Time)
    psr     :: Function
end

abstract ProjectionGraph

type SimpleProjectionGraph <: ProjectionGraph
    label :: Symbol
    G :: SimpleGraph
end

type WeightDelayProjectionGraph <: ProjectionGraph
    label :: Symbol
    G :: SimpleGraph
    M :: SparseMatrixCSC{Float64,Int64}
    D :: SparseMatrixCSC{Float64,Int64}
end

type WeightProjectionGraph <: ProjectionGraph
    label :: Symbol
    G :: SimpleGraph
    M :: SparseMatrixCSC{Float64,Int64}
end

function make_graph(n)
    G = Graphs.simple_graph(n)
    return G
end

function build_weight_delay_projection_graph (projection)
    c = projection.rule
    w = projection.weight
    d = projection.delay
    G = make_graph (n)
    W::Array{Float64,2} = zeros(n,n)
    D::Array{Float64,2} = zeros(n,n)
    eind = 1
    for i = 1 : n
        for j = 1 : n
            if c(i,j)
                add_edge! (G, i, j)
                W[i,j] = w(i,j)
                D[i,j] = d(i,j)
                eind = eind + 1
            end
        end
    end
    return WeightDelayProjectionGraph(projection.label,G,sparse(M),sparse(D))
end

function build_weight_projection_graph (projection)
    c = projection.rule
    w = projection.weight
    G = make_graph (n)
    W::Array{Float64,2} = zeros(n,n)
    eind = 1
    for i = 1 : n
        for j = 1 : n
            if c(i,j)
                add_edge! (G, i, j)
                W[i,j] = w(i,j)
                eind = eind + 1
            end
        end
    end
    WeightProjectionGraph(projection.label,G,sparse(M))
end

type Network

    n :: Int64
    d :: Float64

    State :: Array{(Function,Sim,Array {Float64,1},Array {Float64,1}),1}

    Connections :: Vector {ProjectionGraph}

    # TODO: use type Unknown for synaptic weight
    PQ :: Array {PriorityQueue {Time,Float64},1}
end

unary_operations = [:heaviside]

find_vars(e) = find_vars(e, Any[], Any[])
function find_vars(e,lst,vars)
    if isa(e,Symbol)
        if current_module()===Main && !isdefined(e) && !(e in unary_operations) && !(e in vars) && !(e in lst)
            push!(lst, e)
        end
    elseif isa(e,Expr) && e.head !== :quote && e.head !== :top
        for x in e.args
            find_vars(x,lst,vars)
        end
    end
    lst
end

function replace_lift_vars(e, aliases, relations, parameters, states)

    if isa(e,Symbol)
        if e == :t
            return :t
        elseif current_module()===Main && !isdefined(e) && (haskey(parameters,e))
            return Expr(:ref,:p,Expr(:ref,Expr(:.,Expr(:.,:ss,:(:sm)),:(:parameter_idx_map)),
                                     Expr(:quote,parameters[e].sym)))
        elseif current_module()===Main && !isdefined(e) && (haskey(states,e))
            return Expr(:ref,:y,Expr(:ref,Expr(:.,Expr(:.,:ss,:(:sm)),:(:unknown_idx_map)),
                                     Expr(:quote,states[e].sym)))
        else
            return replace_vars(e,aliases,relations,parameters,states)
        end
    elseif isa(e,Expr) && e.head !== :quote && e.head !== :top
        begin
            e1 = Expr(e.head)
            e1.args = map((x) -> replace_lift_vars(x,aliases,relations,parameters,states), e.args)
            e1.typ = e.typ
            return e1
        end
    else
        return replace_vars(x,aliases,relations,parameters,states)
    end
end

function replace_vars(e, aliases, relations, parameters, states)
    if isa(e,Symbol)
        if e == :t
            return MTime
        #elseif current_module()===Main && !isdefined(e) && (haskey(ports,e))
        #    return ports[e]
        elseif current_module()===Main && !isdefined(e) && (haskey(parameters,e))
            return parameters[e]
        elseif current_module()===Main && !isdefined(e) && (haskey(states,e))
            return states[e]
        elseif current_module()===Main && !isdefined(e) && (haskey(aliases,e))
            begin
                a = aliases[e]
                e1 = Expr(:call)
                e1.args = [a[1], map((x) -> replace_vars(x,aliases,relations,parameters,states), a[2])...]
                return e1
            end
        elseif current_module()===Main && !isdefined(e) && (haskey(relations,e))
            begin
                r = relations[e]
                e1 = Expr(:call)
                e1.args = [r[1], map((x) -> replace_vars(x,aliases,relations,parameters,states), r[2])...]
                return e1
            end
        else
            return e
        end
    elseif isa(e,Expr) && e.head == :call && (e.args[1] == :heaviside)
        begin
            cond = MExpr(Expr(:comparison,replace_vars(e.args[2],aliases,relations,parameters,states), :<, 0.0))
            e1 = ifelse(cond, 0.0, 1.0)
            return e1
        end
    elseif isa(e,Expr) && e.head == :call && (haskey(relations,e.args[1]))
        begin
            r = relations[e.args[1]]
            e1 = Expr(e.head)
            e1.args = [r[1], map((x) -> replace_vars(x,aliases,relations,parameters,states), [e.args[2],r[2]]...)]
            e1.typ = e.typ
            return e1
        end
    elseif isa(e,Expr) && e.head !== :quote && e.head !== :top
        begin
            e1 = Expr(e.head)
            e1.args = map((x) -> replace_vars(x,aliases,relations,parameters,states), e.args)
            e1.typ = e.typ
            return e1
        end
    else
        return e
    end
end
replace_vars(e) = replace_vars (e, Dict{Symbol,Alias}(), Dict{Symbol,Relation}(),
                                Dict{Symbol,Parameter}(), Dict{Symbol,Unknown}())

function parse_MathInline (parent)
    math = find_element(parent,"MathInline")
    if math == nothing
        return nothing
    else
        e = parse(content(math))
        return e
    end
end

function parse_Regime (sysname,parameters,states,r)

    rname = symbol(attribute(r, "name"))
    timeDerivatives = get_elements_by_tagname (r, "TimeDerivative")
    stateAssignments =  get_elements_by_tagname (r, "StateAssignment")
    onEvents = get_elements_by_tagname (r, "OnEvent")
    onConditions = get_elements_by_tagname (r, "OnCondition")

    @assert (length (onConditions) <= 1)

    @assert ((!(isempty (timeDerivatives))) || (!(isempty (stateAssignments))))

    odes = map ((x) ->
                let
                    quantity = symbol(attribute(x, "variable"))
                    rhs = parse_MathInline(x)
                    fv = find_vars(rhs,Any[],Any[quantity])
                    return ODE (quantity, fv, rhs)
                end, timeDerivatives)

    asgns = map ((x) ->
                 let
                     quantity = symbol(attribute(x, "variable"))
                     rhs = parse_MathInline(x)
                     fv = find_vars(rhs,Any[],Any[quantity])
                     return Assignment (quantity, fv, rhs)
                 end, stateAssignments)

    events = map ((x) ->
                  let
                      quantity = symbol(attribute(x, "src_port"))
                      eventAssignments = get_elements_by_tagname (x, "StateAssignment")
                      easgns = map ((x) ->
                                    let
                                        quantity = symbol(attribute(x, "variable"))
                                        rhs = parse_MathInline(x)
                                        fv = find_vars(rhs,Any[],Any[quantity])
                                        return Assignment (quantity, fv, rhs)
                                    end, eventAssignments)
                      asgnsys = (map((x) ->
                                     let u = Unknown(x.quantity)
                                         reinit(u, MExpr(x.rhs))
                                     end, easgns))
                      return OnEvent (quantity, asgnsys)
                  end, onEvents)

    structuralEvents = map ((x) ->
                            let
                                target_regime = let a = attribute(x, "target_regime")
                                    if a == nothing
                                        nothing
                                    else
                                        symbol(a)
                                    end
                                end
                                trigger = parse_MathInline(find_element(x, "Trigger"))
                                eventAssignments = get_elements_by_tagname (x, "StateAssignment")
                                event_out = find_element (x, "EventOut")
                                event_quantity = symbol(attribute(event_out, "port"))
                                seasgns = map ((x) ->
                                               let
                                                   quantity = symbol(attribute(x, "variable"))
                                                   rhs = parse_MathInline(x)
                                                   fv = find_vars(rhs,Any[],Any[quantity])
                                                   return Assignment (quantity, fv, rhs)
                                               end, eventAssignments)

                                return OnCondition (target_regime, trigger, event_quantity, seasgns)
                            end, onConditions)

    Regime(rname,vec(odes),vec(asgns),vec(events),vec(structuralEvents))
end

function parse_Dynamics (sysname,parameters,dynamics)

    states = map((x)->symbol(attribute(x,"name")),
                 get_elements_by_tagname (dynamics, "StateVariable"))
    regimes   = get_elements_by_tagname (dynamics, "Regime")
    relations = get_elements_by_tagname (dynamics, "Relation")
    aliases   = get_elements_by_tagname (dynamics, "Alias")
    relations = map ((x) ->
                     let
                         quantity = symbol(attribute(x, "name"))
                         argument = symbol(attribute(x, "argument"))
                         fv = find_vars(rhs,Any[],Any[quantity,argument])
                         rhs = parse_MathInline(x)
                         return Relation (quantity, argument, fv, rhs)
                     end, relations)

    aliases = map ((x) ->
                   let
                       quantity = symbol(attribute(x, "name"))
                       rhs = parse_MathInline(x)
                       fv = find_vars(rhs,Any[],Any[quantity])
                       return Alias (quantity, fv, rhs)
                   end, aliases)

    return (states, vec(aliases), vec(relations), map((r) -> parse_Regime(sysname,parameters,states,r), regimes))
end

function parse_ComponentClass (filename)
    xdoc = parse_file(filename)

    xroot = root(xdoc)  # an instance of XMLElement
    #@assert(name(xroot) == "NineML")

    component = find_element(xroot, "ComponentClass")

    name = symbol(attribute(component, "name"))

    dynamics = find_element(component, "Dynamics")
    analog_send_ports = get_elements_by_tagname(component, "AnalogSendPort")
    analog_receive_ports = get_elements_by_tagname(component, "AnalogReceivePort")
    analog_reduce_ports = get_elements_by_tagname(component, "AnalogReducePort")
    event_send_ports = get_elements_by_tagname(component, "EventSendPort")
    event_receive_ports = get_elements_by_tagname(component, "EventReceivePort")

    parameters = map((x) -> symbol(attribute(x, "name")),
                     get_elements_by_tagname(component, "Parameter"))

    (states, aliases, relations, dynamics) = parse_Dynamics (name,parameters,dynamics)

    ports = setdiff (map((x) -> symbol(attribute(x,"name")),
                         [analog_receive_ports, analog_reduce_ports, event_receive_ports, analog_send_ports]),
                     states)

    ComponentClass(name, parameters, states, ports, (aliases, relations, dynamics))
end

function parse_Component (component)

    name = symbol(attribute(component, "name"))

    parameterValues = Dict{Symbol,Union(Float64,Expr)}()
    initialValues = Dict{Symbol,Union(Float64,Expr)}()

    for x in get_elements_by_tagname(component, "Property")
        let q = find_element(x,"Quantity")
            sv = find_element(q,"SingleValue")
            val = find_element(x,"MathInline") == nothing ? parse(content(sv)) : parse_MathInline(sv)

            parameterValues[symbol(attribute(x, "name"))] = val
        end
    end

    for x in get_elements_by_tagname(component, "Initial")
        let q = find_element(x,"Quantity")
            sv = find_element(q,"SingleValue")
            val = find_element(x,"MathInline") == nothing ? parse(content(sv)) : parse_MathInline(sv)

            initialValues[symbol(attribute(x, "name"))] = val
        end
    end

    Component(name, parameterValues, initialValues)

end

function parse_Components (filename)

    xdoc = parse_file(filename)

    xroot = root(xdoc)  # an instance of XMLElement
    #@assert(name(xroot) == "NineML")

    components = get_elements_by_tagname(xroot, "Component")
    return map(parse_Component, components)

end

function eval_Relation (r::Relation)

    Expr(:function,
         Expr(:call,r.quantity,[r.argument,r.freevars]),
         replace_vars(r.rhs))

end

function eval_Alias (a::Alias)

    Expr(:function,
         Expr(:call,a.quantity,a.freevars...),
         replace_vars(a.rhs))
end

function eval_Relation (r::Relation)

    Expr(:function,
         Expr(:call,r.quantity,r.freevars...),
         replace_vars(r.rhs))
end

function eval_Regime (regime::Regime,
                      name::Symbol,
                      parameters::Dict{Symbol,Parameter},
                      states::Dict{Symbol,Unknown},
                      aliases::Dict{Symbol,(Expr,Array{Symbol})},
                      relations::Dict{Symbol,(Expr,Array{Symbol})},
                      initialValues::Dict{Symbol,Union(Float64,Expr)})

    rname  = regime.name
    odes   = regime.odes
    asgns  = regime.asgns
    events = regime.events
    structuralEvents = regime.structuralEvents

    paramsys = (map((x) ->
                    let u = x[2]
                        InitialEquation(u - 0.0)
                    end, parameters))

    odesys = (map((x) ->
                  let u = states[x.quantity]
                      DerUnknown(x.quantity,0.0,false,u) -
                      (isa(x.rhs,Float64) ? x.rhs :
                       MExpr(replace_vars(x.rhs,aliases,relations,parameters,states)))
                  end, odes))

    asgnsys = (map((x) ->
                   let u = Unknown(x.quantity, 0.0)
                       u - MExpr(replace_vars(x.rhs,aliases,relations,parameters,states))
                   end, asgns))

    eventsys = (map((x) -> Event(x.quantity, x.asgnsys), events))

    conds = filter ((x) -> (x.target_regime == nothing) ? true : false, structuralEvents)
    condsys = map((x) ->
                  Event(MExpr(replace_vars(x.trigger,aliases,relations,parameters,states)),
                        map ((a) ->
                             reinit(states[a.quantity],
                                    replace_vars(a.rhs,aliases,relations,parameters,states)),
                             x.asgns)),
                      conds)

    strevs = filter ((x) -> (x.target_regime == nothing) ? false : true, structuralEvents)
    strevfns = map ((x) ->
                    let
                        target_regime_name = symbol(join([x.target_regime,name]))
                        asgns_exprs = map ((a) ->
                                           Expr(:(=),
                                                replace_lift_vars(a.quantity,aliases,relations,parameters,states),
                                                replace_lift_vars(a.rhs,aliases,relations,parameters,states)),
                                           x.asgns)
                        trigger_expr = replace_vars(x.trigger,aliases,relations,parameters,states)
                        response = quote
                            (t,y,yp,p,ss) -> begin
                                println("response: t = ", t)
                                $(asgns_exprs...)
                                println("response: p = ", p)
                                return (y,p)
                                end
                        end
                        return eval(Main, quote ((eqsys) -> StructuralEvent($trigger_expr, eqsys(),
                                                                            ()->$target_regime_name(),
                                                                            pos_response=$response))
                                                 end)
                    end,
                    strevs)

    if isempty(strevs)
        this_regime_name = symbol(join([rname,name]))
        expr = Expr(:function,
                    Expr(:call,this_regime_name),
                         ##(map ((x) -> Expr(:kw,x[1],x[2]), initialValues))...),
                    quote
                        Equation[$paramsys...,$asgnsys...,$odesys...,$eventsys...,$condsys...]
                    end)
        eval(Main,expr)
        return this_regime_name
    else
        this_regime_eqname = symbol(join([rname,name,"eq"]))
        expr1 = Expr(:function,
                     Expr(:call,this_regime_eqname),
                          ##(map ((x) -> Expr(:kw,x[1],x[2]), initialValues))...),
                     quote
                         Equation[$paramsys...,$asgnsys...,$odesys...,$eventsys...,$condsys...]
                     end)
        eqsys = eval(Main,expr1)

        this_regime_name = symbol(join([rname,name]))
        expr2 = Expr(:function,
                     Expr(:call,this_regime_name),
                          ##(map ((x) -> Expr(:kw,x[1],x[2]), initialValues))...),
                     quote
                         Equation[$(map ((x) -> x(eqsys), strevfns))...]
                     end)
        eval(Main,expr2)
        return this_regime_name
    end
end

function eval_Dynamics (dynamics,
                        name::Symbol,
                        parameterValues::Dict{Symbol,Union(Float64,Expr)},
                        initialValues::Dict{Symbol,Union(Float64,Expr)},
                        parameterNames::Vector{Symbol},
                        stateNames::Vector{Symbol},
                        portNames::Vector{Symbol})

    aliasDefs    = dynamics[1]
    relationDefs = dynamics[2]
    regimes      = dynamics[3]

    states = Dict{Symbol,Unknown}()
    ports  = Dict{Symbol,Parameter}()
    parameters = Dict{Symbol,Parameter}()
    for x in parameterValues
        if x[1] in parameterNames
            parameters[x[1]] = Parameter(x[2],string(x[1]))
        end
    end
    for x in portNames
        pp = Parameter(string(x))
        ports[x] = pp
        parameters[x] = pp
    end
    for x in initialValues
        states[x[1]] = Unknown(x[1],string(x[1]))
        states[x[1]].value = x[2]
    end
    aliases = Dict{Symbol,(Expr,Array{Symbol})}()
    relations = Dict{Symbol,(Expr,Array{Symbol})}()
    for a in aliasDefs
        aliases[a.quantity] = (NineML.eval_Alias(a), a.freevars)
    end
    for r in relations
        relations[r.quantity] = (NineML.eval_Relation(r), r.freevars)
    end

    regimeNames = map(r -> eval_Regime(r, name, parameters, states, aliases, relations, initialValues),
                      regimes)

    first_regime_name = regimeNames[1]

    expr = quote
            function $name ()
                $first_regime_name ()
            end
    end
    eval(Main,expr)

end

end


text:
# SteinHierarchericalPoisson
#
# We assume we have the following hierarcherical model:
#
# n_i | T_i, lambda_i ~ Pois(T_i lambda_i)
# lambda_i | beta ~ Gamma(alpha, beta)
# beta ~ Gamma(gamma, delta)
#

using Distributions: quantile, Gamma, Poisson

type SteinHierarchericalPoisson <: SteinDistribution
    # the counts from each poisson
    n::Array{Int}
    # the times from each poisson
    T::Array{Float64,1}
    # the shape parameter for the poisson priors
    alpha::Float64
    # the shape parameter for the beta prior
    gamma::Float64
    # the scale parameter for the beta prior
    delta::Float64
end

# Values used in Seth Tribble's thesis:
defaultalpha = 1.802
defaultgamma = 0.1
defaultdelta = 1.0

SteinHierarchericalPoisson(n, T) =
    SteinHierarchericalPoisson(n, T, defaultalpha, defaultgamma, defaultdelta)

# Returns lower bound of support
function supportlowerbound(d::SteinHierarchericalPoisson, i::Int)
    0.0
end

# Returns upper bound of support
function supportupperbound(d::SteinHierarchericalPoisson, i::Int)
    Inf
end

function numpoissons(d::SteinHierarchericalPoisson)
    @assert length(d.n) == length(d.T)
    length(d.n)
end

function rungibbs(d::SteinHierarchericalPoisson,
                  n::Int;
                  qmcvariates=[])
    p = numpoissons(d)
    lambdas = Array(Float64, n+1, p)
    betas = Array(Float64, n+1)
    # work with qmc variates or iid ones
    if size(qmcvariates,1) != 0
        @assert size(qmcvariates) == (n, p+1)
        randvariates = qmcvariates
    else
        randvariates = rand(n, p+1)
    end
    # initialize the samples
    lambdas[1,:] = [1.0 for _ in 1:p]
    betas[1] = 1.0
    # do the gibbs!
    for i in 1:n
        # sample the lambdas
        for j in 1:p
            g = Gamma(d.alpha + d.n[j], (betas[i] + d.T[j])^-1)
            lambdas[i+1,j] = quantile(g, randvariates[i,j])
        end
        # sample the beta
        g = Gamma(d.gamma + 10*d.alpha, (d.delta + sum(lambdas[i+1,:]))^-1)
        betas[i+1] = quantile(g, randvariates[i,p+1])
    end
    # discard the first point
    lambdas[2:end,:], betas[2:end]
end

function gradlogdensity(d::SteinHierarchericalPoisson,
                        point::Array{Float64,1})
    lambdas, beta = point[1:end-1], point[end]
    gradlambda = beta + d.T + ((d.n + d.alpha) ./ lambdas)
    gradbeta = -sum(lambdas) + d.gamma / beta - d.delta
    [gradlambda; gradbeta]
end