Untitled
unknown
python
9 months ago
7.7 kB
6
Indexable
import math
from math import comb, gamma
from itertools import product
import numpy as np
from scipy.stats import norm, beta as beta_dist
from scipy.special import beta as BetaFunc # Beta(x,y) = Γ(x)Γ(y)/Γ(x+y)
# --- ثابتهای مسأله (معادل globalها در کد R) ---
Z0 = 0.25
Z1 = 0.25
Z2 = 0.75
a = 20
b = 4.22
D0 = 50
D1 = 950
Y = 500
W = 1100
delta = 0 # برای pnorm(delta)
k = 3
lambda_ = 0.002 # (lambda را نمیتوان نام متغیر در پایتون گذاشت)
# تابع A بر اساس کد R:
# ------------------------------------------------
# A(x) در Banerjee سریای را تا زمانی که اختلاف گامها کمتر از 1e-6 شود جمع میکند.
def A(xx):
aw = [0.0] # متناظر با aw<-0 در R ولی با لیست برای نگهداری مقادیر تجمعی
vw = 0 # شمارنده نمای
s = 0.001 # مقدار اولیه برای شروع حلقه
# تا زمانی که مقدار گام اخیر از 1e-6 بیشتر باشد ادامه میدهیم
while s >= 1e-6:
# ((1+vw)^(1/k)) * (xx^vw)
cw = ((1 + vw)**(1 / k)) * (xx**vw)
new_val = aw[-1] + cw
s = new_val - aw[-1] # اختلاف گام
aw.append(new_val)
vw += 1
return aw[-1]
# تابع اصلی co که معادل co<-function(x){...} در R است
# x ورودیای به شکل [m,q,h,L]
# ------------------------------------------------
def co(x):
# استخراج پارامترها از بردار x
m = int(math.floor(x[0]))
q = int(math.floor(x[1]))
h = x[2]
L = x[3]
n = m * q # کل نمونه در هر سیکل
alpha = 0.0
beta_ = 0.0 # نام آن را beta_ میگذاریم تا با تابع beta تداخلی نداشته باشد
F_theta = norm.cdf(delta) # pnorm(delta)
# Fi(m,i) و delta0(m) در کد R:
# -----------------------------------------------------------------
# Fi(m,i) = m * choose(m-1,i-1)* beta(i, m-i+1)* pbeta(0.5, i, m-i+1)
# delta0(m)=1 - (4/m)* sum((Fi(m,1..m)-0.5)^2)
# اینها برای محاسبهی ucl استفاده میشوند.
def Fi(m_, i_):
# choose(m-1, i-1)
ch = comb(m_ - 1, i_ - 1)
# beta(i, m-i+1) => تابع BetaFunc(i, m-i+1)
bt = BetaFunc(i_, m_ - i_ + 1)
# pbeta(0.5, i, m-i+1)
cdf_05 = beta_dist.cdf(0.5, i_, m_ - i_ + 1)
return m_ * ch * bt * cdf_05
def delta0(m_):
vals = []
for i_ in range(1, m_ + 1):
vals.append(Fi(m_, i_) - 0.5)
return 1 - (4 / m_) * sum([v**2 for v in vals])
# ساختن تمام ترکیبات R از طریق itertools.product(range(9), repeat=m)
# معادل با iterpc(9,m, replace=TRUE, ordered=TRUE) و سپس getall(I) - 1.
# در R: getall(I) اعداد 1..9 میداد که منهای 1 => 0..8
# در اینجا مستقیماً range(9) => 0..8
R_list = list(product(range(9), repeat=m))
# محاسبه ucl
d0 = delta0(m) # همان delta0(m)
ucl = int(math.floor((n / 2 + (L * np.sqrt(n * d0 / 4)) + n) / 2))
# در کد R اگر ucl>n باشد، EA=100000 مقداردهی میشود اما به شکل return انجام نمیدهد.
# برای سادگی در پایتون مستقیم برمیگردیم:
if ucl > n:
return 1e5 # هزینه بالا برای طرح نامعتبر
# محاسبه alpha با حلقه روی c=0..ucl
# "alpha" = 1 - Sum_{sum(r)=c}(...) => در انتها alpha=1-alpha
cdf_half = [beta_dist.cdf(0.5, j, m - j + 1) for j in range(1, m + 1)]
alpha_sum = 0.0
for c_ in range(ucl + 1):
# فیلتر آنهایی که جمع المانهایشان c_ است
subset_c = [r for r in R_list if sum(r) == c_]
for r_ in subset_c:
# محاسبه حاصلضرب بر اساس j از 1..m
# اما در پایتون ایندکس r_ از 0..m-1 است
pr = 1.0
for j in range(m):
# choose(q, r_[j])
ch = comb(q, r_[j])
# pbeta(0.5, j+1, m-j) = cdf_half[j]
p_half = cdf_half[j]
pr *= ch * (p_half**(q - r_[j])) * ((1 - p_half)**(r_[j]))
alpha_sum += pr
alpha = 1.0 - alpha_sum
# محاسبه beta (beta_) با حلقه مشابه، اما با F_theta
cdf_Ftheta = [beta_dist.cdf(F_theta, j, m - j + 1) for j in range(1, m + 1)]
for y_ in range(ucl + 1):
subset_y = [r for r in R_list if sum(r) == y_]
for r_ in subset_y:
pr = 1.0
for j in range(m):
ch = comb(q, r_[j])
p_ftheta = cdf_Ftheta[j]
pr *= ch * (p_ftheta**(q - r_[j])) * ((1 - p_ftheta)**(r_[j]))
beta_ += pr
# حالا p در Banerjee:
# p = 1 - exp(-lambda * h^k)
p = 1.0 - math.exp(-lambda_ * (h**k))
# محاسبه A(1-p) و A(beta_)
Ap = A(1 - p)
Abeta_ = A(beta_)
# محاسبه ET بر اساس فرمولهای داخل کد
# ------------------------------------------------
# ET = Z1 + Z2
# + alpha * Z0 * ((1-p)/p)
# + (h*p*Ap)
# + [ beta * h * p * ( (p*Ap) - (1-beta)*Abeta ) ] / (1 - p - beta)
try:
ET = (Z1 + Z2
+ alpha * Z0 * ((1 - p) / p)
+ (h * p * Ap)
+ (beta_ * h * p * ((p * Ap) - (1 - beta_) * Abeta_)) / (1 - p - beta_))
except ZeroDivisionError:
# اگر 1 - p - beta_ صفر یا خیلی کوچک باشد
return 1e5
# محاسبه EC
# ------------------------------------------------
# EC = (a + b*n)* [ (beta/(1-beta)) + 1/p ]
# + alpha*Y*((1-p)/p)
# + (D0 - D1)* ( ((1/lambda)^(1/k)) * gamma(1 + 1/k) - h*(1-p)*p*Ap )
# + D0*h*p*(1-p)*Ap
# + [ (beta*h*D1*p*( p*Ap - (1-beta)*Abeta )) / (1-p-beta) ]
# + (D1*h*(p^2)*Ap)
# + W
try:
EC = ((a + b * n) * ((beta_ / (1 - beta_)) + 1.0 / p)
+ alpha * Y * ((1 - p) / p)
+ (D0 - D1) * (((1.0 / lambda_)**(1.0 / k)) * gamma(1.0 + 1.0 / k)
- h * (1 - p) * p * Ap)
+ (D0 * h * p * (1 - p) * Ap)
+ ((beta_ * h * D1 * p * ((p * Ap) - (1 - beta_) * Abeta_))
/ (1 - p - beta_))
+ (D1 * h * (p**2) * Ap)
+ W)
except ZeroDivisionError:
return 1e5
EA = EC / ET
return EA
# --- نمونه فراخوانی مشابه با کد R: ---
if __name__ == "__main__":
# چند نمونه از ورودیها که در انتهای کد R هم آمده بود:
print("co([2,1,4.17,1]) =", co([2,1,4.17,1]))
print("co([3,1,3.25,1]) =", co([3,1,3.25,1]))
print("co([4,1,3.2,1]) =", co([4,1,3.2,1]))
print("co([2,2,3.13,1]) =", co([2,2,3.13,1]))
print("co([2,3,30,1]) =", co([2,3,30,1]))
# بهینهسازی با L-BFGS-B در محدوده خاص:
from scipy.optimize import minimize
# حد پایین و بالای هر پارامتر: [m, q, h, L]
bounds = [(2,4), # m بین 2 و 4
(1,6), # q بین 1 و 6
(1,5), # h بین 1 و 5
(1,2)] # L بین 1 و 2
x0 = [2,1,1,1] # شروع
res = minimize(co, x0, method="L-BFGS-B", bounds=bounds)
print("\nResult of L-BFGS-B optimization:")
print("x* =", res.x)
print("objective =", res.fun)
print("status:", res.message)
Editor is loading...
Leave a Comment