@@ -251,6 +251,119 @@ struct KarrasSchedule : SigmaSchedule {
251251 }
252252};
253253
254+ struct BetaSchedule : SigmaSchedule {
255+ static constexpr double alpha = 0.6 ;
256+ static constexpr double beta = 0.6 ;
257+
258+ // Log Beta function
259+ static double log_beta (double a, double b) {
260+ return std::lgamma (a) + std::lgamma (b) - std::lgamma (a + b);
261+ }
262+
263+ // Regularized incomplete beta function using continued fraction
264+ static double incbeta (double x, double a, double b) {
265+ if (x <= 0.0 ) return 0.0 ;
266+ if (x >= 1.0 ) return 1.0 ;
267+
268+ // Use the continued fraction approximation (Lentz’s method)
269+ const int MAX_ITER = 200 ;
270+ const double EPSILON = 3.0e-7 ;
271+
272+ double aa, c, d, del, h;
273+ double qab = a + b;
274+ double qap = a + 1.0 ;
275+ double qam = a - 1.0 ;
276+
277+ c = 1.0 ;
278+ d = 1.0 - qab * x / qap;
279+ if (std::abs (d) < 1e-30 ) d = 1e-30 ;
280+ d = 1.0 / d;
281+ h = d;
282+
283+ for (int m = 1 ; m <= MAX_ITER; m++) {
284+ int m2 = 2 * m;
285+
286+ // Even term
287+ aa = m * (b - m) * x / ((qam + m2) * (a + m2));
288+ d = 1.0 + aa * d;
289+ if (std::abs (d) < 1e-30 ) d = 1e-30 ;
290+ c = 1.0 + aa / c;
291+ if (std::abs (c) < 1e-30 ) c = 1e-30 ;
292+ d = 1.0 / d;
293+ h *= d * c;
294+
295+ // Odd term
296+ aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
297+ d = 1.0 + aa * d;
298+ if (std::abs (d) < 1e-30 ) d = 1e-30 ;
299+ c = 1.0 + aa / c;
300+ if (std::abs (c) < 1e-30 ) c = 1e-30 ;
301+ d = 1.0 / d;
302+ del = d * c;
303+ h *= del;
304+
305+ if (std::abs (del - 1.0 ) < EPSILON) break ;
306+ }
307+
308+ return std::exp (a * std::log (x) + b * std::log (1.0 - x) - log_beta (a, b)) / a * h;
309+ }
310+
311+ // Beta CDF using symmetry for better convergence
312+ static double beta_cdf (double x, double a, double b) {
313+ if (x == 0.0 ) return 0.0 ;
314+ if (x == 1.0 ) return 1.0 ;
315+ if (x < (a + 1.0 ) / (a + b + 2.0 )) {
316+ return incbeta (x, a, b);
317+ } else {
318+ return 1.0 - incbeta (1.0 - x, b, a);
319+ }
320+ }
321+
322+ // Inverse Beta CDF (PPF) using Newton-Raphson
323+ static double beta_ppf (double u, double a, double b, int max_iter = 30 ) {
324+ double x = 0.5 ; // initial guess
325+ for (int i = 0 ; i < max_iter; i++) {
326+ double f = beta_cdf (x, a, b) - u;
327+ if (std::abs (f) < 1e-10 ) break ;
328+ // derivative = x^(a-1) * (1-x)^(b-1) / B(a,b)
329+ double df = std::exp ((a-1.0 )*std::log (x) + (b-1.0 )*std::log (1.0 -x) - log_beta (a,b));
330+ x -= f / df;
331+ if (x <= 0.0 ) x = 1e-10 ;
332+ if (x >= 1.0 ) x = 1.0 - 1e-10 ;
333+ }
334+ return x;
335+ }
336+
337+ std::vector<float > get_sigmas (uint32_t n, float /* sigma_min*/ , float /* sigma_max*/ , t_to_sigma_t t_to_sigma) override {
338+ std::vector<float > result;
339+ result.reserve (n + 1 );
340+
341+ int t_max = TIMESTEPS - 1 ;
342+ if (n == 0 ) {
343+ return result;
344+ } else if (n == 1 ) {
345+ result.push_back (t_to_sigma ((float )t_max));
346+ result.push_back (0 .f );
347+ return result;
348+ }
349+
350+ int last_t = -1 ;
351+ for (uint32_t i = 0 ; i < n; i++) {
352+ double u = 1.0 - double (i)/double (n); // reversed linspace
353+ double t_cont = beta_ppf (u, alpha, beta) * t_max;
354+ int t = (int )std::lround (t_cont);
355+
356+ if (t != last_t ) {
357+ result.push_back (t_to_sigma ((float )t));
358+ last_t = t;
359+ }
360+ }
361+
362+ result.push_back (0 .f );
363+ return result;
364+ }
365+ };
366+
254367struct Denoiser {
255368 std::shared_ptr<SigmaSchedule> scheduler = std::make_shared<DiscreteSchedule>();
256369 virtual float sigma_min () = 0;
0 commit comments