Skip to content

Commit 415c9f5

Browse files
committed
Add concepts for actors
1 parent 64ddf38 commit 415c9f5

File tree

13 files changed

+407
-188
lines changed

13 files changed

+407
-188
lines changed

core/include/detray/propagator/actor_chain.hpp

+20-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "detray/definitions/containers.hpp"
1212
#include "detray/definitions/detail/qualifiers.hpp"
1313
#include "detray/propagator/base_actor.hpp"
14+
#include "detray/propagator/composite_actor.hpp"
1415
#include "detray/utils/tuple.hpp"
1516
#include "detray/utils/tuple_helpers.hpp"
1617

@@ -28,7 +29,7 @@ namespace detray {
2829
/// The states of the actors need to be passed to the chain in an external tuple
2930
///
3031
/// @tparam actors_t the types of the actors in the chain.
31-
template <typename... actors_t>
32+
template <concepts::actor... actors_t>
3233
class actor_chain {
3334

3435
public:
@@ -62,7 +63,8 @@ class actor_chain {
6263
DETRAY_HOST_DEVICE
6364
static constexpr auto make_default_actor_states() {
6465
// Only possible if each state is default initializable
65-
if constexpr (std::default_initializable<state_tuple>) {
66+
if constexpr ((std::default_initializable<typename actors_t::state> &&
67+
...)) {
6668
return state_tuple{};
6769
} else {
6870
return std::nullopt;
@@ -82,7 +84,7 @@ class actor_chain {
8284
/// @param actr the actor (might be a composite actor)
8385
/// @param states states of all actors (only bare actors)
8486
/// @param p_state the state of the propagator (stepper and navigator)
85-
template <typename actor_t, typename actor_states_t,
87+
template <concepts::actor actor_t, typename actor_states_t,
8688
typename propagator_state_t>
8789
DETRAY_HOST_DEVICE inline void run(const actor_t &actr,
8890
actor_states_t &states,
@@ -133,7 +135,7 @@ class actor_chain<> {
133135
using state_ref_tuple = dtuple<>;
134136

135137
/// Empty states replaces a real actor states container
136-
struct state {};
138+
using state = state_tuple;
137139

138140
/// Call to actors does nothing.
139141
///
@@ -145,11 +147,25 @@ class actor_chain<> {
145147
/*Do nothing*/
146148
}
147149

150+
/// @returns the actor list
151+
DETRAY_HOST_DEVICE constexpr const actor_tuple &actors() const {
152+
return m_actors;
153+
}
154+
155+
/// @returns an empty state
156+
DETRAY_HOST_DEVICE
157+
static consteval state_tuple make_default_actor_states() {
158+
return dtuple<>{};
159+
}
160+
148161
/// @returns an empty state
149162
DETRAY_HOST_DEVICE static constexpr state_ref_tuple setup_actor_states(
150163
const state_tuple &) {
151164
return {};
152165
}
166+
167+
private:
168+
[[no_unique_address]] actor_tuple m_actors = {};
153169
};
154170

155171
} // namespace detray

core/include/detray/propagator/actors.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
#include "detray/propagator/actors/parameter_resetter.hpp"
1414
#include "detray/propagator/actors/parameter_transporter.hpp"
1515
#include "detray/propagator/actors/pointwise_material_interactor.hpp"
16+
#include "detray/propagator/concepts.hpp"

core/include/detray/propagator/base_actor.hpp

-170
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,8 @@
77

88
#pragma once
99

10-
// Propagate include(s)
11-
#include "detray/definitions/containers.hpp"
12-
#include "detray/definitions/detail/qualifiers.hpp"
13-
#include "detray/utils/tuple_helpers.hpp"
14-
1510
// System include(s)
16-
#include <concepts>
1711
#include <type_traits>
18-
#include <utility>
1912

2013
namespace detray {
2114

@@ -28,167 +21,4 @@ struct actor {
2821
struct state {};
2922
};
3023

31-
namespace detail {
32-
/// Extrac the tuple of actor states from an actor type
33-
/// @{
34-
// Simple actor: No observers
35-
template <typename actor_t>
36-
struct get_state_tuple {
37-
private:
38-
using state_t = typename actor_t::state;
39-
40-
// Remove empty default state of base actor type from tuple
41-
using principal = std::conditional_t<std::same_as<state_t, actor::state>,
42-
dtuple<>, dtuple<state_t>>;
43-
using principal_ref =
44-
std::conditional_t<std::same_as<state_t, actor::state>, dtuple<>,
45-
dtuple<state_t &>>;
46-
47-
public:
48-
using type = principal;
49-
using ref_type = principal_ref;
50-
};
51-
52-
// Composite actor: Has observers
53-
template <typename actor_t>
54-
requires(!std::same_as<typename std::remove_cvref_t<actor_t>::observer_states,
55-
void>) struct get_state_tuple<actor_t> {
56-
private:
57-
using principal_actor_t = typename actor_t::actor_type;
58-
59-
using principal = typename get_state_tuple<principal_actor_t>::type;
60-
using principal_ref = typename get_state_tuple<principal_actor_t>::ref_type;
61-
62-
using observers = typename actor_t::observer_states;
63-
using observer_refs = typename actor_t::observer_state_refs;
64-
65-
public:
66-
using type = detail::tuple_cat_t<principal, observers>;
67-
using ref_type = detail::tuple_cat_t<principal_ref, observer_refs>;
68-
};
69-
70-
/// Tuple of state types
71-
template <typename actor_t>
72-
using state_tuple_t = get_state_tuple<actor_t>::type;
73-
74-
/// Tuple of references
75-
template <typename actor_t>
76-
using state_ref_tuple_t = get_state_tuple<actor_t>::ref_type;
77-
/// @}
78-
79-
} // namespace detail
80-
81-
/// Composition of actors
82-
///
83-
/// The composition represents an actor together with its observers. In
84-
/// addition to running its own implementation, it notifies its observing actors
85-
///
86-
/// @tparam principal_actor_t the actor the compositions implements itself.
87-
/// @tparam observers a pack of observing actors that get called on the updated
88-
/// actor state of the compositions actor implementation.
89-
template <class principal_actor_t = actor, typename... observers>
90-
class composite_actor final : public principal_actor_t {
91-
92-
public:
93-
/// Tag whether this is a composite type (hides the def in the actor)
94-
struct is_comp_actor : public std::true_type {};
95-
96-
/// The composite is an actor in itself.
97-
using actor_type = principal_actor_t;
98-
using state = typename actor_type::state;
99-
100-
/// Tuple of states of observing actors
101-
using observer_states =
102-
detail::tuple_cat_t<detail::state_tuple_t<observers>...>;
103-
using observer_state_refs =
104-
detail::tuple_cat_t<detail::state_ref_tuple_t<observers>...>;
105-
106-
/// Call to the implementation of the actor (the actor possibly being an
107-
/// observer itself)
108-
///
109-
/// First runs its own implementation, then passes the updated state to its
110-
/// observers.
111-
///
112-
/// @param states the states of all actors in the chain
113-
/// @param p_state the state of the propagator (stepper and navigator)
114-
/// @param subject_state the state of the actor this actor observes. Uses
115-
/// a dummy type if this is not an observing actor.
116-
template <typename actor_states_t, typename propagator_state_t,
117-
typename subj_state_t = typename actor::state>
118-
DETRAY_HOST_DEVICE void operator()(
119-
actor_states_t &states, propagator_state_t &p_state,
120-
subj_state_t &&subject_state = {}) const {
121-
122-
// State of the primary actor that is implement by this composite actor
123-
auto &actor_state = detail::get<typename actor_type::state &>(states);
124-
125-
// Do your own work ...
126-
// Two cases: This is a simple actor or observing actor (pass on its
127-
// subject's state)
128-
if constexpr (std::is_same_v<subj_state_t, typename actor::state>) {
129-
actor_type::operator()(actor_state, p_state);
130-
} else {
131-
actor_type::operator()(actor_state, p_state,
132-
std::forward<subj_state_t>(subject_state));
133-
}
134-
135-
// ... then run the observers on the updated state
136-
notify(m_observers, states, actor_state, p_state,
137-
std::make_index_sequence<sizeof...(observers)>{});
138-
}
139-
140-
private:
141-
/// Notifies the observing actors for composite and simple actor case.
142-
///
143-
/// @param observer one of the observers
144-
/// @param states the states of all actors in the chain
145-
/// @param actor_state the state of this compositions actor as the subject
146-
/// to all of its observers
147-
/// @param p_state the state of the propagator (stepper and navigator)
148-
template <typename observer_t, typename actor_states_t,
149-
typename actor_impl_state_t, typename propagator_state_t>
150-
DETRAY_HOST_DEVICE inline void notify(const observer_t &observer,
151-
actor_states_t &states,
152-
actor_impl_state_t &actor_state,
153-
propagator_state_t &p_state) const {
154-
// Two cases: observer is a simple actor or a composite actor
155-
if constexpr (!typename observer_t::is_comp_actor()) {
156-
// No actor state defined (empty)
157-
if constexpr (std::same_as<typename observer_t::state,
158-
detray::actor::state>) {
159-
observer(actor_state, p_state);
160-
} else {
161-
observer(detail::get<typename observer_t::state &>(states),
162-
actor_state, p_state);
163-
}
164-
} else {
165-
observer(states, actor_state, p_state);
166-
}
167-
}
168-
169-
/// Resolve the observer notification.
170-
///
171-
/// Unrolls the observer types and runs the notification for each of them.
172-
///
173-
/// @param observer_list all observers of the actor
174-
/// @param states the states of all actors in the chain
175-
/// @param actor_state the state of this compositions actor as the subject
176-
/// to all of its observers
177-
/// @param p_state the state of the propagator (stepper and navigator)
178-
template <std::size_t... indices, typename actor_states_t,
179-
typename actor_impl_state_t, typename propagator_state_t>
180-
DETRAY_HOST_DEVICE inline void notify(
181-
const dtuple<observers...> &observer_list, actor_states_t &states,
182-
actor_impl_state_t &actor_state, propagator_state_t &p_state,
183-
std::index_sequence<indices...> /*ids*/) const {
184-
185-
(notify(detail::get<indices>(observer_list), states, actor_state,
186-
p_state),
187-
...);
188-
}
189-
190-
/// Keep the observers (might be composites again)
191-
[[no_unique_address]] dtuple<observers...> m_observers = {};
192-
};
193-
19424
} // namespace detray
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/** Detray library, part of the ACTS project (R&D line)
2+
*
3+
* (c) 2022-2025 CERN for the benefit of the ACTS project
4+
*
5+
* Mozilla Public License Version 2.0
6+
*/
7+
8+
#pragma once
9+
10+
// Propagate include(s)
11+
#include "detray/definitions/containers.hpp"
12+
#include "detray/definitions/detail/qualifiers.hpp"
13+
#include "detray/propagator/base_actor.hpp"
14+
#include "detray/propagator/concepts.hpp"
15+
#include "detray/propagator/detail/type_traits.hpp"
16+
#include "detray/utils/tuple_helpers.hpp"
17+
18+
// System include(s)
19+
#include <concepts>
20+
#include <type_traits>
21+
#include <utility>
22+
23+
namespace detray {
24+
/// Composition of actors
25+
///
26+
/// The composition represents an actor together with its observers. In
27+
/// addition to running its own implementation, it notifies its observing actors
28+
///
29+
/// @tparam principal_actor_t the actor the compositions implements itself.
30+
/// @tparam observers a pack of observing actors that get called on the updated
31+
/// actor state of the compositions actor implementation.
32+
template <concepts::actor principal_actor_t = actor,
33+
concepts::actor... observers>
34+
class composite_actor final : public principal_actor_t {
35+
36+
public:
37+
/// Tag whether this is a composite type (hides the def in the actor)
38+
struct is_comp_actor : public std::true_type {};
39+
40+
/// The composite is an actor in itself.
41+
using actor_type = principal_actor_t;
42+
using state = typename actor_type::state;
43+
44+
/// Tuple of states of observing actors
45+
using observer_states =
46+
detail::tuple_cat_t<detail::state_tuple_t<observers>...>;
47+
using observer_state_refs =
48+
detail::tuple_cat_t<detail::state_ref_tuple_t<observers>...>;
49+
50+
/// Call to the implementation of the actor (the actor possibly being an
51+
/// observer itself)
52+
///
53+
/// First runs its own implementation, then passes the updated state to its
54+
/// observers.
55+
///
56+
/// @param states the states of all actors in the chain
57+
/// @param p_state the state of the propagator (stepper and navigator)
58+
/// @param subject_state the state of the actor this actor observes. Uses
59+
/// a dummy type if this is not an observing actor.
60+
template <typename actor_states_t, typename propagator_state_t,
61+
typename subj_state_t = typename actor::state>
62+
DETRAY_HOST_DEVICE void operator()(
63+
actor_states_t &states, propagator_state_t &p_state,
64+
subj_state_t &&subject_state = {}) const {
65+
66+
// State of the primary actor that is implement by this composite actor
67+
auto &actor_state = detail::get<typename actor_type::state &>(states);
68+
69+
// Do your own work ...
70+
// Two cases: This is a simple actor or observing actor (pass on its
71+
// subject's state)
72+
if constexpr (std::same_as<subj_state_t, typename actor::state>) {
73+
actor_type::operator()(actor_state, p_state);
74+
} else {
75+
actor_type::operator()(actor_state, p_state,
76+
std::forward<subj_state_t>(subject_state));
77+
}
78+
79+
// ... then run the observers on the updated state
80+
notify(m_observers, states, actor_state, p_state,
81+
std::make_index_sequence<sizeof...(observers)>{});
82+
}
83+
84+
private:
85+
/// Notifies the observing actors for composite and simple actor case.
86+
///
87+
/// @param observer one of the observers
88+
/// @param states the states of all actors in the chain
89+
/// @param actor_state the state of this compositions actor as the subject
90+
/// to all of its observers
91+
/// @param p_state the state of the propagator (stepper and navigator)
92+
template <concepts::actor observer_t, typename actor_states_t,
93+
typename propagator_state_t>
94+
DETRAY_HOST_DEVICE inline void notify(const observer_t &observer,
95+
actor_states_t &states,
96+
state &actor_state,
97+
propagator_state_t &p_state) const {
98+
// Two cases: observer is a simple actor or a composite actor
99+
if constexpr (!concepts::composite_actor<observer_t>) {
100+
// No actor state defined (empty)
101+
if constexpr (std::same_as<typename observer_t::state,
102+
detray::actor::state>) {
103+
observer(actor_state, p_state);
104+
} else {
105+
observer(detail::get<typename observer_t::state &>(states),
106+
actor_state, p_state);
107+
}
108+
} else {
109+
observer(states, actor_state, p_state);
110+
}
111+
}
112+
113+
/// Resolve the observer notification.
114+
///
115+
/// Unrolls the observer types and runs the notification for each of them.
116+
///
117+
/// @param observer_list all observers of the actor
118+
/// @param states the states of all actors in the chain
119+
/// @param actor_state the state of this compositions actor as the subject
120+
/// to all of its observers
121+
/// @param p_state the state of the propagator (stepper and navigator)
122+
template <std::size_t... indices, typename actor_states_t,
123+
typename propagator_state_t>
124+
DETRAY_HOST_DEVICE inline void notify(
125+
const dtuple<observers...> &observer_list, actor_states_t &states,
126+
state &actor_state, propagator_state_t &p_state,
127+
std::index_sequence<indices...> /*ids*/) const {
128+
129+
(notify(detail::get<indices>(observer_list), states, actor_state,
130+
p_state),
131+
...);
132+
}
133+
134+
/// Keep the observers (might be composites again)
135+
[[no_unique_address]] dtuple<observers...> m_observers = {};
136+
};
137+
138+
} // namespace detray

0 commit comments

Comments
 (0)