mirror of
https://github.com/TheAlgorithms/C-Plus-Plus.git
synced 2026-10-29 03:44:39 +08:00
* add conditional probability algorithm * test: assert error messages, add new line at end of file, improve docs and test descriptions * Apply self test comment Co-authored-by: realstealthninja <68815218+realstealthninja@users.noreply.github.com> * docs: use proper latex syntax probability/conditional_probability.cpp --------- Co-authored-by: realstealthninja <68815218+realstealthninja@users.noreply.github.com>
163 lines
5.5 KiB
C++
163 lines
5.5 KiB
C++
/**
|
|
* @file
|
|
* @brief [Conditional
|
|
* Probability](https://en.wikipedia.org/wiki/Conditional_probability)
|
|
* @details
|
|
* In probability theory, conditional probability is a measure of the
|
|
* probability of an event occurring, given that another event (by assumption,
|
|
* presumption, assertion, or evidence) is already known to have occurred.
|
|
*
|
|
* This particular method relies on event A occurring with some sort of
|
|
* relationship with another event B. In this situation, the event A can be
|
|
* analyzed by a conditional probability with respect to B.
|
|
*
|
|
* If the event of interest is A and the event B is known or assumed to have
|
|
* occurred, "the conditional probability of A given B", or "the probability of
|
|
* A under the condition B" is given by the formula:
|
|
*
|
|
* \f[P(A \mid B) = \frac{P(A \cap B)}{P(B)}\f]
|
|
* where: \f$P(B) > 0\f$.
|
|
*
|
|
*
|
|
* @author [SomrajBanik](https://github.com/SomrajBanik)
|
|
*/
|
|
|
|
#include <cassert> /// for assert
|
|
#include <cmath> /// for std::fabs
|
|
#include <iostream> /// for IO operations
|
|
#include <stdexcept> /// for std::invalid_argument
|
|
#include <string> /// for std::string
|
|
|
|
/**
|
|
* @namespace probability
|
|
* @brief Probability algorithms
|
|
*/
|
|
namespace probability {
|
|
/**
|
|
* @namespace conditional_probability
|
|
* @brief Functions for the [Conditional
|
|
* Probability](https://en.wikipedia.org/wiki/Conditional_probability) algorithm
|
|
* implementation
|
|
*/
|
|
namespace conditional_probability {
|
|
/**
|
|
* @brief Computes the conditional probability P(X|Y)
|
|
* @param p_intersect probability that both X and Y occur, in [0, P(Y)]
|
|
* @param p_given probability of the event that is given (Y), in (0, 1]
|
|
* @returns P(X|Y)
|
|
* @throws std::invalid_argument if p_given is not in (0, 1], or if
|
|
* p_intersect is not in [0, p_given]
|
|
*/
|
|
double conditional_compute(double p_intersect, double p_given) {
|
|
if (p_given <= 0.0 || p_given > 1.0) {
|
|
throw std::invalid_argument("The given probability must be in (0, 1].");
|
|
}
|
|
if (p_intersect < 0.0 || p_intersect > p_given) {
|
|
throw std::invalid_argument(
|
|
"P(intersection) must be between 0 and the given probability.");
|
|
}
|
|
|
|
return p_intersect / p_given;
|
|
}
|
|
|
|
} // namespace conditional_probability
|
|
} // namespace probability
|
|
|
|
/**
|
|
* @brief Self-test implementations
|
|
* @returns void
|
|
*/
|
|
static void test() {
|
|
using probability::conditional_probability::conditional_compute;
|
|
|
|
const double epsilon = 1e-9; /// tolerance for double comparison
|
|
|
|
std::cout << "\n\n";
|
|
std::cout << "Testing conditional probability...\n\n";
|
|
|
|
// Test case 1
|
|
std::cout << "Test 1: P(A and B) = 0.2, P(B) = 0.5\n";
|
|
std::cout << "Expected: P(A|B) = 0.4\n";
|
|
std::cout << "Result: P(A|B) = " << conditional_compute(0.2, 0.5) << "\n";
|
|
assert(std::fabs(conditional_compute(0.2, 0.5) - 0.4) < epsilon);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
// Test case 2
|
|
std::cout << "Test 2: A always happens when B does (B is a subset of A)\n";
|
|
std::cout << "Expected: P(A|B) = 1.0\n";
|
|
std::cout << "Result: P(A|B) = " << conditional_compute(0.5, 0.5) << "\n";
|
|
assert(std::fabs(conditional_compute(0.5, 0.5) - 1.0) < epsilon);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
// Test case 3
|
|
std::cout << "Test 3: A and B never happen together (mutually exclusive "
|
|
"events)\n";
|
|
std::cout << "Expected: P(A|B) = 0.0\n";
|
|
std::cout << "Result: P(A|B) = " << conditional_compute(0.0, 0.3) << "\n";
|
|
assert(std::fabs(conditional_compute(0.0, 0.3) - 0.0) < epsilon);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
// Test case 4
|
|
std::cout << "Test 4: One die, A = 'roll is 2', B = 'roll is even'\n";
|
|
std::cout << "Expected: P(A|B) = 1/3 or 0.333333(approx)\n";
|
|
std::cout << "Result: P(A|B) = "
|
|
<< conditional_compute(1.0 / 6.0, 1.0 / 2.0) << " (approx) "
|
|
<< "\n";
|
|
assert(std::fabs(conditional_compute(1.0 / 6.0, 1.0 / 2.0) - 1.0 / 3.0) <
|
|
epsilon);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
// Error handling test 1 (Test case 5)
|
|
std::cout << "Test 5: Error handling - P(B) = 0 (invalid)\n";
|
|
bool thrown = false;
|
|
try {
|
|
conditional_compute(0.2, 0.0);
|
|
} catch (const std::invalid_argument &e) {
|
|
std::cout << "Error caught: " << e.what() << "\n";
|
|
assert(std::string(e.what()) ==
|
|
"The given probability must be in (0, 1].");
|
|
thrown = true;
|
|
}
|
|
assert(thrown);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
// Error handling test 2 (Test case 6)
|
|
std::cout << "Test 6: Error handling - P(A and B) < 0 (invalid)\n";
|
|
thrown = false;
|
|
try {
|
|
conditional_compute(-0.1, 0.5);
|
|
} catch (const std::invalid_argument &e) {
|
|
std::cout << "Error caught: " << e.what() << "\n";
|
|
assert(std::string(e.what()) ==
|
|
"P(intersection) must be between 0 and the given probability.");
|
|
thrown = true;
|
|
}
|
|
assert(thrown);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
// Error handling test 3 (Test case 7)
|
|
std::cout << "Test 7: Error handling - P(B) > 1 (invalid)\n";
|
|
thrown = false;
|
|
try {
|
|
conditional_compute(0.2, 1.5);
|
|
} catch (const std::invalid_argument &e) {
|
|
std::cout << "Error caught: " << e.what() << "\n";
|
|
assert(std::string(e.what()) ==
|
|
"The given probability must be in (0, 1].");
|
|
thrown = true;
|
|
}
|
|
assert(thrown);
|
|
std::cout << "--PASSED--\n\n";
|
|
|
|
std::cout << "All tests have successfully passed!\n";
|
|
}
|
|
|
|
/**
|
|
* @brief Main function
|
|
* @returns 0 on exit
|
|
*/
|
|
int main() {
|
|
test(); // run self test implementations
|
|
return 0;
|
|
}
|