#ifndef INCLUDED_C_CPM_H #define INCLUDED_C_CPM_H #ifndef INCLUDED_C_EDGEWEIGHTEDDIGRAPH_H #include #endif /*INCLUDED_C_EDGEWEIGHTEDDIGRAPH_H*/ #ifndef INCLUDED_C_ACYCLICLP_H #include #endif /*INCLUDED_C_ACYCLICLP_H*/ #ifndef INCLUDED_C_VERTEXIDLIST_H #include #endif /*INCLUDED_C_VERTEXIDLIST_H*/ /* ------------------------------------------------------------------------------------------------------------------ */ /* */ typedef struct { c_AcyclicLP_t lp_engine; /* Inner longest-path engine */ c_size_t num_tasks; /* Raw number of user tasks */ c_size_t source_node; /* Virtual source node index */ c_size_t sink_node; /* Virtual sink node index */ c_size_t V; /* Total inner nodes count (2 * num_tasks + 2) */ c_Allocator_t allocator; /* Deep copy of the user-provided allocator */ } c_CPM_t; /** * @brief Initializes and executes the Critical Path Method scheduler. * @param task_durations Array of doubles containing durations for each task (size = num_tasks) * @param allocator Explicit allocator context used to configure internal tracking state memory */ c_err_t c_CPM_Init(c_CPM_t* self, c_size_t num_tasks, const double* task_durations, c_Allocator_t* allocator); /** * @brief Releases internal tracking buffers safely. */ void c_CPM_Destroy(c_CPM_t* self); /** * @brief Adds a dependency constraint indicating that 'prereq_task' must finish before 'target_task' can start. */ c_err_t c_CPM_AddDependency(c_CPM_t* self, c_EdgeWeightedDigraph_t* working_graph, c_size_t prereq_task, c_size_t target_task); /** * @brief Finalizes the calculation after all dependencies are added. */ c_err_t c_CPM_Calculate(c_CPM_t* self, c_EdgeWeightedDigraph_t* working_graph); /** * @brief Returns the minimum total project duration. */ C_STATIC_FORCE_INLINE double c_CPM_GetProjectDuration(c_CPM_t* self) { if (!self) return 0.0; return c_AcyclicLP_DistTo(&self->lp_engine, self->sink_node); } /** * @brief Returns the Early Start (ES) time for a given task. */ C_STATIC_FORCE_INLINE double c_CPM_GetEarlyStart(c_CPM_t* self, c_size_t task_id) { if (!self || task_id >= self->num_tasks) return 0.0; return c_AcyclicLP_DistTo(&self->lp_engine, task_id); } /** * @brief Extracts the sequence of global edge IDs that form the critical path. */ c_err_t c_CPM_GetCriticalPath(c_CPM_t* self, c_VertexIdList_t* out_critical_edges); #endif /*INCLUDED_C_CPM_H*/