机器学习笔记之无约束优化问题——(阶段性收尾)共轭方向法与Wolfe准则优化方法Python示例

news2024/10/7 10:13:19

机器学习笔记之无约束优化问题——基于共轭方向法与Wolfe准则优化方法的Python示例

  • 引言
    • 小插曲:画图——非标准二次型的等值线
    • 算法在图像中的表示
      • 基于精确搜索的共轭梯度法
      • 基于Wolfe准则的共轭梯度法
    • 附:共轭梯度法完整代码

引言

本节使用 Python \text{Python} Python共轭梯度法精确搜索非精确搜索进行示例。

本人数学水平与代码水平有限,欢迎小伙伴一起讨论~关联文章:

小插曲:画图——非标准二次型的等值线

非标准二次型——这意味着:对应函数 f ( x ) = x T Q x \begin{aligned}f(x) = x^T \mathcal Q x\end{aligned} f(x)=xTQx中的正定矩阵 Q \mathcal Q Q不是对角阵。本节以凸二次函数
f ( x ) = x T Q x Q = ( 1 1 1 2 ) ; x ∈ R 2 f(x) = x^T \mathcal Q x \quad \mathcal Q = \begin{pmatrix}1 & 1 \\ 1 & 2\end{pmatrix};x \in \mathbb R^2 f(x)=xTQxQ=(1112);xR2
等值线为例,使用 Python \text{Python} Python做出基于 Wolfe Condition \text{Wolfe Condition} Wolfe Condition精确搜索的共轭梯度法效果。代码见文章最下方,后面不再赘述。如果使用二元函数进行表示,可以表示为如下形式:
f ( x 1 , x 2 ) = ( x 1   x 2 ) ( 1 1 1 2 ) ( x 1 x 2 ) = ( x 1 + x 2 x 1 + 2 x 2 ) ( x 1 x 2 ) = x 1 2 + 2 x 1 x 2 + 2 x 2 2 \begin{aligned} f(x_1,x_2) & = (x_1 \text{ } x_2)\begin{pmatrix} 1 & 1 \\ 1 & 2 \end{pmatrix}\begin{pmatrix} x_1 \\ x_2 \end{pmatrix} \\ & = (x_1 + x_2 \quad x_1 + 2x_2) \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} \\ & = x_1^2 + 2 x_1 x_2 + 2x_2^2 \end{aligned} f(x1,x2)=(x1 x2)(1112)(x1x2)=(x1+x2x1+2x2)(x1x2)=x12+2x1x2+2x22

很明显:该函数中不仅包含平方项,并且包含交叉项。因而无法将 x 1 , x 2 x_1,x_2 x1,x2进行独立表示。对于等值线函数表示如下:
基于 C > 0 \mathcal C>0 C>0的不同取值,可以得到相应大小的等值线结果。
x 1 2 + 2 x 1 x 2 + 2 x 2 2 = C x_1^2 + 2 x_1 x_2 + 2x_2^2 = \mathcal C x12+2x1x2+2x22=C
针对上述问题,这里的思路是:在给定等值线 C \mathcal C C的条件下,确定 x x x的范围判断 x 1 x1 x1是否为边缘的条件是: x 1 , C x_1,\mathcal C x1,C均视作常数,此时上述函数就是关于 x 2 x_2 x2的一元二次方程,只需要求解根判别公式 Δ = b 2 − 4 a c ≜ 0 \Delta = b^2 - 4ac \triangleq 0 Δ=b24ac0即可找到该范围:

  • 因为 Δ ≜ 0 \Delta \triangleq 0 Δ0说明一元二次方程有唯一解,意味着随机变量 x 1 x_1 x1的正交基在该位置与函数图像相切,见下示例图:
    确定等值线的左右边界示例
  • 其中 a = 2 , b = 2 x 1 , c = x 1 2 − C a = 2,b=2 x_1,c = x_1^2 - \mathcal C a=2,b=2x1,c=x12C,带入即可。
    0 ≜ Δ = b 2 − 4 a c = 4 x 1 2 − 8 ( x 1 2 − C ) ⇒ x = ± 2 C C > 0 \begin{aligned} 0 \triangleq \Delta & = b^2 - 4 ac \\ & = 4 x_1^2 - 8(x_1^2 - \mathcal C) \\ & \Rightarrow x = \pm \sqrt{2 \mathcal C} \quad \mathcal C > 0 \end{aligned} 0Δ=b24ac=4x128(x12C)x=±2C C>0

基于该范围,范围边缘 ± 2 C \pm \sqrt{2 \mathcal C} ±2C 只有唯一解,范围内的其他点均对应两个不相同的解。使用求根公式 − b ± b 2 − 4 a c 2 a \begin{aligned}\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}\end{aligned} 2ab±b24ac 大值与小值分开作图
一次画半个椭圆~
对应代码表示如下:

import math
import matplotlib.pyplot as plt

def CalxLimits(C):
	# 根判别式
    return math.sqrt(2 * C),-1 * math.sqrt(2 * C)

# def f(x,y):
    # 没有用到;只是描述一下这个非标准二次型函数。
    # return 2 * (y ** 2) + 2 * x * y + (x ** 2)

def GetAnalytical(x,C):
	# 求根公式 
    return 0.25 * (-2 * x + math.sqrt(8 * C - (4 * (x ** 2)))),0.25 * (-2 * x - math.sqrt(8 * C - (4 * (x ** 2))))

def DrawContourPicture(CList):
    for C in CList:
        UpperPointList,LowerPointList = list(),list()
        Upper,Lower = CalxLimits(C)
        xList = list(np.linspace(Lower,Upper,10000))
        for x in xList:
            Upperx,Lowerx = GetAnalytical(x,C)
            UpperPointList.append(Upperx)
            LowerPointList.append(Lowerx)

        plt.plot(xList, UpperPointList,'--',c="tab:blue")
        plt.plot(xList, LowerPointList,'--',c="tab:blue")
  	plt.show()

if __name__ == '__main__':
    CList = [0.01, 0.1, 0.5, 2, 4.5]
    DrawContourPicture(CList)

对应图像效果表示如下:
非标准二次型

算法在图像中的表示

基于精确搜索的共轭梯度法

由于目标函数 f ( ⋅ ) f(\cdot) f()凸二次函数,那么该函数一定存在全局最优解。因而可以使用基于精确搜索的共轭梯度法获取最优解。回顾无约束优化问题——共轭梯度法,其算法步骤表示如下:
初始化操作

  • 给定初始点 x 0 = ( 3 2 ) T x_0 = (3 \quad 2)^T x0=(32)T,记 d 0 = − ∇ f ( x 0 ) d_0 = - \nabla f(x_0) d0=f(x0);设置阈值 ϵ = 0.05 ; k = 0 \epsilon = 0.05;k=0 ϵ=0.05;k=0

算法过程

  • 首先判断范数 ∥ ∇ f ( x k ) ∥ ≤ ϵ \|\nabla f(x_k)\| \leq \epsilon ∥∇f(xk)ϵ是否成立 ? ? ?若成立,则算法终止
    个人理解:这里利用范数来侧面描述梯度向量 ∇ f ( x k ) \nabla f(x_k) f(xk)的大小。当 ∥ ∇ f ( x k ) ∥ ⇒ 0 \|\nabla f(x_k)\| \Rightarrow 0 ∥∇f(xk)0意味着向量 ∇ f ( x k ) \nabla f(x_k) f(xk)趋于零向量
  • 计算当前迭代步骤的最优步长 α k \alpha_k αk
    需要注意一下:上面链接文章中对目标函数的定义为 f ( x ) = 1 2 x T Q x + C T x \begin{aligned}f(x) =\frac{1}{2}x^T \mathcal Q x + \mathcal C^T x\end{aligned} f(x)=21xTQx+CTx,而系数 1 2 \begin{aligned}\frac{1}{2}\end{aligned} 21只是为了方便求导。在本节中的 f ( x ) = x T Q x f(x) = x^T \mathcal Q x f(x)=xTQx没有系数,因而需要在相应 α k \alpha_k αk化简结果中填上一个系数 1 2 \begin{aligned}\frac{1}{2}\end{aligned} 21
    α k = − [ ∇ f ( x k ) ] T d k 2 ( d k ) T Q d k \alpha_k = - \frac{[\nabla f(x_k)]^T d_k}{2(d_k)^T \mathcal Q d_k} αk=2(dk)TQdk[f(xk)]Tdk
  • 计算新位置点 x k + 1 = x k + α k ⋅ d k x_{k+1} = x_k + \alpha_k \cdot d_k xk+1=xk+αkdk,并计算共轭方向 d k + 1 d_{k+1} dk+1
    d k + 1 = − ∇ f ( x k + 1 ) + β k ⋅ d k , β k = [ ∇ f ( x k + 1 ) ] T Q d k ( d k ) T Q d k d_{k+1} = - \nabla f(x_{k+1}) + \beta_k \cdot d_k,\beta_k = \frac{[\nabla f(x_{k+1})]^T \mathcal Q d_k}{(d_k)^T \mathcal Q d_k} dk+1=f(xk+1)+βkdk,βk=(dk)TQdk[f(xk+1)]TQdk
  • k = k + 1 k = k+1 k=k+1,转步骤 1 1 1重新进行判断。

相应代码表示如下:

def ConjugateGradient():

    def f(PointInput, Q):
        # 二次型
        return np.dot(np.dot(PointInput, Q), PointInput)

    def Nablaf(PointInput, Q):
        # 二次型求导
        return 2 * np.dot(Q, PointInput)

    def GetNorm(ArrayInput):
        return np.linalg.norm(ArrayInput)

    Epsilon = 0.05
    InitPoint = np.array([3., 2.])
    Q = np.array([[1., 1.], [1., 2.]])
    PointList = list()
    PointList.append(InitPoint)

    ConjugateStart = -1 * Nablaf(InitPoint, Q)

    while True:
        if GetNorm(Nablaf(InitPoint, Q)) <= Epsilon:
            break
        else:
            alpha = -0.5 * (np.dot(Nablaf(InitPoint, Q), ConjugateStart) / np.dot(np.dot(ConjugateStart, Q),ConjugateStart))

            NewPoint = InitPoint + alpha * ConjugateStart
            Beta = np.dot(np.dot(Nablaf(NewPoint, Q), Q), ConjugateStart) / np.dot(np.dot(ConjugateStart, Q),ConjugateStart)
            NewConjugate = -1 * Nablaf(NewPoint, Q) + Beta * ConjugateStart
            PointList.append(NewPoint)
            print("[info] Iterations: ", len(PointList))
            
            InitPoint = NewPoint
            ConjugateStart = NewConjugate
    return PointList

对应图像表示如下:
精确搜索共轭梯度法示例
很明显,可以发现:使用精确搜索,它仅需要 1 1 1线搜索 n = 2 n=2 n=2次迭代必然能够找到最优解。由于下降方向是共轭方向 d k d_k dk,并且 Q \mathcal Q Q不是对角阵,因此上面迭代产生的下降方向之间并不满足垂直关系。
只是看起来优点迷惑人~

当然,如果在计算 α k \alpha_k αk过程中没有乘以 1 2 \begin{aligned}\frac{1}{2}\end{aligned} 21,会得到下面的结果:
循环无法停止,它只会在这几个点上无限循环下去。不要问我是怎么知道的~
循环错误示例

基于Wolfe准则的共轭梯度法

非精确搜索—— Wolfe Condition \text{Wolfe Condition} Wolfe Condition一节中介绍了这种方法,它主要通过参数 C 1 \mathcal C_1 C1来描述所选 α \alpha α上界;以及参数 C 2 \mathcal C_2 C2来描述上界以下范围内 α \alpha α满足的梯度范围
其中 ϕ ( α ) = f ( x k + 1 ) = f ( x k + α ⋅ d k ) \phi(\alpha) = f(x_{k+1}) = f(x_k + \alpha \cdot d_k) ϕ(α)=f(xk+1)=f(xk+αdk)
{ ϕ ( α ) ≤ f ( x k ) + C 1 [ ∇ f ( x k ) ] T d k ⋅ α ϕ ′ ( α ) ≥ C 2 ⋅ [ ∇ f ( x k ) ] T d k C 1 ∈ ( 0 , 1 ) C 2 ∈ ( C 1 , 1 ) \begin{cases} \phi(\alpha) \leq f(x_k) + \mathcal C_1 [\nabla f(x_k)]^T d_k \cdot \alpha \\ \phi'(\alpha) \geq \mathcal C_2 \cdot [\nabla f(x_k)]^T d_k \\ \mathcal C_1 \in (0,1) \\ \mathcal C_2 \in (\mathcal C_1,1) \end{cases} ϕ(α)f(xk)+C1[f(xk)]Tdkαϕ(α)C2[f(xk)]TdkC1(0,1)C2(C1,1)
线搜索过程中,每次迭代只选择一个满足上述条件的优质结果参与迭代,从而得到近似最优解。关于 Wolfe Condition \text{Wolfe Condition} Wolfe Condition收敛性证明详见传送门。对应代码描述如下:

    def WolfeConditionOperation(C1,C2,PointInput,Conjugate,Q,UpperLimits):

        def phi(alpha,PointInput,Conjugate,Q):
            return np.dot(np.dot(PointInput + alpha * Conjugate,Q),PointInput + alpha * Conjugate)

        def Derphi(alpha,PointInput,Conjugate,Q):
            # phi()函数关于alpha的导函数
            return np.dot(np.dot(Conjugate,Q),PointInput) + np.dot(np.dot(PointInput,Q),Conjugate) \
                   + 2 * alpha * np.dot(np.dot(Conjugate,Q),Conjugate)

        assert 0 < C1 < 1 and C1 < C2 < 1
        while True:
            alpha = random.uniform(0.0,UpperLimits)
            if phi(alpha,PointInput,Conjugate,Q) <= f(PointInput,Q) + C1 * alpha * np.dot(Nablaf(PointInput,Q),Conjugate):
                if Derphi(alpha,PointInput,Conjugate,Q) >= C2 * np.dot(Nablaf(PointInput,Q),Conjugate):
                    if not alpha:
                        continue
                    else:
                        UpperLimits /= 1.2
                        break
        return alpha

基于 Wolfe Condition \text{Wolfe Condition} Wolfe Condition共轭梯度法收敛效果描述如下:
需要说明的是,每次迭代产生的 α \alpha α不是固定的,对应图像也不是固定的。甚至有些时候选择出的 α \alpha α结果不满足迭代条件甚至卡死。多试几次~
WolfeCondition共轭梯度效果

附:共轭梯度法完整代码

import math
import random
import numpy as np
import matplotlib.pyplot as plt

def CalxLimits(C):
    return math.sqrt(2 * C),-1 * math.sqrt(2 * C)

# def f(x,y):
    # 没有用到;只是描述一下这个非标准型函数。
    # return 2 * (y ** 2) + 2 * x * y + (x ** 2)

def GetAnalytical(x,C):
    return 0.25 * (-2 * x + math.sqrt(8 * C - (4 * (x ** 2)))),0.25 * (-2 * x - math.sqrt(8 * C - (4 * (x ** 2))))

def DrawContourPicture(CList):

    for C in CList:
        UpperPointList,LowerPointList = list(),list()
        Upper,Lower = CalxLimits(C)
        xList = list(np.linspace(Lower,Upper,10000))
        for x in xList:
            Upperx,Lowerx = GetAnalytical(x,C)
            UpperPointList.append(Upperx)
            LowerPointList.append(Lowerx)

        plt.plot(xList, UpperPointList,'--',c="tab:blue")
        plt.plot(xList, LowerPointList,'--',c="tab:blue")
    # plt.show()

def ConjugateGradient(mode="WolfeCondition"):
    # 使用精确搜索(步长是最优解)的迭代效果。

    def f(PointInput,Q):
        # 二次型
        return np.dot(np.dot(PointInput,Q),PointInput)

    def Nablaf(PointInput,Q):
        # 二次型求导
        return 2 * np.dot(Q,PointInput)

    def GetNorm(ArrayInput):
        return np.linalg.norm(ArrayInput)

    def WolfeConditionOperation(C1,C2,PointInput,Conjugate,Q,UpperLimits):

        def phi(alpha,PointInput,Conjugate,Q):
            return np.dot(np.dot(PointInput + alpha * Conjugate,Q),PointInput + alpha * Conjugate)

        def Derphi(alpha,PointInput,Conjugate,Q):
            # phi()函数关于alpha的导函数
            return np.dot(np.dot(Conjugate,Q),PointInput) + np.dot(np.dot(PointInput,Q),Conjugate) \
                   + 2 * alpha * np.dot(np.dot(Conjugate,Q),Conjugate)

        assert 0 < C1 < 1 and C1 < C2 < 1

        while True:
            alpha = random.uniform(0.0,UpperLimits)
            if phi(alpha,PointInput,Conjugate,Q) <= f(PointInput,Q) + C1 * alpha * np.dot(Nablaf(PointInput,Q),Conjugate):
                if Derphi(alpha,PointInput,Conjugate,Q) >= C2 * np.dot(Nablaf(PointInput,Q),Conjugate):
                    if not alpha:
                        continue
                    else:
                        UpperLimits /= 1.2
                        break
        return alpha

    assert mode in ["Exact","WolfeCondition"]
    Epsilon = 0.05
    InitPoint = np.array([3.,2.])
    Q = np.array([[1.,1.],[1.,2.]])
    PointList = list()
    PointList.append(InitPoint)
    UpperLimits = 2.0
    C1 = 0.5
    C2 = 0.8
    ConjugateStart = -1 * Nablaf(InitPoint,Q)

    while True:
        if GetNorm(Nablaf(InitPoint,Q)) <= Epsilon:
            break
        else:
            if mode == "Exact":
                alpha = -0.5 * (np.dot(Nablaf(InitPoint,Q),ConjugateStart) / np.dot(np.dot(ConjugateStart,Q),ConjugateStart))
            else:
                alpha = WolfeConditionOperation(C1,C2,InitPoint,ConjugateStart,Q,UpperLimits)

            NewPoint = InitPoint + alpha * ConjugateStart
            Beta = np.dot(np.dot(Nablaf(NewPoint,Q),Q),ConjugateStart) / np.dot(np.dot(ConjugateStart,Q),ConjugateStart)
            NewConjugate = -1 * Nablaf(NewPoint,Q) + Beta * ConjugateStart
            PointList.append(NewPoint)

            InitPoint = NewPoint
            ConjugateStart = NewConjugate
            
    return PointList

def DrawPicture(PointList):
    CList = [0.01,0.1,0.5,2,4.5]
    DrawContourPicture(CList)
    
    plotList = list()
    for (x,y) in PointList:
        plotList.append((x,y))
        plt.scatter(x, y, s=40, facecolor="none", edgecolors="tab:red", marker='o')
        if len(plotList) < 2:
            continue
        else:
            plt.plot([plotList[0][0], plotList[1][0]], [plotList[0][1], plotList[1][1]], c="tab:red")
            plotList.pop(0)
    plt.show()

if __name__ == '__main__':
    PointList = ConjugateGradient()
    # PointList = ConjugateGradient(mode="Exact")
    DrawPicture(PointList)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1015163.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL优化--分组优化(group by)

分组操作&#xff0c;我们主要来看看索引对于分组操作的影响。 在没有索引的情况下&#xff0c;执行如下SQL&#xff0c;查询执行计划&#xff1a; explain select profession , count(*) from tb_user group by profession ;然后&#xff0c;我们在针对于 profession &#…

Linux 上的 Wayland 是什么?它与 X 有何不同?

导读Wayland 是 Linux 发行版的替代窗口系统。它取代了老化的 X11 标准。由于它需要修改应用程序才能使用它&#xff0c;因此迄今为止采用速度很慢。在撰写本文时&#xff0c;增强的安全性是相对于 X11 的主要优势。 X11 或 X Window 系统可让您的图形桌面环境显示和控制窗口。…

【C语言】指针的进阶(一)

目录 前言 1. 字符指针 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 4. 数组参数、指针参数 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 5. 函数指针 前言 指针在C语言中可谓是有着举足轻重的…

MySQL夺命20连问

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Seata 源码篇之核心思想 - 01

Seata 源码篇之核心思想 - 01 引言基础架构数据源代理分支事务提交和回滚隔离级别解决脏写读未提交读已提交 小结 笔者个人项目中使用到了seata来做分布式事务管理&#xff0c;面试过程中也经常被问到seata的原理&#xff0c;seata源码本身也不是很复杂&#xff0c;所以准备出一…

FWT小结

核心思想&#xff1a;把 a , b a,b a,b 化成 f w t ( a ) , f w t ( b ) fwt(a),fwt(b) fwt(a),fwt(b)&#xff0c;相乘后再化为 a a a 化的过程用的是分治 所以和FFT其实一模一样 OR / AND 卷积 不需要什么技巧&#xff0c;暴力分治转移即可 每次分治下去&#xff0c;…

瑞萨MCU入门教程(非常详细的瑞萨单片机入门教程)

瑞萨MCU零基础入门系列教程 前言 得益于瑞萨强大的MCU、强大的软件开发工具(e studio)&#xff0c;也得益于瑞萨和RA生态工作室提供的支持&#xff0c;我们团队编写了《ARM嵌入式系统中面向对象的模块编程方法》&#xff0c;全书37章&#xff0c;将近500页: 讲解面向对象编程…

硬件笔记:组装“固态 U 盘”的八年,从 100 块到 1000 块

这篇文章&#xff0c;聊聊自从 2015 年开始&#xff0c;到目前为止&#xff0c;我使用固态硬盘组装的高速 U 盘&#xff0c;以及它们的使用体验&#xff0c;以及一些明显的坑。 写在前面 2015 年的 8 月&#xff0c;我剁手下单了一块 32G 大小&#xff0c;NGFF接口的三星 22x…

关于 C/C++ 中在指针前加 const 关键字的作用说明

1. 作用说明&#xff1a; 在指针前加 const 的用途为&#xff1a;不可改变指针指向的内存的值&#xff0c;即将该指向指向的内存中的变量置为只读&#xff08;read-only) 变量。 但是&#xff0c;可以给 const 的指针赋值&#xff0c;即将具有 const 属性的指针指向别的内存地…

Linux 内核镜像分析

文章目录 前言一、概述二、bzImage2.1 镜像分析 三、zImage3.1 镜像分析参考链接 前言 介绍了vmlinux的来源&#xff0c;以及分析方法&#xff1b; 一、概述 在linux系统中&#xff0c;vmlinux&#xff08;vmlinuz&#xff09;是一个包含linux kernel的静态链接的可执行文件…

JavaScript中的原型继承和类继承之间的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 原型继承&#xff08;Prototype Inheritance&#xff09;⭐ 类继承&#xff08;Class Inheritance&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启…

MySQL开启安全审计日志,开启查询日志

MySQL 查询开启日志 在 MySQL 数据库中&#xff0c;开启查询日志是一个非常有用的技术&#xff0c;它能帮助你追踪每一个执行的查询语句&#xff0c;以便更好地优化 SQL 语句和性能。本文将介绍如何在 MySQL 数据库中开启查询日志。 开启查询日志 MySQL 中的查询日志是一种记…

Mysql开启binlog

本案例基于mysql5.7.16实验 1、在linux中进入mysql查询binlog是否打开&#xff0c;执行命令如下&#xff1a; mysql -u root -p 2、查询binlog是否开启命令如下&#xff0c;如果log_bin为OFF则证明mysql的binlog没有打开 show variables like %log_bin%; 3、退出mysql终端&…

OPC DA如何实现跨平台

目录 简介 EntireX DCOM Utgard OPC XML DA OPC UA 协议转换代理 简介 本文介绍OPC DA跨平台通讯的几种方案。 OPC官方说明文档 OPC&#xff08;OLE for Process Control&#xff09;是为过程控制专门设计的OLE 技术&#xff0c;基于COM/DCOM的数据访问的标准。常说的O…

vmware去虚拟化

路径&#xff1a;C:\Program Files (x86)\VMware\VMware Workstation\x64\vmware-vmx.exe &#xff0c;复制一份备份 用16进制工具打开修改这个文件&#xff0c;如winhex 1、搜索 25 73 2E 65 6E 61 62 6C &#xff0c;找到上面有两个"VMware"开头的 2、硬盘SCSI格…

JAVASE---String类

String类的重要性 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者字符指针&#xff0c;可以使用标准库提供的字符串系列函数完成大部分操作&#xff0c;但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想&#xff0c;而…

Java 类和对象

在面向对象语言中万物皆对象&#xff0c;一切都围绕对象来进行&#xff0c;找对象、建对象&#xff0c;用对象等。 类&#xff1a;把具有相同特征和行为的一组对象抽象为类&#xff0c;类是抽象概念&#xff0c;如人类、车类等&#xff0c;无法具体到每个实体。 对象&#xff…

71、Spring Data JPA 的 样本查询--参数作为样本去查询数据库的数据,也可以定义查询的匹配规则

★ 样本查询 给Spring Data传入一个样本数据&#xff0c;Spring Data就能从数据库中查询出和样本相同的数据。被查询的数据并不需要和样本是完全相同的&#xff0c;可能只需要和样本有几个属性是相同的。总结&#xff1a; 样本查询–就是把参数作为样本去查询数据库的数据&…

一、 计算机网络概论

一、计算机网络概论 1、计算机网络概述 1.1、概念 计算机网络是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统 是一些互连的、自治的计算机系统的集合 以能够相互共享资源的方…

【Git】Git 变基(rebase)以及rebase和merge之间的区别

Git 变基 1.变基 — rebase 在 Git 中整合来自不同分支的修改主要有两种方法&#xff1a;merge 以及 rebase。 在前面的文章中已经介绍了merge&#xff0c;这里我们来学习另一个指令rebase。 变基的基本操作 回顾之前在 分支的合并 中的一个例子&#xff0c;在该例子中&am…