test/simulation_test.rb in y_petri-2.0.15 vs test/simulation_test.rb in y_petri-2.1.3
- old
+ new
@@ -1,281 +1,355 @@
#! /usr/bin/ruby
-# -*- coding: utf-8 -*-
+# encoding: utf-8
require 'minitest/spec'
require 'minitest/autorun'
require_relative '../lib/y_petri' # tested component itself
# require 'y_petri'
# require 'sy'
-describe ::YPetri::Simulation do
+describe YPetri::Simulation do
before do
- @pç = pç = Class.new( ::YPetri::Place )
- @tç = tç = Class.new( ::YPetri::Transition )
- @nç = nç = Class.new( ::YPetri::Net )
- [ @pç, @tç, @nç ].each { |klass|
- klass.namespace!
- klass.class_exec {
- private
- define_method :Place do pç end
- define_method :Transition do tç end
- define_method :Net do nç end
- }
- }
- @p1 = @pç.new name: "P1", default_marking: 1
- @p2 = @pç.new name: "P2", default_marking: 2
- @p3 = @pç.new name: "P3", default_marking: 3
- @p4 = @pç.new name: "P4", default_marking: 4
- @p5 = @pç.new name: "P5", default_marking: 5
- @t1 = @tç.new name: "T1",
- s: { @p1 => -1, @p2 => -1, @p4 => 1 },
- rate: 0.1
- @t2 = @tç.new name: "T2",
- s: { @p1 => -1, @p3 => 1 },
- rate: -> a { a * 0.5 }
- @t3 = @tç.new name: "T3",
- s: { @p1 => -1, @p2 => -1, @p4 => 1 },
- domain: @p3,
- rate: -> a { a * 0.5 }
- @net = @nç.new << @p1 << @p2 << @p3 << @p4 << @p5
- @net.include_transition! @t1
- @net.include_transition! @t2
- @net << @t3
- @s = YPetri::Simulation.new net: @net,
- marking_clamps: { @p1 => 2.0, @p5 => 2.0 },
- initial_marking: { @p2 => @p2.default_marking,
- @p3 => @p3.default_marking,
- @p4 => @p4.default_marking }
+ @w = YPetri::World.new
end
- it "exposes the net" do
- @s.net.must_equal @net
- @s.net.places.size.must_equal 5
- @s.net.transitions.size.must_equal 3
- assert @net.include? @t1
- assert @s.net.include? @t1
- assert @net.include? @t2
- assert @s.net.include? @t2
- assert @net.include? @t3
- assert @s.net.include? @t3
- @s.net.transitions.size.must_equal 3
+ it "should allow for creation of an empty simulation" do
+ net = @w.Net.new
+ sim = net.simulation
+ sim.pp.must_equal []
+ sim.pp( *[] ).must_equal []
+ sim.tt.must_equal( [] )
+ sim.tt( *[] ).must_equal []
end
- it "exposes Petri net places" do
- @s.places.must_equal [ @p1, @p2, @p3, @p4, @p5 ]
- @s.pp.must_equal [ :P1, :P2, :P3, :P4, :P5 ]
- @s.places( :pp ).must_equal( { @p1 => :P1, @p2 => :P2, @p3 => :P3,
- @p4 => :P4, @p5 => :P5 } )
- @s.pp( :pp ).must_equal( { P1: :P1, P2: :P2, P3: :P3, P4: :P4, P5: :P5 } )
- end
+ describe "simulation setup" do
+ before do
+ @p = @w.Place.new name: :A, default_marking: 1
+ @q = @w.Place.new name: :B, default_marking: 2
+ @net = @w.Net.of @p, @q
+ end
- it "exposes Petri net transitions" do
- @s.transitions.must_equal [ @t1, @t2, @t3 ]
- @s.tt.must_equal [ :T1, :T2, :T3 ]
- @s.transitions( :tt ).must_equal( { @t1 => :T1, @t2 => :T2, @t3 => :T3 } )
- @s.tt( :tt ).must_equal( { T1: :T1, T2: :T2, T3: :T3 } )
- end
+ it "should allow to set up a simplistic simulation instance" do
+ @net.simulation
+ @net.simulation marking_clamps: { @q => 42 } # one clamp
+ @net.simulation initial_marking: { @p => 42, @q => 43 }
+ @net.simulation marking_clamps: { @p => 42 }, initial_marking: { @q => 43 }
+ @net.simulation initial_marking: { A: 42 }
+ end
- it "exposes place clamps" do
- @s.clamped_places( :place_clamps ).must_equal( { @p1 => 2, @p5 => 2 } )
- @s.clamped_pp( :place_clamps ).must_equal( { P1: 2, P5: 2 } )
- end
+ it "should fail with malformed arguments" do
+ -> { @net.simulation use_default_marking: false }.must_raise TypeError
+ -> { @net.simulation initial_marking: { Foo: 1 } }.must_raise NameError
+ end
- it "presents free places" do
- @s.free_places.must_equal [ @p2, @p3, @p4 ]
- @s.free_pp.must_equal [ :P2, :P3, :P4 ]
- @s.free_places( :free_pp )
- .must_equal( { @p2 => :P2, @p3 => :P3, @p4 => :P4 } )
- @s.free_pp( :free_pp )
- .must_equal( { P2: :P2, P3: :P3, P4: :P4 } )
- end
+ describe "place representation aspects" do
+ before do
+ @s = YPetri::Simulation.new( net: @net,
+ initial_marking: { A: 42 },
+ marking_clamps: { B: 43 } )
+ end
- it "presents clamped places" do
- @s.clamped_places.must_equal [ @p1, @p5 ]
- @s.clamped_pp.must_equal [ :P1, :P5 ]
- @s.clamped_places( :clamped_pp ).must_equal( { @p1 => :P1, @p5 => :P5 } )
- @s.clamped_pp( :clamped_pp ).must_equal( { P1: :P1, P5: :P5 } )
- end
+ it "should have elements/access" do
+ @s.send( :place, :A )
+ .must_be_kind_of YPetri::Simulation::PlaceRepresentation
+ @s.send( :place, :B )
+ .must_be_kind_of YPetri::Simulation::PlaceRepresentation
+ @s.net.places.names.must_equal [:A, :B]
+ @s.pn.must_equal [:A, :B]
+ @s.send( :places ).free.size.must_equal 1
+ @s.send( :free_places ).names.must_equal [:A]
+ @s.send( :places ).clamped.size.must_equal 1
+ @s.send( :clamped_places ).names.must_equal [:B]
+ @s.send( :places, [:A] ).map( &:source ).must_equal [@p]
+ @s.send( :transitions, [] ).must_equal []
+ @s.send( :places, [:A] ).map( &:source ).must_equal [@p]
+ @s.send( :places, [] ).must_equal []
+ end
- it "exposes initial marking" do
- @s.free_places( :im ).must_equal( { @p2 => 2, @p3 => 3, @p4 => 4 } )
- @s.free_pp( :im ).must_equal( { P2: 2, P3: 3, P4: 4 } )
- @s.im.must_equal [ 2, 3, 4 ]
- @s.im_vector.must_equal Matrix[[2], [3], [4]]
- @s.im_vector.must_equal @s.iᴍ
- end
+ describe "marking vector representation" do
+ it "should work" do
+ @s.instance_variable_get( :@m_vector ).must_equal @s.m_vector
+ @s.m_vector.must_be_kind_of YPetri::Simulation::MarkingVector
+ @s.m_vector.size.must_equal 2
+ @s.m_vector.to_a.must_equal [42, 43]
+ @s.m.must_equal [42, 43]
+ @s.marking.must_equal [42]
+ @s.marking_clamps.keys_to_names.must_equal( { B: 43 } )
+ end
+ end
+ end # describe simulation step
- it "exposes marking (simulation state)" do
- @s.m.must_equal [2, 3, 4] # (we're after reset)
- @s.free_places( :m ).must_equal( { @p2 => 2, @p3 => 3, @p4 => 4 } )
- @s.free_pp( :m ).must_equal( { P2: 2, P3: 3, P4: 4 } )
- @s.ᴍ.must_equal Matrix[[2], [3], [4]]
- end
+ describe "transition representation aspects" do
+ before do
+ @ts = @w.Transition.new name: "T_ts", codomain: :A, action: -> { 1 }
+ @tS = @w.Transition.new name: "T_tS", s: { B: -1, A: 1 }, action: proc { 1 }
+ @Ts = @w.Transition.new name: "T_Ts", codomain: :A, rate: -> { 1 }
+ @TS = @w.Transition.new name: "T_TS", s: { B: -1, A: 1 }, rate: proc { 1 }
+ end
- it "separately exposes marking of clamped places" do
- @s.m_clamped.must_equal [ 2, 2 ]
- @s.clamped_places( :m_clamped ).must_equal( { @p1 => 2, @p5 => 2 } )
- @s.clamped_pp( :m_clamped ).must_equal( { P1: 2, P5: 2 } )
- @s.ᴍ_clamped.must_equal Matrix[[2], [2]]
- end
+ it "should be what intended" do
+ @ts.type.must_equal :ts
+ @ts.domain.must_equal []
+ @ts.codomain.must_equal [@p]
+ @tS.type.must_equal :tS
+ @tS.domain.must_equal [@q] # inferred
+ @tS.codomain.must_equal [@q, @p]
+ @Ts.type.must_equal :Ts
+ @Ts.domain.must_equal []
+ @Ts.codomain.must_equal [@p]
+ @TS.type.must_equal :TS
+ @TS.domain.must_equal [@q] # inferred
+ @TS.codomain.must_equal [@q, @p]
+ end
- it "exposes marking of all places (with capitalized M)" do
- @s.marking.must_equal [ 2, 2, 3, 4, 2 ]
- @s.places( :marking )
- .must_equal( { @p1 => 2, @p2 => 2, @p3 => 3, @p4 => 4, @p5 => 2 } )
- @s.pp( :marking ).must_equal( { P1: 2, P2: 2, P3: 3, P4: 4, P5: 2 } )
- @s.marking_vector.must_equal Matrix[[2], [2], [3], [4], [2]]
- end
+ describe "ts transition" do
+ before do
+ @net = @w.Net.of @p, @q, @ts
+ end
- it "has #S_for / #stoichiometry_matrix_for" do
- assert_equal Matrix.empty(3, 0), @s.S_for( [] )
- assert_equal Matrix[[-1], [0], [1]], @s.S_for( [@t1] )
- x = Matrix[[-1, -1], [0, 0], [1, 1]]
- x.must_equal @s.S_for( [@t1, @t3] )
- x.must_equal( @s.S_for( [@t1, @t3] ) )
- @s.stoichiometry_matrix_for( [] ).must_equal Matrix.empty( 5, 0 )
- end
+ describe "no clamps" do
+ before do
+ @sim = @net.simulation net: @net
+ end
- it "has stoichiometry matrix for 3. tS transitions" do
- @s.S_tS.must_equal Matrix.empty( 3, 0 )
- end
+ it "should behave" do
+ @sim.tt.size.must_equal 1
+ @ts.codomain.names.must_equal [:A]
+ @sim.ts_tt.first.codomain.names.must_equal [:A]
+ @ts.domain.names.must_equal []
+ @sim.ts_tt.first.domain.names.must_equal []
+ @sim.timed?.must_equal false
+ @sim.m.must_equal [1, 2]
+ @sim.pm.must_equal( { A: 1, B: 2 } )
+ @sim.recording.must_equal( { 0 => [1, 2]} )
+ @sim.simulation_method.must_equal :pseudo_euler
+ @sim.core.must_be_kind_of YPetri::Core
+ @sim.ts_tt.first.domain.must_equal []
+ @sim.send( :ts_transitions ).first.domain_access_code.must_equal ''
+ λ = @sim.send( :transitions ).ts.first.delta_closure
+ λ.arity.must_equal 0
+ λ.call.must_equal 1
+ cc = @sim.send( :transitions ).ts.delta_closures
+ cc.map( &:call ).must_equal [1]
+ cl = @sim.send( :transitions ).ts.delta_closure
+ cl.call.must_equal Matrix[ [1], [0] ]
+ @sim.step!
+ @sim.pm.must_equal( { A: 2, B: 2 } ) # marking of A goes up by 1
+ @sim.recording.must_equal( { 0 => [1, 2], 1 => [2, 2] } )
+ end
+ end
- it "has stoichiometry matrix for 4. Sr transitions" do
- @s.S_TSr.must_equal Matrix.empty( 3, 0 )
- end
+ describe "with clamps" do
+ before do
+ @sim = @net.simulation marking_clamps: { B: 42 }
+ end
- it "has stoichiometry matrix for 6. SR transitions" do
- @s.S_SR.must_equal Matrix[[-1, 0, -1], [0, 1, 0], [1, 0, 1]]
- @s.S.must_equal @s.S_SR
- end
+ it "should behave" do
+ @sim.recording.must_equal( { 0 => [1] } )
+ @sim.step!
+ @sim.recording.must_equal( { 0 => [1], 1 => [2] } )
+ end
+ end
+ end # ts transition
- it "presents 1. ts" do
- assert_equal [], @s.ts_transitions
- assert_equal( {}, @s.ts_transitions( :ts_transitions ) )
- assert_equal [], @s.ts_tt
- assert_equal( {}, @s.ts_tt( :ts_tt ) )
- end
+ describe "tS transition" do
+ before do
+ @net = @w.Net.of @p, @q, @tS
+ end
- it "presents 2. tS transitions" do
- assert_equal [], @s.tS_transitions
- assert_equal( {}, @s.tS_transitions( :tS_transitions ) )
- assert_equal [], @s.tS_tt
- assert_equal( {}, @s.tS_tt( :tS_tt ) )
- end
+ describe "no clamps" do
+ before do
+ @sim = @net.simulation net: @net
+ end
- it "presents 3. Tsr transitions" do
- assert_equal [], @s.Tsr_transitions
- assert_equal( {}, @s.Tsr_transitions( :Tsr_transitions ) )
- assert_equal [], @s.Tsr_tt
- assert_equal( {}, @s.Tsr_tt( :Tsr_tt ) )
- end
+ it "should behave" do
+ @sim.recording.must_equal( { 0 => [1, 2] } )
+ @sim.step!
+ @sim.recording.must_equal( { 0 => [1, 2], 1 => [2, 1] } )
+ end
+ end
- it "presents 4. TSr transitions" do
- assert_equal [], @s.TSr_transitions
- assert_equal( {}, @s.TSr_transitions( :TSr_tt ) )
- assert_equal [], @s.TSr_tt
- assert_equal( {}, @s.TSr_tt( :TSr_tt ) )
- end
+ describe "with clamps" do
+ before do
+ @sim = @net.simulation marking_clamps: { B: 43 }
+ end
- it "presents 5. sR transitions" do
- assert_equal [], @s.sR_transitions
- assert_equal( {}, @s.sR_transitions( :sR_transitions ) )
- assert_equal [], @s.sR_tt
- assert_equal( {}, @s.sR_tt( :sR_tt ) )
- end
+ it "should behave" do
+ @sim.recording.must_equal( { 0 => [1] } )
+ 3.times do @sim.step! end
+ @sim.recording.must_equal( { 0 => [1], 1 => [2], 2 => [3], 3 => [4] } )
+ end
+ end
+ end # tS transition
- it "presents SR transitions" do
- assert_equal [@t1, @t2, @t3], @s.SR_transitions
- assert_equal( { @t1 => :T1, @t2 => :T2, @t3 => :T3 },
- @s.SR_transitions( :SR_tt ) )
- assert_equal [:T1, :T2, :T3], @s.SR_tt
- assert_equal( { T1: :T1, T2: :T2, T3: :T3 }, @s.SR_tt( :SR_tt ) )
- end
+ describe "Ts transition" do
+ before do
+ @net = @w.Net.of @p, @q, @Ts
+ end
- it "presents A transitions" do
- assert_equal [], @s.A_transitions
- assert_equal( {}, @s.A_transitions( :A_tt ) )
- assert_equal [], @s.A_tt
- assert_equal( {}, @s.A_tt( :A_tt ) )
- end
+ describe "no clamps" do
+ before do
+ @sim = @net.simulation sampling: 1
+ end
- it "presents S transitions" do
- assert_equal [@t1, @t2, @t3], @s.S_transitions
- assert_equal [:T1, :T2, :T3], @s.S_tt
- assert_equal( { T1: :T1, T2: :T2, T3: :T3 }, @s.S_tt( :S_tt ) )
- end
+ it "should behave" do
+ @sim.timed?.must_equal true
+ @sim.simulation_method.must_equal :pseudo_euler
+ @sim.Ts_tt.size.must_equal 1
+ @sim.send( :transitions ).Ts.first.gradient_closure.call.must_equal 1
+ @sim.Ts_tt.first.codomain.names.must_equal [:A]
+ @sim.recording.must_equal( { 0.0 => [1, 2] } )
+ @sim.step! 1
+ @sim.recording.must_equal( { 0.0 => [1, 2], 1.0 => [2, 2] } )
+ end
+ end
- it "presents s transitions" do
- assert_equal [], @s.s_transitions
- assert_equal [], @s.s_tt
- assert_equal( {}, @s.s_tt( :s_tt ) )
- end
+ describe "with clamps" do
+ before do
+ @sim = @net.simulation sampling: 1, marking_clamps: { B: 43 }
+ end
- it "presents R transitions" do
- assert_equal [@t1, @t2, @t3], @s.R_transitions
- assert_equal [:T1, :T2, :T3], @s.R_tt
- assert_equal( { T1: :T1, T2: :T2, T3: :T3 }, @s.R_tt( :R_tt ) )
- end
+ it "should behave" do
+ @sim.recording.must_equal( { 0.0 => [1] } )
+ 3.times do @sim.step! 1 end
+ @sim.recording.must_equal( { 0.0 => [1], 1.0 => [2], 2.0 => [3], 3.0 => [4] } )
+ end
+ end
+ end # Ts transition
- it "presents r transitions" do
- assert_equal [], @s.r_transitions
- assert_equal [], @s.r_tt
- end
+ describe "TS transition" do
+ before do
+ @net = @w.Net.of @p, @q, @TS
+ end
- it "1. handles ts transitions" do
- @s.Δ_closures_for_tsa.must_equal []
- @s.Δ_if_tsa_fire_once.must_equal Matrix.zero( @s.free_pp.size, 1 )
- end
+ describe "no clamps" do
+ before do
+ @sim = @net.simulation sampling: 1
+ end
- it "2. handles Tsr transitions" do
- @s.Δ_closures_for_Tsr.must_equal []
- @s.Δ_Tsr( 1.0 ).must_equal Matrix.zero( @s.free_pp.size, 1 )
- end
+ it "should behave" do
+ @sim.recording.must_be_kind_of YPetri::Net::State::Features::Dataset
+ @sim.recording.must_equal @net.State.marking.new_dataset.update( 0.0 => [1, 2] )
+ @sim.recording.must_equal( { 0.0 => [1, 2] } )
+ @sim.step! 1
+ @sim.recording.must_equal( { 0.0 => [1, 2], 1.0 => [2, 1] } )
+ end
+ end
- it "3. handles tS transitions" do
- @s.action_closures_for_tS.must_equal []
- @s.action_vector_for_tS.must_equal Matrix.column_vector( [] )
- @s.ᴀ_t.must_equal Matrix.column_vector( [] )
- @s.Δ_if_tS_fire_once.must_equal Matrix.zero( @s.free_pp.size, 1 )
- end
+ describe "with clamps" do
+ before do
+ @sim = @net.simulation sampling: 1, marking_clamps: { B: 43 }
+ end
- it "4. handles TSr transitions" do
- @s.action_closures_for_TSr.must_equal []
- @s.action_closures_for_Tr.must_equal []
- @s.action_vector_for_TSr( 1.0 ).must_equal Matrix.column_vector( [] )
- @s.action_vector_for_Tr( 1.0 ).must_equal Matrix.column_vector( [] )
- @s.Δ_TSr( 1.0 ).must_equal Matrix.zero( @s.free_pp.size, 1 )
+ it "should behave" do
+ @sim.recording.must_equal( { 0.0 => [1] } )
+ 3.times do @sim.step! end
+ @sim.recording.must_equal( { 0.0 => [1], 1.0 => [2], 2.0 => [3], 3.0 => [4] } )
+ end
+ end
+ end # TS transition
+ end # transition representation aspects
end
+end
- it "5. handles sR transitions" do
- assert_equal [], @s.rate_closures_for_sR
- assert_equal [], @s.rate_closures_for_s
- # @s.gradient_for_sR.must_equal Matrix.zero( @s.free_pp.size, 1 )
- @s.Δ_sR( 1.0 ).must_equal Matrix.zero( @s.free_pp.size, 1 )
+
+describe YPetri::Simulation do
+ before do
+ self.class.class_exec { include YPetri }
+ U = Place m!: 2.5
+ V = Place m!: 2.5
+ Uplus = Transition codomain: :U do 1 end # s transition
+ U2V = Transition s: { U: -1, V: 1 } # S transition
+ set_ssc :Timeless, YPetri::Simulation::DEFAULT_SETTINGS.call
+ new_simulation ssc: :Timeless
+ 5.times do simulation.step! end
end
- it "6. handles stoichiometric transitions with rate" do
- @s.rate_closures_for_SR.size.must_equal 3
- @s.rate_closures_for_S.size.must_equal 3
- @s.rate_closures.size.must_equal 3
- @s.flux_vector_for_SR.must_equal Matrix.column_vector( [ 0.4, 1.0, 1.5 ] )
- @s.φ_for_SR.must_equal @s.flux_vector
- @s.SR_tt( :φ_for_SR ).must_equal( { T1: 0.4, T2: 1.0, T3: 1.5 } )
- @s.first_order_action_vector_for_SR( 1 )
- .must_equal Matrix.column_vector [ 0.4, 1.0, 1.5 ]
- @s.SR_tt( :first_order_action_for_SR, 1 ).must_equal( T1: 0.4, T2: 1.0, T3: 1.5 )
- @s.Δ_SR( 1 ).must_equal Matrix[[-1.9], [1.0], [1.9]]
- @s.free_pp( :Δ_SR, 1 ).must_equal( { P2: -1.9, P3: 1.0, P4: 1.9 } )
+ it "should behave" do
+ simulation.tap do |s|
+ assert ! s.timed?
+ s.core.must_be_kind_of YPetri::Core::Timeless::PseudoEuler
+ s.recording.size.must_equal 6
+ s.recording.events.must_equal [0, 1, 2, 3, 4, 5]
+ s.recording.reconstruct( event: 2 ).pm.must_equal( { U: 2.5, V: 4.5 } )
+ s.recording.marking.slice( 2..4 ).series
+ .must_equal [[2.5, 2.5, 2.5], [4.5, 5.5, 6.5]]
+ s.recording.marking( slice: 2..4 )
+ .must_equal( { 2 => [2.5, 4.5],
+ 3 => [2.5, 5.5],
+ 4 => [2.5, 6.5] } )
+ s.recording.firing_series( slice: 1..2 )
+ .must_equal [[1, 1]]
+ s.recording.firing_series( transitions: [:U2V] )
+ .must_equal [[1, 1, 1, 1, 1, 1]]
+ s.recording.delta_series( places: [:U], transitions: [:Uplus] )
+ .must_equal [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0]]
+ tmp = s.recording.features( marking: [:U], firing: [:U2V] )
+ tmp.delete( :features )
+ .must_equal( { marking: [:U], firing: [:U2V],
+ delta: { places: [], transitions: [] } } )
+ tmp.must_equal( { 0 => [2.5, 1], 1 => [2.5, 1], 2 => [2.5, 1],
+ 3 => [2.5, 1], 4 => [2.5, 1], 5 => [2.5, 1] } )
+ end
end
+end
- it "presents sparse stoichiometry vectors for its transitions" do
- @s.sparse_σ( @t1 ).must_equal Matrix.cv( [-1, 0, 1] )
- @s.sparse_stoichiometry_vector( @t1 )
- .must_equal Matrix.cv( [-1, -1, 0, 1, 0] )
+
+describe YPetri::Simulation::Timed do
+ before do
+ skip
+ self.class.class_exec { include YPetri }
+ A = Place m!: 0.5
+ B = Place m!: 0.5
+ A_pump = T s: { A: -1 } do 0.005 end
+ B_decay = Transition s: { B: -1 }, rate: 0.05
+ run!
end
- it "presents correspondence matrices free, clamped => all places" do
- @s.F2A.must_equal Matrix[[0, 0, 0], [1, 0, 0], [0, 1, 0],
- [0, 0, 1], [0, 0, 0]]
- @s.C2A.must_equal Matrix[[1, 0], [0, 0], [0, 0], [0, 0], [0, 1]]
+ it "should behave" do
+ places.map( &:marking ).must_equal [0.5, 0.5] # marking unaffected
+ simulation.tap do |s|
+ s.settings.must_equal( { method: :pseudo_euler, guarded: false,
+ step: 0.1, sampling: 5, time: 0..60 } )
+ assert s.recording.to_csv.start_with?( "0.0,0.5,0.5\n" +
+ "5.0,0.475,0.38916\n" +
+ "10.0,0.45,0.30289\n" +
+ "15.0,0.425,0.23574\n" +
+ "20.0,0.4,0.18348\n" +
+ "25.0,0.375,0.1428\n" )
+ assert s.recording.to_csv.end_with?( "60.0,0.2,0.02471" )
+ s.recording.events.must_equal [ 0.0, 5.0, 10.0, 15.0, 20.0,
+ 25.0, 30.0, 35.0, 40.0, 45.0,
+ 50.0, 55.0, 60.0 ]
+ s.recording.values_at( 5, 10 )
+ .must_equal [ [0.475, 0.38916], [0.45, 0.30289] ]
+ s.recording.slice( 2..12 )
+ .must_equal( { 5.0 => [0.475, 0.38916], 10.0=>[0.45, 0.30289] } )
+ s.recording.net
+ .must_equal net
+ s.recording.features
+ .must_equal net.State.marking( [:A, :B] )
+ net.State.Features.State
+ .must_equal net.State
+ s.recording.State
+ .must_equal net.State
+ s.recording.series( marking: [:A] )
+ .must_equal [ [ 0.5, 0.475, 0.45, 0.425, 0.4, 0.375, 0.35, 0.325,
+ 0.3, 0.275, 0.25, 0.225, 0.2 ] ]
+ s.recording.firing.series
+ .must_equal []
+ s.recording.firing
+ .must_equal( [*0..12].map { |n| n * 5.0 } >> [[]] * 13 )
+ # It is obvious why this fails: Given delta feature is not in the
+ # recording. It has to be generated, and since the net is timed,
+ # it also requires Δt to be generated.
+
+ # I'll comment it out for a while to see what the plot is doing.
+=begin
+ s.recording.delta( [:A], transitions: [:A_pump] )
+ .must_equal [ [ -0.0005 ] * 13 ]
+=end
+ plot_state
+ sleep 5
+ end
end
end