link rel="shortcut icon" type="image/x-icon" href="/flexman/favicon.ico"
Adaptive scheduling and optimization Library.
This project is a generalized simulation and optimization library designed to solve continuous-time scheduling problems by finding the best sequence of modes to achieve a target state. Users can define their systems’ state evolution freely, track resources, and optimize performance using techniques like exhaustive searches, heuristic evaluations, and Particle Swarm Optimization (PSO). The library is modular and adaptable to various applications, with the industrial tapping machine serving as an example.
is_strictly_better_than and
is_probably_better_than to suit your problem domain.This library is header-only and does not require installation. All dependencies are automatically fetched using the provided CMake configuration.
Clone the repository:
git clone https://github.com/username/repository.git
cd repository
Build the project using CMake:
mkdir build && cd build
cmake ..
make
The provided example focuses on simulating and optimizing the operations of an industrial tapping machine. The simulation incorporates:
Set up the state, input, and resource types for the simulation:
namespace tapping {
/// @brief Number of system states.
constexpr std::size_t n_states = 3;
/// @brief Number of system inputs.
constexpr std::size_t n_input = 2;
/// @brief Number of system outputs.
constexpr std::size_t n_output = 3;
/// @brief State vector type.
using state_t = fsmlib::Vector<double, n_states>;
/// @brief Input vector type.
using input_t = fsmlib::Vector<double, n_input>;
/// @brief Result type containing a state and resource data.
using result_t = flexman::core::Result<state_t, resources_t>;
/// @brief Solution type containing a state and resource data.
using solution_t = flexman::core::Solution<state_t, resources_t>;
/// @brief Pareto front type for storing optimal solutions.
using pareto_front_t = flexman::core::ParetoFront<state_t, resources_t>;
/// @brief Discrete state-space system representation.
using discrete_system_t = fsmlib::control::DiscreteStateSpace<double, n_states, n_input, n_output>;
/// @brief Continuous state-space system representation.
using continous_system_t = fsmlib::control::StateSpace<double, n_states, n_input, n_output>;
/// @brief Mode representation for discrete systems.
using discrete_mode_t = flexman::core::Mode<discrete_system_t, input_t>;
/// @brief Mode representation for continuous systems.
using continous_mode_t = flexman::core::Mode<continous_system_t, input_t>;
} // namespace tapping
The resources_t struct allows users to define multiple metrics for optimization. In this example, it tracks energy and time, but it can include other dimensions depending on the use case. These metrics are essential for guiding the search, as they define what makes one solution better than another.
/// @brief Tapping resources.
struct resources_t {
double energy; ///< Energy spent tapping.
double time; ///< Time spent tapping.
};
Use a builder_t class to define continuous and discrete modes. For instance,
in the tapping example we create a continuous-time mode this way:
/// @brief Creates a continuous-time state space model.
inline auto make_continuous_mode(flexman::ModeId id) const noexcept
{
continous_mode_t mode;
mode.id = id;
mode.input = { ... };
mode.system.A = { ... };
mode.system.B = { ... };
mode.system.C = { ... };
mode.system.D = { ... };
return mode;
}
and if the library you are using for defining the mode allows to discretize it
you can also add a make_discrete_mode function, like we have done with the
tapping example:
/// @brief Creates a discrete-time mode.
inline auto make_discrete_mode(flexman::ModeId id, double sample_time) const noexcept
{
// First, create the continuous-time mode.
continous_mode_t ct_mode = this->make_continuous_mode(id);
// Create the discrete-time mode
discrete_mode_t mode;
// Initialize the discrete-time mode.
mode.id = id;
mode.input = ct_mode.input;
mode.system = fsmlib::control::c2d(ct_mode.system, sample_time);
// Return the discretized mode.
return mode;
}
Then you can build the modes, ready to be used by the search function:
builder_t builder;
auto continuous_mode = builder.make_continuous_mode(1);
auto discrete_mode = builder.make_discrete_mode(1, 0.01);
Leverage discrete_search_t and continuous_search_t to simulate the system:
tapping::discrete_search_t discrete_manager;
tapping::continuous_search_t continuous_manager;
discrete_manager.updated_solution(solution, discrete_mode);
continuous_manager.updated_solution(solution, continuous_mode);
The library supports exhaustive searches, which explore all possible solutions, and heuristic searches, which approximate the best solutions efficiently. Users must define their logic for comparing solutions by implementing two key functions:
is_strictly_better_than: Determines if one solution is definitively better
than another.is_probably_better_than: Provides a heuristic comparison for approximate
searches.Refine results using Particle Swarm Optimization:
// Assuming `result` contains initial solutions
auto optimized_result = pso::optimize(result);
Compile the code:
mkdir build && cd build
cmake ..
make
Call the executable with --help to see all the settings we can set:
./flexman_tapping --help
This is an example of actual simulation:
./flexman_tapping --run 0 --mode 0 --algorithm 0 --pso --output output.json --plot
This command runs:
--run 0)--mode 0)--algorithm 0)--pso)output.json (--output output.json)--plot)View the results, including Pareto fronts and optimized solutions.
The library is modular and can be adapted for various systems by defining custom:
We welcome contributions! Please submit issues and pull requests on GitHub to help improve the project.
Special thanks to Michael Balszun for contributions and inspiration.
This project is licensed under the BSD-2 License.