Untitled

 avatar
unknown
python
a month ago
3.9 kB
2
Indexable
import math
from itertools import product
from collections import defaultdict
from scipy.stats import norm, beta

def powerRSS(m, n, Delta, UCL):
    # محاسبه‌ی (F_theta = pnorm(Delta)) در R
    # در پایتون با norm.cdf از scipy.stats:
    F_theta = norm.cdf(Delta)
    
    # k = n/m در R. در صورتی‌که n بخش‌پذیر بر m باشد، k عدد صحیح خواهد بود
    # برای اطمینان از به‌دست آمدن عدد صحیح (در صورت درست بودن ورودی):
    k = n // m
    
    # معادل iterpc(9, m, replace=TRUE, ordered=TRUE) در R، 
    # تمام ترکیب‌های (در واقع پرموته با تکرار) طول m از اعداد {0,...,8}:
    # در R: R = getall(I) - 1 => یعنی همه‌ی عناصر را یک واحد کم می‌کند.
    # پس در پایتون باید ابتدا همه‌ی ترکیت‌ها را از 0..8 بگیریم و بعد 1 واحد کم کنیم.
    # اما طبق کد اصلی، در نهایت اعداد در R از {0..8} تبدیل می‌شوند به {-1..7}.
    all_sequences = list(product(range(9), repeat=m))
    R = []
    for seq in all_sequences:
        # هر عضو را یک واحد کم می‌کنیم
        R.append([x - 1 for x in seq])  # حالا هر x در بازه -1..7
    
    # بردارهای احتمال بتا برای pbeta(0.5, 1:m, m-(1:m)+1)
    # در R: pbeta(0.5, shape1=j, shape2=m-j+1) برای j از 1 تا m
    p_half = [
        beta.cdf(0.5, j, m - j + 1)
        for j in range(1, m+1)
    ]
    
    # بردارهای احتمال بتا برای pbeta(F_theta, 1:m, m-(1:m)+1)
    p_delta = [
        beta.cdf(F_theta, j, m - j + 1)
        for j in range(1, m+1)
    ]
    
    # تعریف تابع comb0 برای حالتی که ممکن است r < 0 یا r > k باشد:
    # در R، choose(k, x) در این شرایط مقدار 0 برمی‌گرداند.
    def comb0(n, r):
        if r < 0 or r > n:
            return 0
        return math.comb(n, r)
    
    # تابعی برای محاسبه‌ی حاصل‌ضرب 
    #    \prod_j choose(k, r_j) * [p[j]^(k - r_j)] * [(1 - p[j])^(r_j)]
    # که در حلقه‌های مختلف استفاده می‌کنیم.
    def product_term(r_row, p):
        prod_val = 1.0
        for j in range(m):
            x = r_row[j]
            cval = comb0(k, x)
            if cval == 0:
                return 0
            prob = p[j]
            prod_val *= cval * (prob ** (k - x)) * ((1 - prob) ** x)
            # اگر در میانه‌ی راه صفر شد، همان صفر را برمی‌گردانیم
            if prod_val == 0:
                return 0
        return prod_val
    
    # طبق فرمول در کد R:
    # U = (UCL + n) / 2
    # اگر U > n باشد، SUM = 0 برمی‌گردانیم و SUM1 = 0
    SUM = 0
    U = (UCL + n) / 2.0
    if U > n:
        return [SUM, 0]
    
    c_ = math.ceil(U)
    
    # برای تسریع عملیات، ابتدا فهرستی از ردیف‌های R را بر اساس مجموع عناصرشان گروه‌بندی می‌کنیم
    sum_map = defaultdict(list)
    for row in R:
        row_sum = sum(row)
        sum_map[row_sum].append(row)
    
    # حلقه‌ی اول: for(w in c:n) و جمع زدن روی p_half
    for w in range(c_, n+1):
        if w in sum_map:
            for r_row in sum_map[w]:
                SUM += product_term(r_row, p_half)
    
    # حلقه‌ی دوم: for(y in 0:(c-1)) و جمع زدن روی p_delta
    SUM1 = 0
    for y in range(0, c_):
        if y in sum_map:
            for r_row in sum_map[y]:
                SUM1 += product_term(r_row, p_delta)
    
    return [SUM, SUM1]

# مثال تست شبیه به R:
res = powerRSS(m=2, n=8, Delta=0, UCL=6)
print("powerRSS(2,8,0,6) in Python => ", res)
Leave a Comment