class ibool
The ibool class is AADC’s active boolean type for tracking logical operations in computational graphs that involve conditional logic.
Overview
ibool is defined in aadc/ibool.h and serves as a drop-in replacement for native bool when boolean expressions depend on kernel inputs and need to be tracked in the valuation graph. Unlike traditional automatic differentiation tools, AADC can record and execute conditional branches, making it suitable for complex mathematical models with conditional logic.
assert(sizeof(bool) == sizeof(ibool)); // Always trueWhen to Use ibool vs bool
Understanding when to use ibool versus native bool is crucial for correct AADC implementation:
| Scenario | Use Type | Reason |
|---|---|---|
| Stochastic conditions | ibool |
Condition depends on kernel inputs and varies between evaluations |
| Static conditions | bool |
Condition is constant or doesn’t depend on kernel inputs |
| Diff-only conditions | bool |
Condition only depends on markAsDiff() variables (not stochastic) |
Stochastic vs Static Conditions
Stochastic conditions are boolean expressions that depend on kernel “random” inputs (markAsInput() or markAsInputNoDiff()). These conditions can evaluate differently for different input values and must be tracked:
// Stochastic - depends on kernel input
idouble temperature(25.0);
AADCArgument temp_arg = temperature.markAsInput();
idouble threshold(30.0);
ibool is_above_threshold = temperature > threshold; // Must use iboolStatic conditions don’t depend on kernel inputs and can use native bool:
// Static - doesn't depend on kernel inputs
bool use_iterative_method = true; // Algorithm choice
int max_iterations = 1000; // Fixed parameter
bool converged = (i == max_iterations); // Loop controlImportant: Variables marked with markAsDiff() (diff-only inputs) do not make conditions stochastic since they don’t vary between kernel evaluations.
Internal State Flags
Similar to idouble, ibool objects maintain internal flag IsRandom to indicate if they depend on stochastic inputs. This flag is managed automatically by AADC Core and propagates through operations.
Recording Phase Behavior
| Context | Condition Type | Approach | Notes |
|---|---|---|---|
| Outside recording | Any | Native bool or ibool |
No tracking needed |
| Inside recording | Static | Native bool or ibool |
Condition doesn’t vary |
| Inside recording | Stochastic | Must use ibool + iIf() |
Traditional if() not supported |
Functional Form: iIf()
For stochastic conditions during recording, use the functional form iIf() instead of traditional if() statements:
// Traditional if-statement (only for static conditions)
if (static_condition) {
result = value_a;
} else {
result = value_b;
}
// Functional form (required for stochastic conditions)
result = iIf(stochastic_condition, value_a, value_b);iIf() Overloads
iIf() supports various type combinations:
idouble iIf(const ibool& cond, const idouble& a, const idouble& b);
idouble iIf(const ibool& cond, const double a, const double b);
idouble iIf(const ibool& cond, const idouble& a, const double b);
idouble iIf(const ibool& cond, const double a, const idouble& b);
ibool iIf(const ibool& cond, const ibool& a, const ibool& b);Boolean Operations
Comparison Operations
All comparison operations between idouble values return ibool:
idouble x(100.0), y(110.0);
ibool less_than = (x < y); // Returns ibool
ibool greater_equal = (x >= y); // Returns ibool
ibool equal = (x == y); // Returns iboolLogical Operations
Standard logical operations are available in the aadcBoolOps namespace:
using namespace aadcBoolOps;
ibool a = (x > 0.0);
ibool b = (y < 100.0);
ibool result = a && b; // Logical AND
ibool result2 = a || b; // Logical OR
ibool not_a = !a; // Logical NOTShort-Circuit Evaluation Warning
Important: Unlike native C++ boolean operators, overloaded && and || operators for ibool do not provide short-circuit evaluation. Both operands are always evaluated:
// In native C++, computeExpensive() is not called if x == 0
if (x != 0 && computeExpensive(x) > threshold) { ... }
// With ibool, computeExpensive() is ALWAYS called
using namespace aadcBoolOps;
if (x != 0 && computeExpensive(x) > threshold) { ... } // computeExpensive called even if x == 0Use aadcBoolOps only when it’s safe to evaluate all operands.
Type Conversion Control
Explicit Conversion Prevention
By default, ibool prevents implicit conversion to native bool:
ibool condition = (x > y);
if (condition) { ... } // Compile error - no implicit conversionControlled Implicit Conversion
When AADC_ALLOW_TO_PASSIVE_BOOL is defined, implicit conversion is allowed with runtime checking:
#define AADC_ALLOW_TO_PASSIVE_BOOL
ibool condition = (x > y);
if (condition) { ... } // Allowed - conversion is monitoredEach conversion is checked, and stochastic conversions are logged and can trigger custom handlers for debugging.
Utility Functions
Mathematical Functions
namespace std {
idouble max(const idouble& a, const idouble& b);
idouble min(const idouble& a, const idouble& b);
idouble abs(const idouble& x);
idouble fabs(const idouble& x);
idouble copysign(const idouble& a, const idouble& b);
// Boolean testing functions
ibool isnan(const idouble& x);
ibool isfinite(const idouble& x);
}Conditional Assignment
void condAssign(idouble& target, const ibool& condition, const idouble& value);
// Equivalent to: target = iIf(condition, value, target);Legacy Code Integration
For large existing codebases using global double to idouble replacement integration strategy:
Enable controlled conversion:
#define AADC_ALLOW_TO_PASSIVE_BOOLUse Active-to-Passive reporting to identify where conversions occur
Modify only truly stochastic conditions to use
iIf()andcondAssign(). Prefer min/max/abs functions for simple comparisons.Use debugging tools to catch unintended conversions during development
Best Practices
- Start with explicit conversion prevention during development of a new project to catch all conditional logic
- Use the functional form
iIf()for all stochastic conditions - Enable Active-to-Passive reporting to monitor conversions in production
- Test thoroughly when enabling implicit conversion in legacy code
- Be cautious with short-circuit evaluation when using
aadcBoolOpsnamespace
Example: Piecewise Function with Conditional Logic
// Mathematical function with conditional behavior
idouble x(2.5); // Input variable
idouble threshold(3.0); // Boundary parameter
idouble slope_low(2.0); // Parameters for different regions
idouble slope_high(0.5);
// Mark inputs for differentiation
auto x_arg = x.markAsInput();
auto threshold_arg = threshold.markAsDiff(); // Diff-only
auto slope_low_arg = slope_low.markAsInput();
auto slope_high_arg = slope_high.markAsInput();
// Stochastic condition - x value determines behavior
ibool in_low_region = x < threshold;
// Static condition - algorithm choice
bool use_quadratic_form = false; // Configuration parameter
// Piecewise function using functional form
idouble result = iIf(in_low_region,
slope_low * x, // Linear in low region
slope_high * (x - threshold) + slope_low * threshold); // Linear in high region
// Static branching for algorithm choice (outside or before recording)
if (use_quadratic_form) {
// Alternative quadratic formulation
idouble quadratic_term = x * x * 0.1;
result = result + quadratic_term;
}See Also
- idouble Class Reference - For the underlying floating-point active type
- Branches and Conditional Logic - For advanced branching techniques