Skip to content

Commit 9e0a3a0

Browse files
InterdisciplinaryPhysicsTeampitmonticoneClaudMor
committed
Update
Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com> Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
1 parent 1008e6c commit 9e0a3a0

File tree

13 files changed

+138
-25
lines changed

13 files changed

+138
-25
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
1313
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1414
MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5"
1515
OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922"
16+
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
1617
SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
1718
SimpleValueGraphs = "b43c691f-cac2-5415-8122-396fe16a49fc"
1819
SimpleWeightedGraphs = "47aef6b3-ad0c-573a-a1e2-d07658019622"

docs/src/API.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,16 @@ is_directed(subgraph::AbstractSubGraph)
127127
is_directed(::Type{S}) where {T,U,G,S <: AbstractSubGraph{T,U,G}}
128128
adjacency_matrix(subgraph::AbstractSubGraph)
129129
MultilayerGraphs.weights(subgraph::S) where {T,U,S<:AbstractSubGraph{T,U}}
130-
name(subgraph::AbstractSubGraph)
131-
130+
132131
is_multiplex_interlayer(interlayer::Interlayer)
133132
134133
get_symmetric_interlayer(
135134
interlayer::In;
136135
symmetric_interlayer_name::String = String(interlayer.name) * "_rev"
137136
) where {T,U,G,In<:Interlayer{T,U,G}}
137+
138+
name(subgraph::AbstractSubGraph)
139+
graph(subgraph::AbstractSubGraph)
138140
```
139141

140142
### [Multilayer-Specific Methods](@id msm_eu)

src/MultilayerGraphs.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export
7272
adjacency_matrix,
7373
weights,
7474
name,
75+
graph,
7576
# layer.jl
7677
AbstractLayer,
7778
Layer,
@@ -162,7 +163,7 @@ export
162163
kleitman_wang_graph_generator
163164
# tensorfacoriazations.jl
164165

165-
using Base, InteractiveUtils, IterTools, SimpleTraits, Bijections
166+
using Base, InteractiveUtils, IterTools, SimpleTraits, Bijections, PrettyTables
166167
using Distributions: Uniform
167168
using LinearAlgebra, Statistics, OMEinsum, TensorOperations, Distributions
168169
using DataStructures, SparseArrays
@@ -174,6 +175,7 @@ include("vertices/multilayervertex.jl")
174175
include("vertices/missingvertex.jl")
175176
include("multilayeredge.jl")
176177
include("halfedge.jl")
178+
include("subgraphs/abstractdescriptor.jl")
177179
include("subgraphs/layerdescriptor.jl")
178180
include("subgraphs/interlayerdescriptor.jl")
179181
include("subgraphs/abstractsubgraph.jl")

src/abstractmultilayergraph.jl

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,8 @@ function _specify_interlayer!(
496496
new_interlayer.descriptor
497497

498498
for edge in edges(new_interlayer)
499-
success = add_edge!(mg, edge)
500-
@assert success
499+
@assert add_edge!(mg, edge)
500+
# assert success
501501
end
502502

503503
return true
@@ -1194,3 +1194,29 @@ function get_rich_mv(
11941194
bare_V = mg.v_V_associations[i]
11951195
return MV(bare_V.node, bare_V.layer, mg.v_metadata_dict[i])
11961196
end
1197+
1198+
# Console print utilities
1199+
function to_string(x::AbstractMultilayerGraph)
1200+
layers_strings = join(to_string.(x.layers), "\n\n")
1201+
interlater_strings = join(to_string.(values(x.interlayers)), "\n\n")
1202+
layers_names = name.(x.layers)
1203+
layers_underlying_graphs = typeof.(graph.(x.layers)
1204+
layers_eltypes = eltype(x.layers).parameters
1205+
layers_vertextypes = repeat([layers_eltypes[1]], length(x.layers))
1206+
layers_weighttypes = repeat([layers_eltypes[2]], length(x.layers))
1207+
1208+
interlayers_names = name.(values(x.layers))
1209+
"""
1210+
$(typeof(x))
1211+
1212+
### LAYERS
1213+
1214+
$layers_strings
1215+
1216+
### INTERLAYERS
1217+
1218+
$interlater_strings
1219+
1220+
"""
1221+
end
1222+
Base.show(io::IO, x::AbstractMultilayerGraph) = print(io, to_string(x))

src/multilayergraph.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ function Graphs.add_edge!(
102102
#= # Should we modify weight and metadata or should we return false? This may be something to decide ecosystem-wise
103103
set_weight!(mg, src, dst, _weight)
104104
set_metadata!(mg, src, dst, _metadata) =#
105+
@debug "Edge already exists" me [edge for edge in edges(mg) if node(src(edge)) == Node("node_1") && node(dst(edge)) == Node("node_1")]
105106
return false
106107
end
107108
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""
2+
AbstractDescriptor{T<:Integer,U<:Real,G<:AbstractGraph{T}}
3+
4+
An abstract tyep representing an abstract notion of subgraph descriptor
5+
"""
6+
abstract type AbstractDescriptor{T<:Integer,U<:Real,G<:AbstractGraph{T}} end
7+
8+
name(x::AbstractDescriptor) = x.name
9+
graph(x::AbstractDescriptor) = x.null_graph

src/subgraphs/abstractsubgraph.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ function add_edge_standard!(
284284
weight::W=nothing,
285285
metadata::Union{Tuple,NamedTuple}=NamedTuple(),
286286
) where {T,U<:Real,W<:Union{U,Nothing},S<:AbstractSubGraph{T,U}}
287+
# @debug "" subgraph src dst weight metadata
287288
return add_edge!(
288289
subgraph,
289290
get_v(subgraph, src),
@@ -427,3 +428,10 @@ end
427428
Return the name of `subgraph`.
428429
"""
429430
name(subgraph::AbstractSubGraph) = subgraph.name
431+
432+
"""
433+
name(subgraph::AbstractSubGraph)
434+
435+
Return the underlying graph of `subgraph`.
436+
"""
437+
graph(subgraph::AbstractSubGraph) = subgraph.graph

src/subgraphs/interlayer.jl

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Internal constructor used with InterlayerDescriptor.
9494
function _Interlayer(
9595
layer_1_multilayervertices::Vector{<:MultilayerVertex},
9696
layer_2_multilayervertices::Vector{<:MultilayerVertex},
97-
edge_list::Union{Vector{<:MultilayerEdge{ <: Union{U,Nothing}}}, Vector{NTuple{2, MultilayerVertex}}}, # MultilayerVertex, {<: Union{U, Nothing}}
97+
edge_list::Union{Vector{<:MultilayerEdge{ <: Union{U,Nothing}}}, Vector{Tuple{<:MultilayerVertex, <:MultilayerVertex}}}, # MultilayerVertex, {<: Union{U, Nothing}}
9898
descriptor::InterlayerDescriptor{T,U,G},
9999
) where {T<:Integer,U<:Real,G<:AbstractGraph{T}}
100100

@@ -155,7 +155,7 @@ Constructor for Interlayer.
155155
156156
- `default_edge_weight::Function`: Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
157157
- `default_edge_metadata::Function`: Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
158-
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.interlayer_name)_(layer_2.interlayer_name)");
158+
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.name)_(layer_2.name)");
159159
- `transfer_vertex_metadata::Bool`:if true, vertex metadata found in both connected layers are carried over to the vertices of the Interlayer. NB: not all choice of underlying graph may support this feature. Graphs types that don't support metadata or that pose limitations to it may result in errors.
160160
161161
"""
@@ -167,7 +167,7 @@ function Interlayer(
167167
default_edge_weight::Function=(x, y) -> nothing,
168168
default_edge_metadata::Function=(x, y) -> NamedTuple(),
169169
transfer_vertex_metadata::Bool=false,
170-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
170+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
171171
) where {T<:Integer,U<:Real,G<:AbstractGraph{T}}
172172

173173
#= layer_1_multilayervertices = collect(mv_vertices(layer_1))
@@ -225,7 +225,7 @@ function _Interlayer(
225225
default_edge_weight::Function=(x, y) -> nothing,
226226
default_edge_metadata::Function=(x, y) -> NamedTuple(),
227227
transfer_vertex_metadata::Bool=false,
228-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
228+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
229229
) where {L1,L2,T<:Integer,U<:Real,G<:AbstractGraph{T}}
230230
231231
descriptor = InterlayerDescriptor(
@@ -266,7 +266,7 @@ Return a random `Interlayer`.
266266
267267
- `default_edge_weight::Function`: Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
268268
- `default_edge_metadata::Function`: Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
269-
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.interlayer_name)_(layer_2.interlayer_name)");
269+
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.name)_(layer_2.name)");
270270
- `transfer_vertex_metadata::Bool`:if true, vertex metadata found in both connected layers are carried over to the vertices of the Interlayer. NB: not all choice of underlying graph may support this feature. Graphs types that don't support metadata or that pose limitations to it may result in errors.
271271
"""
272272
function Interlayer(
@@ -276,7 +276,7 @@ function Interlayer(
276276
null_graph::G;
277277
default_edge_weight::Function=(x, y) -> nothing,
278278
default_edge_metadata::Function=(x, y) -> NamedTuple(),
279-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
279+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
280280
transfer_vertex_metadata::Bool=false,
281281
) where {T<:Integer,U<:Union{Nothing,<:Real},G<:AbstractGraph{T}}
282282

@@ -403,7 +403,7 @@ function _Interlayer(
403403
default_edge_weight::Function=(x, y) -> nothing,
404404
default_edge_metadata::Function=(x, y) -> NamedTuple(),
405405
transfer_vertex_metadata::Bool=false,
406-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
406+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
407407
) where {L1,L2,T<:Integer,U<:Union{Nothing,<:Real},G<:AbstractGraph{T}}
408408
(L1 != L2) ||
409409
throw(ErrorException("The two layers must be different. Found $(L1) and $(L2)"))
@@ -467,7 +467,7 @@ Return an `Interlayer{T,U,G}` that has edges only between vertices that represen
467467
468468
- `default_edge_weight::Function`: Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
469469
- `default_edge_metadata::Function`: Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
470-
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.interlayer_name)_(layer_2.interlayer_name)");
470+
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.name)_(layer_2.name)");
471471
- `transfer_vertex_metadata::Bool`:if true, vertex metadata found in both connected layers are carried over to the vertices of the Interlayer. NB: not all choice of underlying graph may support this feature. Graphs types that don't support metadata or that pose limitations to it may result in errors;
472472
"""
473473
multiplex_interlayer(
@@ -477,7 +477,7 @@ multiplex_interlayer(
477477
default_edge_weight::Function=(x, y) -> nothing,
478478
default_edge_metadata::Function=(x, y) -> NamedTuple(),
479479
transfer_vertex_metadata::Bool=false,
480-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)")
480+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)")
481481
) where {T<:Integer,U<:Real,G<:AbstractGraph{T}} = _multiplex_interlayer(
482482
mv_vertices(layer_1),
483483
mv_vertices(layer_2),
@@ -511,7 +511,7 @@ function _multiplex_interlayer(
511511
default_edge_weight::Function=(x, y) -> nothing,
512512
default_edge_metadata::Function=(x, y) -> NamedTuple(),
513513
transfer_vertex_metadata::Bool=false,
514-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
514+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
515515
) where {L1,L2,T<:Integer,U<:Real,G<:AbstractGraph{T}}
516516
common_nodes = intersect(
517517
[mv.node for mv in layer_1_multilayervertices],
@@ -578,7 +578,7 @@ Construct an empty interlayer (i.e. an interlayer with no edges).
578578
579579
- `default_edge_weight::Function`: Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
580580
- `default_edge_metadata::Function`: Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
581-
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.interlayer_name)_(layer_2.interlayer_name)");
581+
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.name)_(layer_2.name)");
582582
- `transfer_vertex_metadata::Bool`:if true, vertex metadata found in both connected layers are carried over to the vertices of the Interlayer. NB: not all choice of underlying graph may support this feature. Graphs types that don't support metadata or that pose limitations to it may result in errors.;
583583
"""
584584
function empty_interlayer(
@@ -587,7 +587,7 @@ function empty_interlayer(
587587
null_graph::G;
588588
default_edge_weight::Function=(x, y) -> nothing,
589589
default_edge_metadata::Function=(x, y) -> NamedTuple(),
590-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
590+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
591591
transfer_vertex_metadata::Bool=false,
592592
) where {T<:Integer,U<:Real,G<:AbstractGraph{T}}
593593
return _empty_interlayer(
@@ -608,7 +608,7 @@ end
608608
layer_2_multilayervertices::Vector{MultilayerVertex{L2}},
609609
null_graph::G,
610610
weighttype::Type{U};
611-
interlayer_name::Symbol = Symbol("interlayer_(layer_1.interlayer_name)_(layer_2.interlayer_name)"),
611+
interlayer_name::Symbol = Symbol("interlayer_(layer_1.name)_(layer_2.name)"),
612612
transfer_vertex_metadata::Bool = false
613613
) where {L1, L2, T<:Integer, U <: Real, G<:AbstractGraph{T}}
614614
@@ -622,7 +622,7 @@ function _empty_interlayer(
622622
default_edge_weight::Function=(x, y) -> nothing,
623623
default_edge_metadata::Function=(x, y) -> NamedTuple(),
624624
transfer_vertex_metadata::Bool=false,
625-
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)"),
625+
interlayer_name::Symbol=Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"),
626626
) where {L1,L2,T<:Integer,U<:Real,G<:AbstractGraph{T}}
627627
edge_list = MultilayerEdge{U}[]
628628
descriptor = InterlayerDescriptor(
@@ -662,15 +662,15 @@ Constructor for Interlayer whose underlying graph is a `SimpleGraph` from `Graph
662662
# KWARGS
663663
664664
- `vertextype::Type{<:Integer} = Int64`: The type of the underlying integer labels associated to vertices.
665-
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.interlayer_name)_(layer_2.interlayer_name)");
665+
- `interlayer_name::Symbol`: The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.name)_(layer_2.name)");
666666
667667
"""
668668
function interlayer_simplegrah(
669669
layer_1::Layer{T,U},
670670
layer_2::Layer{T,U},
671671
edge_list::Union{<:Vector{<:MultilayerEdge{<:Union{U, Nothing}}}, Vector{NTuple{2, MultilayerVertex}}};
672672
vertextype::Type{<:Integer} = Int64,
673-
interlayer_name::Symbol = Symbol("interlayer_$(layer_1.interlayer_name)_$(layer_2.interlayer_name)")
673+
interlayer_name::Symbol = Symbol("interlayer_$(layer_1.name)_$(layer_2.name)")
674674
) where {T<:Integer,U<:Real}
675675

676676
layer_1_multilayervertices = collect(mv_vertices(layer_1))
@@ -879,7 +879,7 @@ end
879879
Return the `Interlayer` corresponding to `interlayer` where `layer_1` and `layer_2` are swapped. Its interlayer_name will be `symmetric_interlayer_name` (defaults to `interlayer_(interlayer.layer_2)_(interlayer.layer_1)`).
880880
"""
881881
function get_symmetric_interlayer(
882-
interlayer::In; symmetric_interlayer_name::String=String(interlayer.interlayer_name) * "_rev"
882+
interlayer::In; symmetric_interlayer_name::String=String(interlayer.name) * "_rev"
883883
) where {T,U,G,In<:Interlayer{T,U,G}}
884884
# Create a symmetric interlayer descriptor
885885
symmetric_descriptor = InterlayerDescriptor(
@@ -984,3 +984,18 @@ function recompute_interlayer!(
984984
interlayer.graph = graph
985985
return interlayer.v_V_associations = v_V_associations
986986
end
987+
988+
989+
# Console print utilities
990+
function to_string(x::Interlayer)
991+
"""
992+
$(typeof(x))
993+
name: $(name(x))
994+
layer_1: $(x.layer_1)
995+
layer_2: $(x.layer_2)
996+
underlying graph: $(x.graph)
997+
nv = $(nv(x))
998+
ne = $(ne(x))
999+
"""
1000+
end
1001+
Base.show(io::IO, x::Interlayer) = print(io, to_string(x))

src/subgraphs/interlayerdescriptor.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
An abstract type representing an `Interlayer` descriptor object.
55
"""
6-
abstract type AbstractInterlayerDescriptor{T<:Integer,U<:Real,G<:AbstractGraph{T}} end
6+
abstract type AbstractInterlayerDescriptor{T<:Integer,U<:Real,G<:AbstractGraph{T}} <: AbstractDescriptor{T,U,G} end
77

88
"""
99
struct InterlayerDescriptor{T,U,G} <: AbstractInterlayerDescriptor{T,U,G}
@@ -103,3 +103,19 @@ function Base.getproperty(descriptor::InterlayerDescriptor, f::Symbol)
103103
[descriptor.layer_1, descriptor.layer_2]
104104
end
105105
end
106+
107+
108+
# Console print utilities
109+
function to_string(x::InterlayerDescriptor)
110+
parameters = typeof(x).parameters
111+
"""
112+
Interlayer\t$(name(x))
113+
layer_1: $(x.layer_1)
114+
layer_2: $(x.layer_2)
115+
underlying_graph: $(typeof(graph(x)))
116+
transfer_vertex_metadata = $(x.transfer_vertex_metadata)
117+
vertex_type: $(parameters[1])
118+
weight_type: $(parameters[2])
119+
"""
120+
end
121+
Base.show(io::IO, x::InterlayerDescriptor) = print(io, to_string(x))

src/subgraphs/layer.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,3 +1724,17 @@ function Base.getproperty(layer::L, f::Symbol) where {L<:Layer}
17241724
Base.getfield(layer.descriptor, f)
17251725
end
17261726
end
1727+
1728+
# Console print utilities
1729+
function to_string(x::Layer)
1730+
"""
1731+
Layer\t$(name(x))
1732+
underlying_graph: $(typeof(graph(x)))
1733+
vertex_type: $(parameters[1])
1734+
weight_type: $(parameters[2])
1735+
nv = $(nv(x))
1736+
ne = $(ne(x))
1737+
"""
1738+
end
1739+
Base.show(io::IO, x::Layer) = print(io, to_string(x))
1740+

0 commit comments

Comments
 (0)