数值优化:牛顿法+armijo 求rosenbrock多维函数

计算231次求的最优解

#Rosenbrock_f.py

import numpy as np 

def cal_rosenbrock(x):

    # 计算rosenbrock函数的值
    return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)



def rosen_der(x):
    xm = x[1:-1]
    xm_m1 = x[:-2]
    xm_p1 = x[2:]
    der = np.zeros_like(x)
    der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm)
    der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
    der[-1] = 200*(x[-1]-x[-2]**2)
    return der

def rosen_hess(x):
    x = np.asarray(x)
    H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1)
    diagonal = np.zeros_like(x)
    diagonal[0] = 1200*x[0]**2-400*x[1]+2
    diagonal[-1] = 200
    diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:]
    H = H + np.diag(diagonal)
    return H


def armijo(x,error,alpha = 1):

    # armijo法求步长alpha
    def loss(alpha,x,loss = 0):
        temp = []
        for i in range(11):
            temp.append(x[i])
        for i in range(11):
            temp[i] -= alpha * error[i]
        for i in range(10):
            loss += 100 * (temp[i + 1] - temp[i] ** 2) ** 2 + (temp[i] - 1) ** 2

        return loss

    def check(alpha,x):
        return loss(alpha,x) > loss_0 - sigma * alpha * np.dot(error,error)

    sigma = 0.02
    rho = 0.4
    loss_0 = loss(0,x)

    if check(alpha,x) == False:
        alpha = 1
    elif check(alpha,x):
        alpha = 0.02
        while check(alpha,x):
            alpha *= rho

    return alpha

def for_rosenbrock_func(max_iter_count = 1000):
    pre_x = np.zeros((11,),dtype=np.float32)
    loss = 10
    cnt = 0
    while loss > 0.001 and cnt < max_iter_count:
        error = np.zeros((11,), dtype=np.float32)
        Hess = np.zeros((11,), dtype=np.float32)

        # 计算梯度
        error = rosen_der(pre_x)
        Hess = np.linalg.inv(rosen_hess(pre_x))

        dk = np.dot(Hess,error)

        #沿下降梯度找寻最优解

        alpha = armijo(pre_x,dk)

        for j in range(11):
            pre_x[j] -= alpha * dk[j]

        loss = cal_rosenbrock(pre_x)  # 最小值为0

        print("count: ", cnt, "the loss:", loss,"step:",alpha)
        cnt += 1
    return pre_x

if __name__ == '__main__':
    w = for_rosenbrock_func()  
    print(w)
DFP(Davidon-Fletcher-Powell)算法是一种用于寻找函数局部最小值的非线性优化方法,它是一种梯度下降法的一种改进。在C++中实现DFP算法需要一些数值计算库,比如 Armadillo 或 Eigen 等。以下是使用 Armadillo 库的一个简单示例,假设 `arma::mat` 用于向量和矩阵操作: ```cpp #include <armadillo> using namespace arma; // 定义函数 f(x) double func(double x1, double x2) { return pow(x1, 2) - 2 * x1 * x2 + 2 * pow(x2, 2) - 2 * x1 + x2; } // 导数 (偏导数) arma::vec grad(double x1, double x2) { return vec({2 * x1 - 2 * x2 - 2, 4 * x2 - 2}); } // DFP算法核心步骤 arma::mat dfp_update(arma::vec& current_point, double learning_rate, int max_iter, double tolerance) { arma::vec gradient = grad(current_point(0), current_point(1)); arma::mat hessian_inv = inv(hessian(grad(current_point))); // 假设Hessian矩阵可用,这里省略计算 arma::vec step_direction = -hessian_inv * gradient; // 更新方向 double alpha = 0; // 学习率调整因子 for (int i = 0; i < max_iter && alpha <= tolerance; ++i) { current_point += learning_rate * step_direction; // 步长搜索 alpha = func(current_point(0), current_point(1)) / func(current_point(0) - step_direction(0), current_point(1) - step_direction(1)); // Wolfe条件检查 } return current_point; } // 初始点 arma::vec initial_point = {0, 0}; // 设置学习率、最大迭代次数和容忍度 double lr = 0.01; // 学习率 int max_iter = 100; // 最大迭代次数 double tolerance = 1e-6; // 达到精度就停止 // 运行DFP算法 arma::vec minima = dfp_update(initial_point, lr, max_iter, tolerance); // 输出结果 std::cout << "找到的极小点坐标: (" << minima(0) << ", " << minima(1) << ")" << std::endl;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值