diff --git a/CMakeLists.txt b/CMakeLists.txt index c233e31..29401d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ add_project_modules_with_tests(SOURCES TEST_SOURCES Search Sort String + Context ) #foreach (item ${SOURCES}) diff --git a/Context/c_FFT.c b/Context/c_FFT.c new file mode 100644 index 0000000..0e2b52e --- /dev/null +++ b/Context/c_FFT.c @@ -0,0 +1,105 @@ +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* Private Helper: Verifies if an integer is a strict power of 2 */ +C_STATIC_FORCE_INLINE +bool c_FFT_IsPowerOfTwo(c_size_t n) { + return (n > 0) && ((n & (n - 1)) == 0); +} + +/* Private Helper: In-place O(N) bit-reversal permutation shuffling */ +static void c_FFT_BitReversePermutation(c_Complex_t* signal, c_size_t n) { + c_size_t j = 0; + for (c_size_t i = 0; i < n; ++i) { + if (i < j) { + c_Complex_t temp = signal[i]; + signal[i] = signal[j]; + signal[j] = temp; + } + c_size_t bit = n >> 1; + while (j & bit) { + j ^= bit; + bit >>= 1; + } + j ^= bit; + } +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +c_err_t c_FFT_Init(c_FFT_t* self, c_size_t N, c_Allocator_t* allocator) { + if (!self || N == 0) return C_ERR_PARAM; + if (!c_FFT_IsPowerOfTwo(N)) return C_ERR_PARAM; /* Algorithm constraint check */ + + self->allocator = allocator ? *allocator : c_DefaultAllocator; + self->N = N; + + return C_SUCCESS; +} + +void c_FFT_Destroy(c_FFT_t* self) { + if (!self) return; + self->N = 0; +} + +/* ================================================================================================================== */ +/* Non-Recursive In-Place FFT Engine paired with your formal c_Complex_t APIs */ + +c_err_t c_FFT_Execute(const c_FFT_t* self, c_Complex_t* signal, c_bool_t inverse) { + if (!self || !signal) return C_ERR_PARAM; + if (self->N == 0) return C_SUCCESS; + + c_size_t n = self->N; + + /* 1. Execute the in-place bit-reversal shuffle up-front */ + c_FFT_BitReversePermutation(signal, n); + + /* 2. Bottom-up butterfly merging loops */ + /* len represents the current sub-problem size (2, 4, 8, ..., N) */ + for (c_size_t len = 2; len <= n; len <<= 1) { + double angle = 2.0 * M_PI / (double)len * (inverse ? 1.0 : -1.0); + + /* Calculate principal twiddle factor step block using your standard constructor factory hook */ + c_Complex_t wlen = c_Complex_Make(cos(angle), sin(angle)); + + for (c_size_t i = 0; i < n; i += len) { + c_Complex_t w = c_Complex_Make(1.0, 0.0); + c_size_t half_len = len >> 1; + + for (c_size_t j = 0; j < half_len; ++j) { + c_size_t idx_u = i + j; + c_size_t idx_v = i + j + half_len; + + c_Complex_t u = signal[idx_u]; + + /* High-performance complex multiplication butterfly product segment: t = v * w */ + c_Complex_t t = c_Complex_Mul(signal[idx_v], w); + + /* Core butterfly update mappings leveraging clean addition and subtraction interfaces */ + signal[idx_u] = c_Complex_Add(u, t); + signal[idx_v] = c_Complex_Sub(u, t); + + /* Advance intermediate rotation matrix step: w = w * wlen */ + w = c_Complex_Mul(w, wlen); + } + } + } + + /* 3. Scale Inverse IFFT vectors uniformly by 1/N using scalar operations helper */ + if (inverse) { + double scale = 1.0 / (double)n; + for (c_size_t i = 0; i < n; ++i) { + signal[i] = c_Complex_MulScalar(signal[i], scale); + } + } + + return C_SUCCESS; +} + diff --git a/Context/c_FFT.h b/Context/c_FFT.h new file mode 100644 index 0000000..535eab6 --- /dev/null +++ b/Context/c_FFT.h @@ -0,0 +1,48 @@ +#ifndef INCLUDED_C_FFT_H +#define INCLUDED_C_FFT_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + +#ifndef INCLUDED_C_COMPLEX_H +#include +#endif /*INCLUDED_C_COMPLEX_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +typedef struct { + c_size_t N; /* Length of the signal buffer (Must be a power of 2) */ + c_Allocator_t allocator; /* Deep copy of the user-provided allocator */ +} c_FFT_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +/** + * @brief Initializes the FFT calculation engine context. + * @param N Total number of signal sample points (Must be a strict power of 2) + */ +c_err_t c_FFT_Init(c_FFT_t* self, c_size_t N, c_Allocator_t* allocator); + +/** + * @brief Releases internal tracking engine allocations. + */ +void c_FFT_Destroy(c_FFT_t* self); + +/** + * @brief Non-recursively executes the forward or inverse FFT in-place. + * @param signal Array of complex samples of size self->N (Modified in-place) + * @param inverse Set to C_TRUE for Inverse FFT (IFFT), C_FALSE for Forward FFT + */ +c_err_t c_FFT_Execute(const c_FFT_t* self, c_Complex_t* signal, c_bool_t inverse); + + +#endif /*INCLUDED_C_FFT_H*/ diff --git a/Context/c_FFT.t.c b/Context/c_FFT.t.c new file mode 100644 index 0000000..985bc1e --- /dev/null +++ b/Context/c_FFT.t.c @@ -0,0 +1,45 @@ +#include "c_Test.h" +#include "c_FFT.h" + +TEST_CASE(test_fft_forward_and_inverse_precision) { + c_size_t N = 8; + c_FFT_t fft; + c_err_t err = c_FFT_Init(&fft, N, NULL); + ASSERT_INT_EQ(C_SUCCESS, err); + + /* Allocate and initialize a test complex input signal (e.g., a simple square pulse) */ + c_Complex_t signal[8] = { + {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, + {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0} + }; + + /* Backup the original signal vector values for accuracy verification tests later */ + double original_real[8]; + for (c_size_t i = 0; i < N; ++i) original_real[i] = signal[i].real; + + /* 1. Execute Forward Fourier Transformation */ + err = c_FFT_Execute(&fft, signal, C_FALSE); + ASSERT_INT_EQ(C_SUCCESS, err); + + /* The DC component (index 0) must equal the sum of all elements = 4.0 */ + ASSERT_DOUBLE_EQ_MSG(4.0, signal[0].real, "Forward FFT DC component calculation wrong"); + + /* 2. Execute Inverse Fourier Transformation to reconstruct the original signal */ + err = c_FFT_Execute(&fft, signal, C_TRUE); + ASSERT_INT_EQ(C_SUCCESS, err); + + /* Confirm that the output matches the original input wave precisely within allowed errors */ + for (c_size_t i = 0; i < N; ++i) { + ASSERT_DOUBLE_EQ_MSG(original_real[i], signal[i].real, "FFT-IFFT signal precision mismatch"); + ASSERT_DOUBLE_EQ_MSG(0.0, signal[i].imag, "Residual imaginary noise caught in reconstructed signal"); + } + + c_FFT_Destroy(&fft); +} + +int main(void) { + TEST_START(FastFourierTransform_Engine_Suite); + RUN_TEST(test_fft_forward_and_inverse_precision); + TEST_REPORT(); + RETURN_TEST_STATUS; +} diff --git a/Context/c_FlowEdge.c b/Context/c_FlowEdge.c new file mode 100644 index 0000000..6bf0659 --- /dev/null +++ b/Context/c_FlowEdge.c @@ -0,0 +1 @@ +#include diff --git a/Context/c_FlowEdge.h b/Context/c_FlowEdge.h new file mode 100644 index 0000000..f71cff9 --- /dev/null +++ b/Context/c_FlowEdge.h @@ -0,0 +1,24 @@ +#ifndef INCLUDED_C_FLOWEDGE_H +#define INCLUDED_C_FLOWEDGE_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + c_size_t from; /* Source vertex of the directed edge */ + c_size_t to; /* Destination vertex of the directed edge */ + double capacity; /* Total flow capacity threshold limit */ + double flow; /* Current active allocated flow amount */ +} c_FlowEdge_t; + +/** + * @brief Resolves the companion residual edge ID using a high-speed bitwise XOR short-circuit + */ +#define C_FLOW_EDGE_REVERSE(edge_id) ((edge_id) ^ 1) + +#endif /*INCLUDED_C_FLOWEDGE_H*/ diff --git a/Context/c_FlowNetwork.c b/Context/c_FlowNetwork.c new file mode 100644 index 0000000..d4ef578 --- /dev/null +++ b/Context/c_FlowNetwork.c @@ -0,0 +1,65 @@ +#include + + +/* ================================================================================================================== */ +/* Flow Network Infrastructure API Primitives */ + +c_err_t c_FlowNetwork_Init(c_FlowNetwork_t* self, c_size_t V, c_Allocator_t* alloc) { + if (!self) return C_ERR_PARAM; + self->allocator = alloc ? *alloc : c_DefaultAllocator; + self->V = V; + self->E = 0; + self->adj_list = NULL; + self->edges_pool = NULL; + self->edges_cap = 0; + + if (V > 0) { + self->adj_list = (c_UIntArray_t*)c_Allocator_Calloc(&self->allocator, V, sizeof(c_UIntArray_t)); + if (!self->adj_list) return C_ERR_NOMEM; + for (c_size_t i = 0; i < V; ++i) c_UIntArray_Init(&self->adj_list[i], 0, alloc); + } + return C_SUCCESS; +} + +void c_FlowNetwork_Destroy(c_FlowNetwork_t* self) { + if (!self) return; + if (self->adj_list) { + for (c_size_t i = 0; i < self->V; ++i) c_UIntArray_Destroy(&self->adj_list[i]); + c_Allocator_Free(&self->allocator, self->adj_list); + } + if (self->edges_pool) c_Allocator_Free(&self->allocator, self->edges_pool); + memset(self, 0, sizeof(*self)); +} + +c_err_t c_FlowNetwork_AddEdge(c_FlowNetwork_t* self, c_size_t from, c_size_t to, double capacity) { + if (!self || from >= self->V || to >= self->V || capacity < 0.0) return C_ERR_PARAM; + + /* Expand pool space to accommodate BOTH the forward edge and its residual twin (+2 entries) */ + if (self->E + 2 > self->edges_cap) { + c_size_t old_cap = self->edges_cap; + c_size_t new_cap = old_cap == 0 ? 8 : old_cap * 2; + c_FlowEdge_t* new_pool = (c_FlowEdge_t*)c_Allocator_Realloc( + &self->allocator, self->edges_pool, old_cap * sizeof(c_FlowEdge_t), new_cap * sizeof(c_FlowEdge_t) + ); + if (!new_pool) return C_ERR_NOMEM; + self->edges_pool = new_pool; + self->edges_cap = new_cap; + } + + c_size_t forward_id = self->E; + c_size_t residual_id = self->E + 1; + + /* Push edge pairs sequentially to lock bitwise XOR reverse mapping property */ + self->edges_pool[forward_id] = (c_FlowEdge_t){ .from = from, .to = to, .capacity = capacity, .flow = 0.0 }; + self->edges_pool[residual_id] = (c_FlowEdge_t){ .from = to, .to = from, .capacity = 0.0, .flow = 0.0 }; + + /* Wire edge pointer handles into both adjacency lists to track backward residual flow channels */ + c_err_t err = c_UIntArray_Append(&self->adj_list[from], (c_uint_t)forward_id); + if (err != C_SUCCESS) return err; + err = c_UIntArray_Append(&self->adj_list[to], (c_uint_t)residual_id); + if (err != C_SUCCESS) return err; + + self->E += 2; + return C_SUCCESS; +} + diff --git a/Context/c_FlowNetwork.h b/Context/c_FlowNetwork.h new file mode 100644 index 0000000..6269ee8 --- /dev/null +++ b/Context/c_FlowNetwork.h @@ -0,0 +1,39 @@ +#ifndef INCLUDED_C_FLOWNETWORK_H +#define INCLUDED_C_FLOWNETWORK_H + +#ifndef INCLUDED_C_FLOWEDGE_H +#include +#endif /*INCLUDED_C_FLOWEDGE_H*/ + +#ifndef INCLUDED_C_UINTARRAY_H +#include +#endif /*INCLUDED_C_UINTARRAY_H*/ + + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + c_size_t V; /* Total number of vertices */ + c_size_t E; /* Total number of directed flow edges (including residual twins) */ + c_UIntArray_t* adj_list; /* Array of lists storing global edge_ids exiting/entering each vertex */ + c_FlowEdge_t* edges_pool; /* Global contiguous array pool housing raw flow edge objects */ + c_size_t edges_cap; /* Allocated edge pool tracking capacity boundary */ + c_Allocator_t allocator; /* Embedded custom allocator structure instance */ +} c_FlowNetwork_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_FlowNetwork_Init(c_FlowNetwork_t* self, c_size_t V, c_Allocator_t* alloc); +void c_FlowNetwork_Destroy(c_FlowNetwork_t* self); +c_err_t c_FlowNetwork_AddEdge(c_FlowNetwork_t* self, c_size_t from, c_size_t to, double capacity); + +#endif /*INCLUDED_C_FLOWNETWORK_H*/ diff --git a/Context/c_FordFulkerson.c b/Context/c_FordFulkerson.c new file mode 100644 index 0000000..bfe4f1a --- /dev/null +++ b/Context/c_FordFulkerson.c @@ -0,0 +1,96 @@ +#include +#include + +#define FF_SENTINEL ((c_size_t)-1) +#define C_MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* ================================================================================================================== */ +/* Edmonds-Karp Augmenting Path Finder Helper (Stack-Safe BFS Queue Engine) */ + +static c_bool_t c_FordFulkerson_HasAugmentingPath(c_FordFulkerson_t* self, c_FlowNetwork_t* graph, c_size_t s, c_size_t t, c_size_t* queue) { + for (c_size_t v = 0; v < self->V; ++v) { + self->marked[v] = C_FALSE; + self->edge_to[v] = FF_SENTINEL; + } + + c_size_t head = 0, tail = 0; + self->marked[s] = C_TRUE; + queue[tail++] = s; + + while (head < tail) { + c_size_t v = queue[head++]; + c_UIntArray_t* adj = &graph->adj_list[v]; + c_size_t size = (c_size_t)c_UIntArray_GetSize(adj); + + for (c_size_t i = 0; i < size; ++i) { + c_uint_t generic_id = 0; + if (c_UIntArray_Get(adj, i, &generic_id) != C_SUCCESS) continue; + + c_size_t edge_id = (c_size_t)generic_id; + c_FlowEdge_t* edge = &graph->edges_pool[edge_id]; + c_size_t w = edge->to; + + /* Check residual capacity: forward edge capacity constraint or backward flow return buffer */ + double residual_capacity = edge->capacity - edge->flow; + if (residual_capacity > 0.0 && !self->marked[w]) { + self->edge_to[w] = edge_id; + self->marked[w] = C_TRUE; + queue[tail++] = w; + if (w == t) return C_TRUE; /* Short-circuit early if sink is reached */ + } + } + } + return self->marked[t]; +} + +/* ================================================================================================================== */ +/* Core Ford-Fulkerson Solver Engine */ + +c_err_t c_FordFulkerson_Init(c_FordFulkerson_t* self, c_FlowNetwork_t* graph, c_size_t s, c_size_t t, c_Allocator_t* allocator) { + if (!self || !graph || s >= graph->V || t >= graph->V || s == t) return C_ERR_PARAM; + + self->allocator = allocator ? *allocator : c_DefaultAllocator; + self->V = graph->V; + self->max_flow = 0.0; + + self->edge_to = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t)); + self->marked = (c_bool_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_bool_t)); + c_size_t* queue = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t)); + + if (!self->edge_to || !self->marked || !queue) { + if (queue) c_Allocator_Free(&self->allocator, queue); + c_FordFulkerson_Destroy(self); + return C_ERR_NOMEM; + } + + /* Process Edmonds-Karp loop increments dynamically */ + while (c_FordFulkerson_HasAugmentingPath(self, graph, s, t, queue)) { + + /* Step 1: Compute bottleneck bottleneck structural threshold along path tree link entries */ + double bottle = DBL_MAX; + for (c_size_t v = t; v != s; v = graph->edges_pool[self->edge_to[v]].from) { + c_FlowEdge_t* edge = &graph->edges_pool[self->edge_to[v]]; + bottle = C_MIN(bottle, edge->capacity - edge->flow); + } + + /* Step 2: Push bottleneck flow changes into forward and backward matching residual twins */ + for (c_size_t v = t; v != s; v = graph->edges_pool[self->edge_to[v]].from) { + c_size_t forward_id = self->edge_to[v]; + c_size_t residual_id = C_FLOW_EDGE_REVERSE(forward_id); + + graph->edges_pool[forward_id].flow += bottle; + graph->edges_pool[residual_id].flow -= bottle; /* Reverse path flow compensation */ + } + self->max_flow += bottle; + } + + c_Allocator_Free(&self->allocator, queue); + return C_SUCCESS; +} + +void c_FordFulkerson_Destroy(c_FordFulkerson_t* self) { + if (!self) return; + if (self->edge_to) c_Allocator_Free(&self->allocator, self->edge_to); + if (self->marked) c_Allocator_Free(&self->allocator, self->marked); + memset(self, 0, sizeof(*self)); +} diff --git a/Context/c_FordFulkerson.h b/Context/c_FordFulkerson.h new file mode 100644 index 0000000..73e42ec --- /dev/null +++ b/Context/c_FordFulkerson.h @@ -0,0 +1,51 @@ +#ifndef INCLUDED_C_FORDFULKERSON_H +#define INCLUDED_C_FORDFULKERSON_H + +#ifndef INCLUDED_C_FLOWNETWORK_H +#include +#endif /*INCLUDED_C_FLOWNETWORK_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + c_size_t* edge_to; /* edge_to[v] = global edge_id on augmenting path to vertex v */ + c_bool_t* marked; /* marked[v] = C_TRUE if an augmenting path can reach vertex v */ + double max_flow; /* Cumulative total maximum value computed */ + c_size_t V; /* Vertex limit count cached locally */ + c_Allocator_t allocator; /* Deep copy of the user-provided allocator */ +} c_FordFulkerson_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +/** + * @brief Computes the maximum flow and minimum cut from source 's' to sink 't'. + * @param allocator Explicit allocator context used to configure temporary path discovery buffers + */ +c_err_t c_FordFulkerson_Init(c_FordFulkerson_t* self, c_FlowNetwork_t* graph, c_size_t s, c_size_t t, c_Allocator_t* allocator); + +/** + * @brief Releases internal tracking buffers safely. + */ +void c_FordFulkerson_Destroy(c_FordFulkerson_t* self); + +/** + * @brief Returns the total maximum flow value computed. + */ +C_STATIC_FORCE_INLINE +double c_FordFulkerson_GetValue(const c_FordFulkerson_t* self) { + return self ? self->max_flow : 0.0; +} + +/** + * @brief Determines if vertex 'v' is on the source side of the minimum cut. + */ +C_STATIC_FORCE_INLINE +c_bool_t c_FordFulkerson_InCut(const c_FordFulkerson_t* self, c_size_t v) { + if (!self || v >= self->V || !self->marked) return C_FALSE; + return self->marked[v]; +} + +#endif /*INCLUDED_C_FORDFULKERSON_H*/ diff --git a/Context/c_FordFulkerson.t.c b/Context/c_FordFulkerson.t.c new file mode 100644 index 0000000..e1658b0 --- /dev/null +++ b/Context/c_FordFulkerson.t.c @@ -0,0 +1,42 @@ +#include "c_Test.h" +#include "c_FordFulkerson.h" + +TEST_CASE(test_ford_fulkerson_max_flow_and_min_cut) { + c_FlowNetwork_t network; + c_err_t err = c_FlowNetwork_Init(&network, 4, NULL); + ASSERT_INT_EQ(C_SUCCESS, err); + + /* Construct a standard flow distribution diamond network layout: + * 0 -> 1 (Capacity: 2.0) + * 0 -> 2 (Capacity: 3.0) + * 1 -> 3 (Capacity: 1.0) + * 2 -> 3 (Capacity: 4.0) + * 1 -> 2 (Capacity: 2.0, Cross diagonal distribution balance) + */ + c_FlowNetwork_AddEdge(&network, 0, 1, 2.0); + c_FlowNetwork_AddEdge(&network, 0, 2, 3.0); + c_FlowNetwork_AddEdge(&network, 1, 3, 1.0); + c_FlowNetwork_AddEdge(&network, 2, 3, 4.0); + c_FlowNetwork_AddEdge(&network, 1, 2, 2.0); + + c_FordFulkerson_t ff; + err = c_FordFulkerson_Init(&ff, &network, 0, 3, &network.allocator); + ASSERT_INT_EQ(C_SUCCESS, err); + + /* Max-flow bottleneck saturation calculation verification must equal exactly 4.0 */ + ASSERT_DOUBLE_EQ_MSG(4.0, c_FordFulkerson_GetValue(&ff), "Maximum flow metric validation failed"); + + /* Min-Cut Verification: check side assignments */ + ASSERT_TRUE(c_FordFulkerson_InCut(&ff, 0)); /* Source must be on source side of cut */ + ASSERT_FALSE(c_FordFulkerson_InCut(&ff, 3)); /* Sink must be on sink side of cut */ + + c_FordFulkerson_Destroy(&ff); + c_FlowNetwork_Destroy(&network); +} + +int main(void) { + TEST_START(FordFulkerson_MaxFlow_Suite); + RUN_TEST(test_ford_fulkerson_max_flow_and_min_cut); + TEST_REPORT(); + RETURN_TEST_STATUS; +} diff --git a/Foundation/c_Complex.c b/Foundation/c_Complex.c new file mode 100644 index 0000000..62237bf --- /dev/null +++ b/Foundation/c_Complex.c @@ -0,0 +1 @@ +#include "c_Complex.h" diff --git a/Foundation/c_Complex.h b/Foundation/c_Complex.h new file mode 100644 index 0000000..1add524 --- /dev/null +++ b/Foundation/c_Complex.h @@ -0,0 +1,208 @@ +#ifndef INCLUDED_C_COMPLEX_H +#define INCLUDED_C_COMPLEX_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + +#ifndef INCLUDED_MATH_H +#define INCLUDED_MATH_H +#include +#endif /*INCLUDED_MATH_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + double real; + double imag; +} c_Complex_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Make(double real, double imag) { + c_Complex_t c; + c.real = real; + c.imag = imag; + return c; +} + +/** + * @brief 从极坐标创建复数 (Polar to Rectangular) + * @param r 幅值 (Magnitude) + * @param theta 幅角 (Phase angle in radians) + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_FromPolar(double r, double theta) { + c_Complex_t c; + c.real = r * cos(theta); + c.imag = r * sin(theta); + return c; +} + +/** + * @brief Adds two complex numbers: res = a + b + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Add(c_Complex_t a, c_Complex_t b) { + c_Complex_t res; + res.real = a.real + b.real; + res.imag = a.imag + b.imag; + return res; +} + +/** + * @brief Subtracts two complex numbers: res = a - b + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Sub(c_Complex_t a, c_Complex_t b) { + c_Complex_t res; + res.real = a.real - b.real; + res.imag = a.imag - b.imag; + return res; +} + +/** + * @brief Multiplies two complex numbers: res = a * b + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Mul(c_Complex_t a, c_Complex_t b) { + c_Complex_t res; + res.real = a.real * b.real - a.imag * b.imag; + res.imag = a.real * b.imag + a.imag * b.real; + return res; +} + +/** + * @brief 复数除法: res = a / b + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Div(c_Complex_t a, c_Complex_t b) { + double denom = b.real * b.real + b.imag * b.imag; + if (denom == 0.0) { + return c_Complex_Make(0.0, 0.0); /* 健壮性防线:防止除以 0 导致崩溃 */ + } + return c_Complex_Make( + (a.real * b.real + a.imag * b.imag) / denom, + (a.imag * b.real - a.real * b.imag) / denom + ); +} + +/** + * @brief Computes the complex conjugate: res = real - i*imag + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Conjugate(c_Complex_t c) { + c_Complex_t res; + res.real = c.real; + res.imag = -c.imag; + return res; +} + +/** + * @brief 计算复数的相反数 (Negate): res = -real - i*imag + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Negate(c_Complex_t c) { + return c_Complex_Make(-c.real, -c.imag); +} + +/** + * @brief 计算复数的模长的平方 (Magnitude Squared / Norm) + * @note 避免了开方操作,适合用于比对大小以提升性能 + */ +C_STATIC_FORCE_INLINE double c_Complex_Norm(c_Complex_t c) { + return c.real * c.real + c.imag * c.imag; +} + +/** + * @brief 计算复数的模长 (Magnitude / Absolute Value) + */ +C_STATIC_FORCE_INLINE double c_Complex_Abs(c_Complex_t c) { + return sqrt(c.real * c.real + c.imag * c.imag); +} + +/** + * @brief 计算复数的幅角 (Phase Angle / Argument) + * @return 返回介于 -PI 到 PI 之间的弧度值 + */ +C_STATIC_FORCE_INLINE double c_Complex_Arg(c_Complex_t c) { + return atan2(c.imag, c.real); +} + +/* ================================================================================================================== */ +/* 标量混合运算接口 (Scalar & Complex Operations) */ + +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_AddScalar(c_Complex_t c, double s) { + return c_Complex_Make(c.real + s, c.imag); +} + +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_SubScalar(c_Complex_t c, double s) { + return c_Complex_Make(c.real - s, c.imag); +} + +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_MulScalar(c_Complex_t c, double s) { + return c_Complex_Make(c.real * s, c.imag * s); +} + +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_DivScalar(c_Complex_t c, double s) { + if (s == 0.0) return c_Complex_Make(0.0, 0.0); + return c_Complex_Make(c.real / s, c.imag / s); +} + +/* ================================================================================================================== */ +/* 超越函数与幂运算接口 (Transcendental & Power Functions) */ + +/** + * @brief 复数的指数函数: e^c + * @note e^(x+iy) = e^x * (cos(y) + i*sin(y)) + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Exp(c_Complex_t c) { + double exp_x = exp(c.real); + return c_Complex_Make(exp_x * cos(c.imag), exp_x * sin(c.imag)); +} + +/** + * @brief 复数的自然对数函数: ln(c) + * @note ln(c) = ln(|c|) + i*arg(c) + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Log(c_Complex_t c) { + return c_Complex_Make(log(c_Complex_Abs(c)), c_Complex_Arg(c)); +} + +/** + * @brief 复数的幂运算: base^exp + * @note a^b = exp(b * log(a)) + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Pow(c_Complex_t base, c_Complex_t exponent) { + if (base.real == 0.0 && base.imag == 0.0) return c_Complex_Make(0.0, 0.0); + return c_Complex_Exp(c_Complex_Mul(exponent, c_Complex_Log(base))); +} + +/** + * @brief 复数的实数幂运算: base^p (p 为实数标量) + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_PowScalar(c_Complex_t base, double p) { + if (base.real == 0.0 && base.imag == 0.0) return c_Complex_Make(0.0, 0.0); + double r = pow(c_Complex_Abs(base), p); + double theta = c_Complex_Arg(base) * p; + return c_Complex_FromPolar(r, theta); +} + +/** + * @brief 复数开平方根: sqrt(c) + */ +C_STATIC_FORCE_INLINE c_Complex_t c_Complex_Sqrt(c_Complex_t c) { + double r = c_Complex_Abs(c); + double real_part = sqrt((r + c.real) / 2.0); + double imag_part = sqrt((r - c.real) / 2.0); + if (c.imag < 0.0) imag_part = -imag_part; + return c_Complex_Make(real_part, imag_part); +} + +/* ================================================================================================================== */ +/* 比较运算 (Comparison Interfaces) */ + +/** + * @brief 判断两个复数是否在允许的误差内相等 + */ +C_STATIC_FORCE_INLINE bool c_Complex_Equals(c_Complex_t a, c_Complex_t b, double epsilon) { + return (fabs(a.real - b.real) <= epsilon) && (fabs(a.imag - b.imag) <= epsilon); +} + +#endif /*INCLUDED_C_COMPLEX_H*/ diff --git a/Foundation/c_Complex.t.c b/Foundation/c_Complex.t.c new file mode 100644 index 0000000..d09bb5f --- /dev/null +++ b/Foundation/c_Complex.t.c @@ -0,0 +1,35 @@ +#include "c_Test.h" +#include "c_Complex.h" + +TEST_CASE(test_complex_extended_apis) { + c_Complex_t a = c_Complex_Make(3.0, 4.0); + c_Complex_t b = c_Complex_Make(1.0, -2.0); + + /* 1. 测试属性提取 */ + ASSERT_DOUBLE_EQ_MSG(25.0, c_Complex_Norm(a), "Norm 运算错误"); + ASSERT_DOUBLE_EQ_MSG(5.0, c_Complex_Abs(a), "Abs 运算错误"); + + /* 2. 测试除法 */ + c_Complex_t res_div = c_Complex_Div(a, b); + /* (3+4i)/(1-2i) = (3+4i)(1+2i)/5 = (-5+10i)/5 = -1 + 2i */ + ASSERT_DOUBLE_EQ_MSG(-1.0, res_div.real, "复数除法实部错误"); + ASSERT_DOUBLE_EQ_MSG(2.0, res_div.imag, "复数除法虚部错误"); + + /* 3. 测试极坐标转换与欧拉公式基础验证 */ + /* e^(i*PI) = -1 + 0i */ + c_Complex_t polar = c_Complex_FromPolar(1.0, 3.141592653589793); + ASSERT_TRUE(c_Complex_Equals(polar, c_Complex_Make(-1.0, 0.0), 1e-6)); + + /* 4. 测试标量混合运算 */ + c_Complex_t res_scalar = c_Complex_MulScalar(b, 3.0); + ASSERT_DOUBLE_EQ_MSG(3.0, res_scalar.real, "标量乘法实部错误"); + ASSERT_DOUBLE_EQ_MSG(-6.0, res_scalar.imag, "标量乘法虚部错误"); +} + +int main(void) { + TEST_START(TestSuite); + RUN_TEST(test_complex_extended_apis); + + TEST_REPORT(); + return (g_test_registry.failed_count > 0 ? 1 : 0); +} diff --git a/Foundation/c_HardwareConcurrency.c b/Foundation/c_HardwareConcurrency.c new file mode 100644 index 0000000..ec93097 --- /dev/null +++ b/Foundation/c_HardwareConcurrency.c @@ -0,0 +1,49 @@ +#include + +/* ================================================================================================================== */ +/* Cross-Platform OS Handle Interceptions */ + +#if defined(_WIN32) || defined(_WIN64) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include +#elif defined(__linux__) || defined(__ANDROID__) || defined(__hpux) || defined(_AIX) + #include +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + #include + #include + #include +#endif + +c_size_t c_HardwareConcurrency(void) { +#if defined(_WIN32) || defined(_WIN64) + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + return (c_size_t)sys_info.dwNumberOfProcessors > 0 ? (c_size_t)sys_info.dwNumberOfProcessors : 1; + +#elif defined(__linux__) || defined(__ANDROID__) || defined(__hpux) || defined(_AIX) + long cores = sysconf(_SC_NPROCESSORS_ONLN); + return (cores > 0) ? (c_size_t)cores : 1; + +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + int mib[2]; + mib[0] = CTL_HW; + mib[1] = HW_NCPU; /* Fallback baseline key token selector */ + +#ifdef HW_AVAILCPU + mib[1] = HW_AVAILCPU; /* Preferred choice: online/available logical cores count query */ +#endif + + int num_cores = 0; + size_t len = sizeof(num_cores); + if (sysctl(mib, 2, &num_cores, &len, NULL, 0) == 0 && num_cores > 0) { + return (c_size_t)num_cores; + } + return 1; + +#else + /* Safe fallback anchor primitive for completely unknown or specialized bare-metal setups */ + return 1; +#endif +} diff --git a/Foundation/c_HardwareConcurrency.h b/Foundation/c_HardwareConcurrency.h new file mode 100644 index 0000000..0d6e0be --- /dev/null +++ b/Foundation/c_HardwareConcurrency.h @@ -0,0 +1,15 @@ +#ifndef INCLUDED_C_HARDWARECONCURRENCY_H +#define INCLUDED_C_HARDWARECONCURRENCY_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_size_t c_HardwareConcurrency(void); + + +#endif /*INCLUDED_C_HARDWARECONCURRENCY_H*/ diff --git a/Foundation/c_HardwareConcurrency.t.c b/Foundation/c_HardwareConcurrency.t.c new file mode 100644 index 0000000..359e067 --- /dev/null +++ b/Foundation/c_HardwareConcurrency.t.c @@ -0,0 +1,23 @@ +#include "c_Test.h" +#include "c_HardwareConcurrency.h" + +TEST_CASE(test_hardware_concurrency_detection) { + c_size_t cores = c_HardwareConcurrency(); + + /* Log numerical results using your system's architectural type-spec macro format */ + printf(" " COLOR_CYAN "[INFO] Detected System Hardware Concurrency: %" C_PRId " logical core(s)" COLOR_RESET "\n", (uint64_t)cores); + + /* + * Invariants verification: + * Even on old or highly constrained embedded hardware setups, + * the system must feature at least 1 logical core running the test loop thread. + */ + ASSERT_TRUE(cores >= 1); +} + +int main(void) { + TEST_START(HardwareConcurrency_Detection_Suite); + RUN_TEST(test_hardware_concurrency_detection); + TEST_REPORT(); + RETURN_TEST_STATUS; +} diff --git a/String/c_LongestCommonSubstring.c b/String/c_LongestCommonSubstring.c new file mode 100644 index 0000000..6f42668 --- /dev/null +++ b/String/c_LongestCommonSubstring.c @@ -0,0 +1,90 @@ +#include + +c_err_t c_LongestCommonSubstring_Init(c_LongestCommonSubstring_t* self, const char* str_a, const char* str_b, c_Allocator_t* allocator) { + if (!self || !str_a || !str_b) return C_ERR_PARAM; + + self->allocator = allocator ? *allocator : c_DefaultAllocator; + self->max_len = 0; + self->start_idx_a = 0; + + c_size_t len_a = strlen(str_a); + c_size_t len_b = strlen(str_b); + + if (len_a == 0 || len_b == 0) return C_SUCCESS; /* Trivial empty evaluation check */ + + /* Optimize spatial footprint boundaries by always assigning the shorter collection as columns */ + const char* s_row = str_a; + const char* s_col = str_b; + c_size_t rows = len_a; + c_size_t cols = len_b; + c_bool_t swapped = C_FALSE; + + if (len_a < len_b) { + s_row = str_b; + s_col = str_a; + rows = len_b; + cols = len_a; + swapped = C_TRUE; + } + + /* 1. Allocate space-optimized 2-row rolling history track arrays */ + c_size_t* prev_row = (c_size_t*)c_Allocator_Calloc(&self->allocator, cols + 1, sizeof(c_size_t)); + c_size_t* curr_row = (c_size_t*)c_Allocator_Calloc(&self->allocator, cols + 1, sizeof(c_size_t)); + + if (!prev_row || !curr_row) { + if (prev_row) c_Allocator_Free(&self->allocator, prev_row); + if (curr_row) c_Allocator_Free(&self->allocator, curr_row); + return C_ERR_NOMEM; + } + + /* 2. Linear matrix sweep iteration pass */ + for (c_size_t i = 1; i <= rows; ++i) { + for (c_size_t j = 1; j <= cols; ++j) { + if (s_row[i - 1] == s_col[j - 1]) { + curr_row[j] = prev_row[j - 1] + 1; + + if (curr_row[j] > self->max_len) { + self->max_len = curr_row[j]; + + /* Map index location back relative to original String A coordinates */ + if (!swapped) { + self->start_idx_a = i - self->max_len; + } else { + self->start_idx_a = j - self->max_len; + } + } + } else { + curr_row[j] = 0; /* Continuous block break, reset sequence link */ + } + } + + /* 3. Shift the rolling window contents smoothly */ + memcpy(prev_row, curr_row, (cols + 1) * sizeof(c_size_t)); + } + + c_Allocator_Free(&self->allocator, prev_row); + c_Allocator_Free(&self->allocator, curr_row); + return C_SUCCESS; +} + +void c_LongestCommonSubstring_Destroy(c_LongestCommonSubstring_t* self) { + if (!self) return; + self->max_len = 0; + self->start_idx_a = 0; +} + +c_err_t c_LongestCommonSubstring_GetSubstring(const c_LongestCommonSubstring_t* self, const char* str_a, char* out_buffer, c_size_t buffer_cap) { + if (!self || !str_a || !out_buffer || buffer_cap == 0) return C_ERR_PARAM; + if (self->max_len == 0) { + out_buffer[0] = '\0'; + return C_SUCCESS; + } + + if (buffer_cap <= self->max_len) return C_ERR_OUTOFBOUND; + + /* Securely slice and copy matching token block segment */ + memcpy(out_buffer, str_a + self->start_idx_a, self->max_len); + out_buffer[self->max_len] = '\0'; /* Terminate string safely */ + + return C_SUCCESS; +} diff --git a/String/c_LongestCommonSubstring.h b/String/c_LongestCommonSubstring.h new file mode 100644 index 0000000..e6e3e73 --- /dev/null +++ b/String/c_LongestCommonSubstring.h @@ -0,0 +1,55 @@ +#ifndef INCLUDED_C_LONGESTCOMMONSUBSTRING_H +#define INCLUDED_C_LONGESTCOMMONSUBSTRING_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + c_size_t max_len; /* Length of the longest common substring found */ + c_size_t start_idx_a; /* Starting coordinate index inside String A sequence */ + c_Allocator_t allocator; /* Deep copy of the user-provided allocator */ +} c_LongestCommonSubstring_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +/** + * @brief Non-recursively computes the longest common substring between String A and String B. + * @param str_a Null-terminated or bound-verified character string A sequence + * @param str_b Null-terminated or bound-verified character string B sequence + * @param allocator Explicit allocator context used to configure temporary dynamic matrices + */ +c_err_t c_LongestCommonSubstring_Init(c_LongestCommonSubstring_t* self, const char* str_a, const char* str_b, c_Allocator_t* allocator); + +/** + * @brief Releases internal tracking structures safely (Trivial for rolling array layouts). + */ +void c_LongestCommonSubstring_Destroy(c_LongestCommonSubstring_t* self); + +/** + * @brief Returns the length of the discovered longest common substring. + */ +C_STATIC_FORCE_INLINE +c_size_t c_LongestCommonSubstring_GetLen(const c_LongestCommonSubstring_t* self) { + return self ? self->max_len : 0; +} + +/** + * @brief Extracts the resolved longest common substring payload back into a safe user buffer. + * @param out_buffer Presized destination character array to copy results into + * @param buffer_cap Maximum threshold size limit matching out_buffer allocation bounds + */ +c_err_t c_LongestCommonSubstring_GetSubstring(const c_LongestCommonSubstring_t* self, const char* str_a, char* out_buffer, c_size_t buffer_cap); + + +#endif /*INCLUDED_C_LONGESTCOMMONSUBSTRING_H*/ diff --git a/String/c_LongestCommonSubstring.t.c b/String/c_LongestCommonSubstring.t.c new file mode 100644 index 0000000..8217e28 --- /dev/null +++ b/String/c_LongestCommonSubstring.t.c @@ -0,0 +1,36 @@ +#include "c_Test.h" +#include "c_LongestCommonSubstring.h" + +TEST_CASE(test_longest_common_substring_resolution) { + /* Test inputs: + * Str A: "AABCCBDE" + * Str B: "XABCYBDE" + * Longest common continuous substring token should be "BDE" (Len: 3) or "ABC" (Len: 3). + * Our engine catches the first optimal one maximized or tracked sequentially. + */ + const char* a = "AABCCBDE"; + const char* b = "XABCYBDE"; + + c_LongestCommonSubstring_t lcs; + c_err_t err = c_LongestCommonSubstring_Init(&lcs, a, b, NULL); + ASSERT_INT_EQ(C_SUCCESS, err); + + c_size_t resolved_len = c_LongestCommonSubstring_GetLen(&lcs); + ASSERT_LL_EQ(3, resolved_len); + + char res_buf[16]; + err = c_LongestCommonSubstring_GetSubstring(&lcs, a, res_buf, sizeof(res_buf)); + ASSERT_INT_EQ(C_SUCCESS, err); + + /* Assert exact string equality token content matches */ + ASSERT_INT_EQ(0, strcmp("ABC", res_buf) == 0 || strcmp("BDE", res_buf) == 0 ? 0 : -1); + + c_LongestCommonSubstring_Destroy(&lcs); +} + +int main(void) { + TEST_START(LongestCommonSubstring_Verification_Suite); + RUN_TEST(test_longest_common_substring_resolution); + TEST_REPORT(); + RETURN_TEST_STATUS; +}