Skip to content

Commit

Permalink
WIP adding unit tets for Julia interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Lecrapouille committed Apr 30, 2024
1 parent da41e40 commit 8d7ee33
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 20 deletions.
20 changes: 7 additions & 13 deletions src/julia/Julia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,10 @@ bool petri_is_event_graph(int64_t const pn, bool* res)

std::vector<tpne::Arc*> erroneous_arcs;
std::string error;
if (isEventGraph(*g_petri_nets[size_t(pn)], error, erroneous_arcs))
return true;
std::cerr << error << std::endl;
return false;
*res = isEventGraph(*g_petri_nets[size_t(pn)], error, erroneous_arcs);
if (!error.empty())
std::cerr << error << std::endl;
return true;
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -458,16 +458,13 @@ bool petri_to_sys_lin(int64_t const pn, CSparseMatrix_t* pD, CSparseMatrix_t* pA
}

//------------------------------------------------------------------------------
bool petri_dater_equation(int64_t const pn, bool use_caption)
bool petri_dater_equation(int64_t const pn, bool use_caption, bool maxplus_notation)
{
CHECK_VALID_PETRI_HANDLE(pn, false);
CHECK_IS_EVENT_GRAPH(pn, false);

std::cout
<< tpne::showDaterEquation(*g_petri_nets[size_t(pn)], "", use_caption, true).str()
<< std::endl
<< tpne::showDaterEquation(*g_petri_nets[size_t(pn)], "", use_caption, false).str()
<< std::endl;
<< tpne::showDaterEquation(*g_petri_nets[size_t(pn)], "", use_caption, maxplus_notation).str();
return true;
}

Expand All @@ -478,10 +475,7 @@ bool petri_counter_equation(int64_t const pn, bool use_caption, bool minplus_not
CHECK_IS_EVENT_GRAPH(pn, false);

std::cout
<< tpne::showCounterEquation(*g_petri_nets[size_t(pn)], "", use_caption, true).str()
<< std::endl
<< tpne::showCounterEquation(*g_petri_nets[size_t(pn)], "", use_caption, false).str()
<< std::endl;
<< tpne::showCounterEquation(*g_petri_nets[size_t(pn)], "", use_caption, minplus_notation).str();
return true;
}

Expand Down
12 changes: 10 additions & 2 deletions src/julia/Julia.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,24 @@ extern "C" int64_t petri_to_canonical(int64_t const pn);
// ****************************************************************************
//! \brief Display the event graph into its dater equation.
//! \param[in] pn: the handle of the petri net created by create_petri_net().
//! \param[in] use_caption: display node captions instead of node keys.
//! \param[in] maxplus_notation: display (max,+) notation instead of classical
//! algebra.
//! \return false if the Petri net handle is invalid or return true.
// ****************************************************************************
extern "C" bool petri_dater_equation(int64_t const pn);
extern "C" bool petri_dater_equation(int64_t const pn, bool use_caption,
bool maxplus_notation);

// ****************************************************************************
//! \brief Display the event graph into its counter equation.
//! \param[in] pn: the handle of the petri net created by create_petri_net().
//! \param[in] use_caption: display node captions instead of node keys.
//! \param[in] minplus_notation: display (min,+) notation instead of classical
//! algebra.
//! \return false if the Petri net handle is invalid or return true.
// ****************************************************************************
extern "C" bool petri_counter_equation(int64_t const pn);
extern "C" bool petri_counter_equation(int64_t const pn, bool use_caption,
bool minplus_notation);

// ****************************************************************************
//! \brief Show the critical cycle in the graph event.
Expand Down
18 changes: 13 additions & 5 deletions src/julia/TimedPetriNetEditor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ function to_graph(pn::PetriNet)
end

"""
to_graph
to_syslin
If and only if the Petri net is an event graph then generate the implicit dynamic linear Max-Plus system.
State space representation:
Expand All @@ -884,12 +884,20 @@ function to_syslin(pn::PetriNet)
)
end

function dater(pn::PetriNet)
ccall((:petri_dater_equation, libtpne), Bool, (Clonglong,), pn.handle) || error("Invalid Petri net handle")
"""
show_dater_equation
"""
function show_dater_equation(pn::PetriNet, use_caption, maxplus_notation)
ccall((:petri_dater_equation, libtpne), Bool, (Clonglong,Bool,Bool,),
pn.handle, use_caption, maxplus_notation) || error("Invalid Petri net handle")
end

function counter(pn::PetriNet)
ccall((:petri_counter_equation, libtpne), Bool, (Clonglong,), pn.handle) || error("Invalid Petri net handle")
"""
show_counter_equation
"""
function show_counter_equation(pn::PetriNet, use_caption, minplus_notation)
ccall((:petri_counter_equation, libtpne), Bool, (Clonglong,Bool,Bool,),
pn.handle, use_caption, minplus_notation) || error("Invalid Petri net handle")
end

#end # TimedPetriNetEditor module
170 changes: 170 additions & 0 deletions src/julia/tests/test_petri.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using SparseArrays, MaxPlus

# Note: soon will included in MaxPlus.jl
include("TimedPetriNetEditor.jl")

# Create an empty Petri net and return its handle. You can create several nets.
pn = petri_net()
@assert pn.handle == 0

# Or create new Petri net by loading it.
pn1 = petri_net("../../data/examples/TrafficLights.json")
@assert pn1.handle == 1

# Duplicate the net
pn2 = petri_net(pn)
@assert pn2.handle == 2

# Failed loading file. FIXME shall not store pn3 internally
pn3 = petri_net("doesnotexist.json")
pn3 = petri_net(pn1)
@assert pn3.handle == 4 # FIXME shall be 3

# Has no places and no transitions? Return true in this case.
is_empty(pn)
@assert ans == true
is_empty(pn1)
@assert ans == false
is_empty(pn2)
@assert ans == true
is_empty(pn3)
@assert ans == false

# Clear the Petri net (remove all nodes and arcs)
clear!(pn3)
@assert is_empty(pn3) == true

# Create places. X-Y coordinate (3.15, 4.15) and 5 tokens for Place 0.
# Return its identifier.
p0 = add_place!(pn, 100.0, 100.0, 5)
@assert ans == 0
p1 = add_place!(pn, 200.0, 200.0, 0)
@assert ans == 1
p2 = add_place!(pn, Place(210.0, 210.0, 10))
@assert ans == 2

# Get the place content
p3 = place(pn, p2)
@assert p3.x == 210.0
@assert p3.y == 210.0
@assert p3.tokens == 10

# Set/Get the number of tokens
tokens(pn, p0)
@assert ans == 5
tokens!(pn, p0, 2)
@assert ans == true
tokens(pn, p0)
@assert ans == 2

# Create transitions. X-Y coordinate (1.0, 2.0) for Transition 0.
# Return its identifier.
t0 = add_transition!(pn, 150.0, 150.0)
@assert ans == 0
t1 = add_transition!(pn, 250.0, 250.0)
@assert ans == 1
t2 = add_transition!(pn, Transition(200.0, 240.0))
@assert ans == 2

# Get the transition content
t3 = transition(pn, t2)
@assert t3.x == 200.0
@assert t3.y == 240.0

# Remove nodes. Be careful the handle of the latest inserted node is invalidated
remove_place!(pn, p1)
@assert ans == true
remove_transition!(pn, t0)
@assert ans == true

# Get the number of nodes
count_transitions(pn)
@assert ans == 2
count_places(pn)
@assert ans == 2

# Get the list of places
places(pn)
@assert size(ans) == (2,)

# Get the list of transitions
transitions(pn)
@assert size(ans) == (2,)

# TODO missing API for arcs :(

# You can save the Petri net to JSON file
# Note: you cannot save empty net
add_place!(pn3, 100.0, 100.0, 5)
is_empty(pn3)
@assert ans == false
save(pn3, "/tmp/petri.json")
@assert ans == true
clear!(pn3)
@assert ans == true
is_empty(pn3)
@assert ans == true
# Load the same file back (old net is deleted)
load!(pn3, "/tmp/petri.json")
@assert ans == true
is_empty(pn2)
@assert ans == true
save(pn2, "/tmp/dummy.json")
@assert ans == true
load!(pn3, "/tmp/dummy.json")
@assert ans == true
is_empty(pn3)
@assert ans == true

# Or create one
pn4 = load("../../data/examples/Howard2.json")
@assert pn4.handle == 5 # FIXME should be ideally 4

# Number of nodes and arcs
count_places(pn4)
@assert ans == 5
count_transitions(pn4)
@assert ans == 4
# TODO count_arcs(pn4)
# @assert ans == 4

# Get the list of marks (number of tokens for each place P0, P1 .. Pn)
tokens(pn4)
@assert ans == [2; 0; 0; 0; 0]

# Check if Petri net is an event graph
is_event_graph(pn4)
@assert ans == true
is_event_graph(pn1)
@assert ans == false

# Modify the number of tokens for each place
tokens!(pn4, [0; 1; 2; 3; 4])
@assert ans == true

# If the Petri net is an event graph, you can return the canonical form
pn5 = canonic(pn4)
@assert pn5.handle == 6 # FIXME should be ideally 5

# Show the counter and dater form
show_dater_equation(pn5, false, false)
@assert ans == true
show_counter_equation(pn5, false, false)
@assert ans == true

# If the Petri net is an event graph, you can generate the graph the (max,+)
# adjacency sparse matrices (that could be used with SimpleGraphs.jl).
N,T = to_graph(pn4)

# Sparse to full (max,+) matrices
full(N)
full(T)

# If the Petri net is an event graph, you can generate the implicit dynamic
# linear (max,+) system.
S = to_syslin(pn5)
show(S.D)
show(S.A)
show(S.B)
show(S.C)
show(S.x0)
1 change: 1 addition & 0 deletions tests/HowardTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ TEST(TestHoward, TestPetriNetSemiSimple)
ASSERT_STREQ(loadFromFile(net,"../data/examples/Howard2.json").c_str(), "");
ASSERT_EQ(net.type(), TypeOfNet::TimedEventGraph);
ASSERT_EQ(net.isEmpty(), false);
ASSERT_EQ(isEventGraph(net), true);
res = findCriticalCycle(net);
ASSERT_EQ(res.success, true);
ASSERT_EQ(res.cycles, 1u);
Expand Down

0 comments on commit 8d7ee33

Please sign in to comment.