1+ #include < stan/math/prim.hpp>
2+ #include < gtest/gtest.h>
3+ #include < limits>
4+
5+ TEST (ProbGamma, lccdf_works) {
6+ using stan::math::gamma_lccdf;
7+
8+ double y = 0.8 ;
9+ double alpha = 1.1 ;
10+ double beta = 2.3 ;
11+
12+ EXPECT_NO_THROW (gamma_lccdf (y, alpha, beta));
13+ }
14+
15+ TEST (ProbGamma, lccdf_zero_y) {
16+ using stan::math::gamma_lccdf;
17+
18+ // When y = 0, LCCDF(0) = log(P(Y > 0)) = log(1) = 0
19+ // For continuous distribution, P(Y > 0) = 1
20+ double alpha = 1.5 ;
21+ double beta = 2.0 ;
22+
23+ double result = gamma_lccdf (0.0 , alpha, beta);
24+ EXPECT_EQ (result, 0.0 );
25+ }
26+
27+ TEST (ProbGamma, lccdf_large_y) {
28+ using stan::math::gamma_lccdf;
29+
30+ // When y is very large, CDF approaches 1, so LCCDF = log(1-1) = log(0) = -inf
31+ double alpha = 1.5 ;
32+ double beta = 2.0 ;
33+ double y = 1e10 ;
34+
35+ double result = gamma_lccdf (y, alpha, beta);
36+
37+ // Should be a very large negative number (approaching -infinity)
38+ EXPECT_LT (result, -1000.0 );
39+ }
40+
41+ TEST (ProbGamma, lccdf_infinity_y) {
42+ using stan::math::gamma_lccdf;
43+ using stan::math::negative_infinity;
44+
45+ // When y = infinity, LCCDF = log(P(Y > ∞)) = log(0) = -∞
46+ double alpha = 1.5 ;
47+ double beta = 2.0 ;
48+ double y = std::numeric_limits<double >::infinity ();
49+
50+ double result = gamma_lccdf (y, alpha, beta);
51+ EXPECT_EQ (result, negative_infinity ());
52+ }
53+
54+ TEST (ProbGamma, lccdf_small_alpha_small_y) {
55+ using stan::math::gamma_lccdf;
56+
57+ // Small alpha, small y - numerically challenging
58+ double y = 0.001 ;
59+ double alpha = 0.1 ;
60+ double beta = 1.0 ;
61+
62+ double result = gamma_lccdf (y, alpha, beta);
63+
64+ // Should be finite and negative
65+ EXPECT_TRUE (std::isfinite (result));
66+ EXPECT_LT (result, 0.0 );
67+ }
68+
69+ TEST (ProbGamma, lccdf_large_alpha_large_y) {
70+ using stan::math::gamma_lccdf;
71+
72+ // Large alpha, large y
73+ double y = 100.0 ;
74+ double alpha = 50.0 ;
75+ double beta = 0.5 ;
76+
77+ double result = gamma_lccdf (y, alpha, beta);
78+
79+ // Should be finite
80+ EXPECT_TRUE (std::isfinite (result));
81+ }
82+
83+ TEST (ProbGamma, lccdf_alpha_one) {
84+ using stan::math::gamma_lccdf;
85+ using std::exp;
86+ using std::log;
87+
88+ // When alpha = 1, gamma becomes exponential
89+ // For exponential with rate beta: LCCDF(y) = log(1 - (1-exp(-beta*y))) = log(exp(-beta*y)) = -beta*y
90+ double y = 2.0 ;
91+ double alpha = 1.0 ;
92+ double beta = 3.0 ;
93+
94+ double result = gamma_lccdf (y, alpha, beta);
95+ double expected = -beta * y; // = -6.0
96+
97+ EXPECT_NEAR (result, expected, 1e-10 );
98+ }
99+
100+ TEST (ProbGamma, lccdf_various_values) {
101+ using stan::math::gamma_lccdf;
102+
103+ // Test a variety of parameter combinations
104+ std::vector<std::tuple<double , double , double >> test_cases = {
105+ {0.5 , 0.5 , 1.0 }, // Small y, small alpha
106+ {1.0 , 1.0 , 1.0 }, // All ones
107+ {2.0 , 3.0 , 0.5 }, // Moderate values
108+ {10.0 , 2.0 , 0.1 }, // Large y, small beta
109+ {0.1 , 10.0 , 2.0 }, // Small y, large alpha
110+ {5.0 , 5.0 , 1.0 }, // Equal alpha and y
111+ {0.01 , 0.5 , 10.0 }, // Small y, large beta
112+ {100.0 , 100.0 , 1.0 } // Large matched values
113+ };
114+
115+ for (const auto & test_case : test_cases) {
116+ double y = std::get<0 >(test_case);
117+ double alpha = std::get<1 >(test_case);
118+ double beta = std::get<2 >(test_case);
119+
120+ double result = gamma_lccdf (y, alpha, beta);
121+
122+ // All results should be finite and <= 0
123+ EXPECT_TRUE (std::isfinite (result))
124+ << " Failed for y=" << y << " , alpha=" << alpha << " , beta=" << beta;
125+ EXPECT_LE (result, 0.0 )
126+ << " Failed for y=" << y << " , alpha=" << alpha << " , beta=" << beta;
127+ }
128+ }
129+
130+ TEST (ProbGamma, lccdf_extreme_small_values) {
131+ using stan::math::gamma_lccdf;
132+
133+ // Very small but non-zero values
134+ double y = 1e-10 ;
135+ double alpha = 1e-5 ;
136+ double beta = 1.0 ;
137+
138+ double result = gamma_lccdf (y, alpha, beta);
139+
140+ EXPECT_TRUE (std::isfinite (result));
141+ }
142+
143+ TEST (ProbGamma, lccdf_extreme_large_alpha) {
144+ using stan::math::gamma_lccdf;
145+
146+ // Very large alpha (approaches normal distribution)
147+ double y = 1000.0 ;
148+ double alpha = 1000.0 ;
149+ double beta = 1.0 ;
150+
151+ double result = gamma_lccdf (y, alpha, beta);
152+
153+ EXPECT_TRUE (std::isfinite (result));
154+ }
155+
156+ TEST (ProbGamma, lccdf_monotonic_in_y) {
157+ using stan::math::gamma_lccdf;
158+
159+ // LCCDF should be monotonically decreasing in y
160+ double alpha = 2.0 ;
161+ double beta = 1.5 ;
162+
163+ double y1 = 1.0 ;
164+ double y2 = 2.0 ;
165+ double y3 = 3.0 ;
166+
167+ double lccdf1 = gamma_lccdf (y1, alpha, beta);
168+ double lccdf2 = gamma_lccdf (y2, alpha, beta);
169+ double lccdf3 = gamma_lccdf (y3, alpha, beta);
170+
171+ EXPECT_GT (lccdf1, lccdf2);
172+ EXPECT_GT (lccdf2, lccdf3);
173+ }
174+
175+ TEST (ProbGamma, lccdf_consistency_with_cdf) {
176+ using stan::math::gamma_lccdf;
177+ using stan::math::gamma_cdf;
178+ using std::log;
179+
180+ // Test that lccdf(y) ≈ log(1 - cdf(y))
181+ double y = 1.5 ;
182+ double alpha = 2.5 ;
183+ double beta = 1.8 ;
184+
185+ double lccdf_val = gamma_lccdf (y, alpha, beta);
186+ double cdf_val = gamma_cdf (y, alpha, beta);
187+ double expected = log (1.0 - cdf_val);
188+
189+ EXPECT_NEAR (lccdf_val, expected, 1e-10 );
190+ }
191+
192+ TEST (ProbGamma, lccdf_numerically_challenging) {
193+ using stan::math::gamma_lccdf;
194+
195+ // Test cases that might cause numerical issues
196+ std::vector<std::tuple<double , double , double >> challenging_cases = {
197+ {1e-8 , 1e-6 , 1.0 }, // Very small y and alpha
198+ {1e-6 , 100.0 , 1e-3 }, // Very small y, large alpha, small beta
199+ {1000.0 , 0.1 , 1e-4 }, // Large y, small alpha, very small beta
200+ {50.0 , 50.0 , 1.0 }, // Matched moderate values
201+ {0.001 , 0.001 , 100.0 }, // Small y and alpha, large beta
202+ {1e6 , 10.0 , 1e-6 }, // Very large y, moderate alpha, very small beta
203+ };
204+
205+ for (const auto & test_case : challenging_cases) {
206+ double y = std::get<0 >(test_case);
207+ double alpha = std::get<1 >(test_case);
208+ double beta = std::get<2 >(test_case);
209+
210+ double result = gamma_lccdf (y, alpha, beta);
211+
212+ // Should not be NaN
213+ EXPECT_FALSE (std::isnan (result))
214+ << " NaN for y=" << y << " , alpha=" << alpha << " , beta=" << beta;
215+
216+ // Should be <= 0 (log of probability)
217+ EXPECT_LE (result, 0.0 )
218+ << " Positive value for y=" << y << " , alpha=" << alpha << " , beta=" << beta;
219+ }
220+ }
221+
222+ TEST (ProbGamma, lccdf_shape_zero_throws) {
223+ using stan::math::gamma_lccdf;
224+
225+ // alpha (shape) must be positive
226+ EXPECT_THROW (gamma_lccdf (1.0 , 0.0 , 1.0 ), std::domain_error);
227+ EXPECT_THROW (gamma_lccdf (1.0 , -1.0 , 1.0 ), std::domain_error);
228+ }
229+
230+ TEST (ProbGamma, lccdf_rate_zero_throws) {
231+ using stan::math::gamma_lccdf;
232+
233+ // beta (rate) must be positive
234+ EXPECT_THROW (gamma_lccdf (1.0 , 1.0 , 0.0 ), std::domain_error);
235+ EXPECT_THROW (gamma_lccdf (1.0 , 1.0 , -1.0 ), std::domain_error);
236+ }
237+
238+ TEST (ProbGamma, lccdf_negative_y_throws) {
239+ using stan::math::gamma_lccdf;
240+
241+ // y must be non-negative
242+ EXPECT_THROW (gamma_lccdf (-1.0 , 1.0 , 1.0 ), std::domain_error);
243+ EXPECT_THROW (gamma_lccdf (-0.001 , 1.0 , 1.0 ), std::domain_error);
244+ }
0 commit comments