Skip to content

Commit 314a129

Browse files
committed
fix: Corrige manejo de casos borde y mejora robustez en algoritmos
- En tpl_bipartite.H se agrega verificación para grafo vacío en matching - En Knapsack.H se corrige verificación de overflow para tipos sin límites - En tpl_mincost.H se simplifica declaración de cola de prioridad - En Tests/bipartite_test.cc se actualizan pruebas para reflejar nuevo comportamiento - En stat_utils.H se reemplaza std::map por DynMapTree para consistencia - En scripts/ci_policy_checks.rb se añade soporte para archivos copiados - En ah-chronos-utils.H se corrige formato y comentarios - En scripts/test_ci_policy_checks.rb se añaden pruebas para literales raw strings - En Matrix_Chain.H se clarifica documentación de validación
1 parent 3f72e94 commit 314a129

12 files changed

Lines changed: 115 additions & 1365 deletions

AUDIT_ADVERSARIAL_BRANCH.md

Lines changed: 0 additions & 468 deletions
This file was deleted.

Knapsack.H

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,17 @@ template <typename V, std::integral W>
342342
{
343343
const size_t take = std::min(k, rem);
344344

345-
const V maxV = std::numeric_limits<V>::max();
346-
if ((wi == 0 or take <= C / wi) and
347-
(items[i].value == V{0} or static_cast<V>(take) <= maxV / items[i].value))
345+
bool value_ok;
346+
if constexpr (std::numeric_limits<V>::is_specialized)
347+
{
348+
const V maxV = std::numeric_limits<V>::max();
349+
value_ok = (items[i].value == V{0} or
350+
static_cast<V>(take) <= maxV / items[i].value);
351+
}
352+
else
353+
value_ok = true;
354+
355+
if ((wi == 0 or take <= C / wi) and value_ok)
348356
{
349357
expanded.append(Knapsack_Item<W, V>{static_cast<W>(wi * take),
350358
static_cast<V>(take) * items[i].value});

Matrix_Chain.H

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ inline void build_parens(const Array<Array<size_t>> &s, size_t i, size_t j, std:
119119
* representation of the parenthesization, and the split table.
120120
*
121121
* @throws ah_domain_error if `dims` has fewer than 2 entries.
122-
* @throws ah_domain_error if any dimension is zero or negative.
122+
* @throws ah_domain_error if any `dims` dimension is zero.
123123
* @throws ah_runtime_error if the cost calculation overflows `size_t`.
124124
*
125125
* @note **Complexity**: Time O(n^3), Space O(n^2), where n is the number of matrices.
@@ -185,8 +185,8 @@ inline void build_parens(const Array<Array<size_t>> &s, size_t i, size_t j, std:
185185

186186
/** @brief Compute only the minimum multiplication cost (value only).
187187
*
188-
* A convenience version that only returns the minimum number of scalar
189-
* multiplications required, without reconstruction.
188+
* A convenience version that delegates to `matrix_chain_order` and returns
189+
* the `min_multiplications` value computed there.
190190
*
191191
* @param[in] dims Array of matrix dimensions (@f$n+1@f$entries for@f$n@f$matrices).
192192
* @return The minimum number of scalar multiplications.

Tests/bipartite_test.cc

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -280,14 +280,14 @@ TEST(Bipartite, DISABLED_EmptyGraph)
280280
EXPECT_TRUE(r.is_empty());
281281
}
282282

283-
// This test documents the current (buggy) behavior
284283
TEST(Bipartite, EmptyGraphThrowsRangeError)
285284
{
286285
Graph g;
287286
DynDlist<Graph::Node *> l, r;
288287

289-
// BUG: Empty graph throws range_error instead of succeeding with empty partitions
290-
EXPECT_THROW(compute_bipartite<Graph>(g, l, r), std::range_error);
288+
EXPECT_NO_THROW(compute_bipartite<Graph>(g, l, r));
289+
EXPECT_TRUE(l.is_empty());
290+
EXPECT_TRUE(r.is_empty());
291291
}
292292

293293
TEST(Bipartite, SingleNode)
@@ -540,18 +540,15 @@ TEST(ComputeBipartiteClass, ThrowsOnNonBipartite)
540540
// ============================================================================
541541
// Maximum Matching Tests
542542
// ============================================================================
543-
// KNOWN BUG: The maximum matching algorithm is not returning correct results.
544-
// The flow network-based algorithm returns 0 matches for all cases.
545-
// Empty graph throws range_error (consistent with compute_bipartite behavior)
546543
TEST(MaximumMatching, EmptyGraphThrowsRangeError)
547544
{
548545
Graph g;
549546

550547
DynDlist<Graph::Arc *> matching;
551548

552-
EXPECT_THROW(
553-
compute_maximum_cardinality_bipartite_matching<Graph>(g, matching),
554-
std::range_error);
549+
EXPECT_NO_THROW(
550+
compute_maximum_cardinality_bipartite_matching<Graph>(g, matching));
551+
EXPECT_TRUE(matching.is_empty());
555552
}
556553

557554
TEST(MaximumMatching, SingleEdge)

ah-chronos-utils.H

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
SOFTWARE.
2929
*/
3030

31-
3231
/** @file ah-chronos-utils.H
3332
* @brief Time duration conversion utilities.
3433
*
@@ -43,57 +42,56 @@
4342
#ifndef AH_CHRONOS_UTILS_H
4443
#define AH_CHRONOS_UTILS_H
4544

46-
# include <string>
47-
# include <chrono>
48-
# include <format>
45+
#include <string>
46+
#include <chrono>
47+
#include <format>
4948

50-
namespace Aleph
51-
{
49+
namespace Aleph {
5250
// given a duration, return the number of seconds
53-
inline double duration_to_seconds(const std::chrono::duration<double> & d)
51+
inline double duration_to_seconds(const std::chrono::duration<double> &d)
5452
{
5553
return d.count();
5654
}
5755

5856
// given a duration, return the number of milliseconds
59-
inline double duration_to_milliseconds(const std::chrono::duration<double> & d)
57+
inline double duration_to_milliseconds(const std::chrono::duration<double> &d)
6058
{
6159
return std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
6260
}
6361

6462
// given a duration, return the number of microseconds
65-
inline double duration_to_microseconds(const std::chrono::duration<double> & d)
63+
inline double duration_to_microseconds(const std::chrono::duration<double> &d)
6664
{
6765
return std::chrono::duration_cast<std::chrono::microseconds>(d).count();
6866
}
6967

7068
// given a duration, return the number of nanoseconds
71-
inline double duration_to_nanoseconds(const std::chrono::duration<double> & d)
69+
inline double duration_to_nanoseconds(const std::chrono::duration<double> &d)
7270
{
7371
return std::chrono::duration_cast<std::chrono::nanoseconds>(d).count();
7472
}
7573

7674
// given a duration, return the number of minutes
77-
inline double duration_to_minutes(const std::chrono::duration<double> & d)
75+
inline double duration_to_minutes(const std::chrono::duration<double> &d)
7876
{
7977
return std::chrono::duration_cast<std::chrono::minutes>(d).count();
8078
}
8179

8280
// given a duration, return the number of hours
83-
inline double duration_to_hours(const std::chrono::duration<double> & d)
81+
inline double duration_to_hours(const std::chrono::duration<double> &d)
8482
{
8583
return std::chrono::duration_cast<std::chrono::hours>(d).count();
8684
}
8785

8886
// given a duration, return the number of days
89-
inline double duration_to_days(const std::chrono::duration<double> & d)
87+
inline double duration_to_days(const std::chrono::duration<double> &d)
9088
{
9189
return std::chrono::duration_cast<std::chrono::days>(d).count();
9290
}
9391

9492
// given a duration, return a string with the proper units
95-
// acording to the magnitude of the duration
96-
inline std::string duration_to_string(const auto & d)
93+
// according to the magnitude of the duration
94+
inline std::string duration_to_string(const auto &d)
9795
{
9896
if (d < std::chrono::seconds(1))
9997
return std::format("{} ms", duration_to_milliseconds(d));
@@ -107,6 +105,6 @@ inline std::string duration_to_string(const auto & d)
107105

108106
return std::format("{} days", duration_to_days(d));
109107
}
110-
}
108+
} // namespace Aleph
111109

112-
#endif //AH_CHRONOS_UTILS_H
110+
#endif // AH_CHRONOS_UTILS_H

0 commit comments

Comments
 (0)