From 5dfdbc84903d55d75e6a2a6d0fb99ef1f20d4a4a Mon Sep 17 00:00:00 2001 From: Martin Holters Date: Mon, 16 Jan 2023 13:59:51 +0100 Subject: [PATCH 1/2] Avoid using element equality for finding elements in circuit Note the following change: Before: ```julia julia> R = resistor(1000); circ = Circuit(); julia> add!(circ, R) Symbol("##296") julia> add!(circ, R) Symbol("##296") julia> ACME.nb(circ) 1 ``` After: ```julia julia> R = resistor(1000); circ = Circuit(); julia> add!(circ, R) Symbol("##296") julia> add!(circ, R) Symbol("##297") julia> ACME.nb(circ) 2 ``` I.e. the same element can now be added twice. In general, element instances should not have an identity, so the new behaviour seems more reasonable. (The same `R` could already be added to another circuit without having any effect on its presence in the first one, for example.) --- src/circuit.jl | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/circuit.jl b/src/circuit.jl index 3b36dcf4..1adc64df 100644 --- a/src/circuit.jl +++ b/src/circuit.jl @@ -1,4 +1,4 @@ -# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021 Martin Holters +# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2023 Martin Holters # See accompanying license file. export Circuit, add!, connect!, disconnect!, @circuit, composite_element @@ -53,9 +53,8 @@ function incidence(c::Circuit) j = sizehint!(Int[], 2nb(c)) v = sizehint!(Int[], 2nb(c)) for (row, pins) in enumerate(c.nets), (elemname, pinname) in pins - elem = c.elements[elemname] - offset = branch_offset(c, elem) - bps = elem.pins[pinname] + offset = branch_offset(c, elemname) + bps = c.elements[elemname].pins[pinname] for (branch, polarity) in bps push!(i, row) push!(j, offset + branch) @@ -93,11 +92,6 @@ Adds the element `elem` to the circuit `c`, creating and returning a new, unique reference designator, leaving its pins unconnected. """ function add!(c::Circuit, elem::Element) - for (k, v) in c.elements - if v == elem - return k - end - end designator = gensym() add!(c, designator, elem) return designator @@ -135,10 +129,10 @@ function Base.delete!(c::Circuit, designator::Symbol) delete!(c.elements, designator) end -function branch_offset(c::Circuit, elem::Element) +function branch_offset(c::Circuit, designator::Symbol) offset = 0 - for el in elements(c) - el == elem && return offset + for (des, el) in c.elements + des === designator && return offset offset += nb(el) end throw(ArgumentError("Element not found in circuit")) From 8f992d13e6b1fd0fc4aafe1900f99137acc73205 Mon Sep 17 00:00:00 2001 From: Martin Holters Date: Tue, 17 Jan 2023 07:14:50 +0100 Subject: [PATCH 2/2] Implement `==` (and `hash`) for `Element` So that e.g. `resistor(1000) == resistor(1000)`, which previously gave `false`. --- src/ACME.jl | 7 ++++++- test/runtests.jl | 12 +++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ACME.jl b/src/ACME.jl index ffbec765..d78270d5 100644 --- a/src/ACME.jl +++ b/src/ACME.jl @@ -1,4 +1,4 @@ -# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021 Martin Holters +# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2023 Martin Holters # See accompanying license file. module ACME @@ -97,6 +97,11 @@ struct Element end end +Base.:(==)(e1::Element, e2::Element) = + all(f -> (getfield(e1, f) == getfield(e2, f))::Bool, fieldnames(Element)) +Base.hash(e::Element, h::UInt) = + foldl((h, f) -> hash(getfield(e, f), h)::UInt, fieldnames(Element); init=h) + for (n,m) in Dict(:nb => :mv, :nx => :mx, :nq => :mq, :nu => :mu) @eval ($n)(e::Element) = size(e.$m, 2) end diff --git a/test/runtests.jl b/test/runtests.jl index 169f1447..6f33609f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Martin Holters +# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Martin Holters # See accompanying license file. include("checklic.jl") @@ -40,6 +40,16 @@ end @test !ACME.setlhs!(solver, zeros(3,3)) end +@testset "Element equality" begin + @test resistor(1e3) == resistor(1e3) + @test hash(resistor(1e3)) == hash(resistor(1e3)) + @test resistor(1e3) != resistor(2.2e3) + @test resistor(1) != voltagesource(1) + @test bjt(:npn) == bjt(:npn) + @test hash(bjt(:npn)) == hash(bjt(:npn)) + @test bjt(:npn) != bjt(:pnp) +end + @testset "simple circuits" begin @testset "empty circuit" begin circ = @circuit begin end