【多目标进化优化】MOPSO 原理与代码实现

news2024/11/19 3:40:08
🎈💞💞 😇 热烈欢迎您的到来 😇 💘💘🎈

——青年有志

🏆初衷: 通俗的语言 dapei 核心的内容

🎉 博主相信: 有足够的积累,并且一直在路上,就有无限的可能!!!

👨‍🎓个人主页: 青年有志的博客

💯 Gitee 源码地址: https://gitee.com/futurelqh/Multi-objective-evolutionary-optimization


前言

前驱知识

  • 粒子群优化算法 PSO:https://blog.csdn.net/qq_46450354/article/details/127464089
  • Pareto 最优解集: https://blog.csdn.net/qq_46450354/article/details/127917026

粒子群优化算法 PSO

pbest: 粒子本身经历过的最优位置

gbest: 粒子群整体经历过的最优位置

算法思路: 在单目标优化中,通过自我认知 pbest 以及社会认知 gbest 来计算出每个个体下一次移动的速度,从而更新个体所处的位置 x,并更新个体 pbest,以及群体的 gbest,更新的依据直接通过比较目标函数值 function value 的大小即可。

PSO 算法流程图

PSO 引出 MOPSO

  • PSO 在用于单目标优化过程中,由于只有一个函数,两个个体之间可以通过直接比较大小来判断好坏,从而判断是否更新 pbest,gbest。
  • 在多目标问题中存在多个目标值,比如求两个目标函数的最小值,有两个个体 P 1 = ( 8 , 15 ) , P 2 = ( 10 , 12 ) {P_1} = (8, 15), P_2 = (10, 12) P1=(8,15),P2=(10,12) P 1 {P_1} P1 的第一个目标函数值小于 P 2 {P_2} P2,而第二个目标函数值大于 P 2 P_2 P2,如何判断谁更好呢?

问题:

  1. 如何更新多目标中的 pbest ?
  2. 如何更新多目标中的 gbest ?
  3. 对于多目标优化问题,输出的结果为一个集合,即 rep (非支配集/归档集) ,此集合的大小如何维护 ?
  4. 并且 PSO 很容易陷入局部最优,如何避免呢?

注: rep 集,在部分文献中会称为 Archive 集,均为同一种,即当前迭代中的的非支配集,也称为归档集,为避免混淆,本文同一使用 rep 。

MOPSO 所解决的正是这些个问题,从而将单目标 PSO,变为了能够高效求解多目标优化的算法。下面我们来看看这些问题是如何解决的

1. 如何更新多目标中的 pbest ?

分为三种情况进行更新:

  • ① 当新产生的个体 i 在每个目标函数值上都比 pbest 更优越,则更新 pbest (i 支配 pbest)
  • ② 当新产生的个体 i 在每个目标函数值上都比 pbest 更劣,则不更新 (pbest 支配 i)
  • ③ 当新产生的个体 i 在部分目标函数值上比 pbest 优越,则随机按照一定的概率进行更新 (i 与 pbest 互不支配)

2. 如何更新多目标中的 gbest ?

  • 如何在所有互不支配的个体当中选出这个 leader 个体呢? 这就需要引入自适应网格算法

自适应网格算法

       ~~~~~~        算法思路: 将所有个体划分在不同的网格里面,再计算网格的密度,密度越小的网格,粒子越稀疏,个体被选择的概率越大(从而保证粒子的分布性)。具体步骤如下:

Step1: 遍历集合种群中的所有个体,分别在每一个目标函数上找出所有个体中的最小值和最大值,如图所示,获得目标函数 f 1 f_1 f1 上的最小值 m i n 1 min_1 min1、最大值 m a x 1 max_1 max1,以及目标函数 f 2 f_2 f2 上的最小值 m i n 2 min_2 min2、最大值 m a x 2 max_2 max2。为了保证边界粒子 x 1 、 x 5 x_1、x_5 x1x5 也能在网格内,需要进行延长操作,把最大最小值根据一定比例稍微延长一点,最后获得网格的边界 L B 1 、 U B 1 、 L B 2 、 U B 2 LB_1、UB_1、LB_2、UB_2 LB1UB1LB2UB2

Step2: 假设设置的参数 n = 3,将网格平均切割成 3 X 3 = 9 个格子

Step3: 摘选出其中有个体的网格,并计算这些网格中存储的个体总数,如:① = 1,② = 1,③ = 1,④ = 2

Step4: 由前面获得的个体数根据公式计算这些网格的被选概率,个体越少被选概率越大,归一化所有网格的被选概率和为 1

Step5: 根据前面计算的概率,采取轮盘赌方法选择一个网格,该网格中的个体作为 gBest 备选集,在备选集中采用随机选择的方法选择其中一个个体作为全局最优 gBest

3. 如何维护 rep (非支配集/归档集) ?

  • 同样可以采取自适应网格算法。即假设在加入新的非支配个体后,rep 库现在的长度是 m ( m > N ) m(m>N) m(m>N),此时我们需要删除 m − N m-N mN 个个体来保证 rep 不溢出。此时只需要通过自适应网格法从 rep 库中选择出一个最差劲个体然后从rep库中删除,如此循环 m − N m-N mN 次,问题迎刃而解
MOPSO 进行了三轮筛选
  1. 首先,根据支配关系进行第一轮筛选,将个体自身与上一次相比的劣解去除,即更新 pbest

  2. 将所有个体根据支配关系进行第二轮筛选,将劣解去除,并加入到 rep 归档集中,并计算个体所处的网格位置

  3. 最后,若归档集数量超过了存档阀值,则根据自适应网格进行筛选删除,直到阀值限额为止,重新进行网格划分。

4. 如何避免算法陷入局部最优?

Step1: 对当前的粒子 x,根据当前迭代次数 It 和最大迭代次数 MaxIt 以及突变率 m 计算扰乱算子 p。

p = ( 1 − ( I t − 1 ) ( M a x I t − 1 ) ) ( 1 / m ) p = ( 1 -\frac{ ( It - 1 ) }{ ( MaxIt - 1 )} )^ {( 1 / m )} p=(1(MaxIt1)(It1))(1/m)

Step2: 获取随机数 rand,如果 rand < p,随机选择粒子的某个决策变量进行变异,其余决策变量不变;若 rand 不小于 p,则保持不变。

Step3: 如果粒子需要变异,首先随机选择到粒子 x 的第 j 个决策变量 x(j),然后根据扰乱算子计算变异范围 d,

d = p ∗ ( V a r M a x − V a r M i n ) ; d = p * (VarMax-VarMin); d=p(VarMaxVarMin);

式中, V a r M a x VarMax VarMax V a r m i n Varmin Varmin 分别是规定的决策变量的最大值和最小值。

Step4: 由 d 计算变异的上下界,上界 U B = x ( j ) + d UB=x(j) + d UB=x(j)+d,下界 L B = x ( j ) − d LB=x(j) - d LB=x(j)d。同时注意越界处理:
U B = m i n ( U B , V a r m a x ) , L B = m a x ( L B , V a r m i n ) UB=min(UB,Var_{max}),LB=max(LB,Var_{min}) UB=min(UB,Varmax),LB=max(LB,Varmin)

Step5: 最后根据变异的范围 [ L B , U B ] [LB,UB] [LB,UB] 随机获取新的 x ( j ) = u n i f r n d ( l b , u b ) x(j)=unifrnd(lb, ub) x(j)=unifrnd(lb,ub) ,即获得区间 ( l b , u b ) (lb,ub) (lb,ub) 中的一个随机数。

Step6: 在粒子变异后,要比较变异后的粒子是否更优秀,如果变异后的粒子更优秀则更新粒子,否则不更新;同样还要比较新的粒子和粒子的 pBest,若新的粒子比 pBest 优秀则更新 pBest,否则不更新。

算法流程

综上可知 MOPSO 算法主要是针对以下一些问题进行研究:

  1. 如何选择 pbest。对于多目标来说两个粒子的对比,并不能对比出哪个好一些。如果粒子的每个目标都要好的话,则该粒子更优。若有些更好,有些更差的话,就无法严格的说哪个好些,哪个差一些。

  2. 如何选择 gbest。对于多目标来说,最优的个体有很多个。该如何选择,涉及到最优个体的存档、存档的管理等问题(多样性/分布性)

  3. 速度更新公式优化;

  4. 位置更新处理;

  5. 增加扰乱算子即变异算子的选择问题,主要是为了解决 PSO 快速收敛到局部最优的问题,增加扰乱可以使得收敛到全局最优

  6. 增加一些其他的操作来改善收敛性和多样性

补充

  • 上述解决方案为较简单的方式,还可以有其他很多方式来解决这三类问题,从而实现不同的算法。
MOPSO 做出的改进方向如下:
  1. 速度更新公式的优化,如:引入了一个收缩因子等

  2. 解决算法快速收敛陷入局部最优的问题,如:变异操作

  3. 算法收敛性和多样性的实现方式,如本文的自适应网格算法;

  4. MOPSO 的存档方法

算法执行图

算法在 ZDT1 测试函数下的执行结果

代码实现

mopso.mlx

Problem Definition

CostFunction = @(x) ZDT(x);      % Cost Function

nVar = 5;             % Number of Decision Variables

VarSize = [1 nVar];   % Size of Decision Variables Matrix

VarMin = 0;          % Lower Bound of Variables
VarMax = 1;          % Upper Bound of Variables

MOPSO Parameters

MaxIt = 200;           % Maximum Number of Iterations

nPop = 200;            % Population Size

nRep = 100;            % Repository Size

w = 0.5;              % Inertia Weight
wdamp = 0.99;         % Intertia Weight Damping Rate
c1 = 1;               % Personal Learning Coefficient
c2 = 2;               % Global Learning Coefficient

nGrid = 7;            % Number of Grids per Dimension
alpha = 0.1;          % Inflation Rate

beta = 2;             % Leader Selection Pressure
gamma = 2;            % Deletion Selection Pressure

mu = 0.1;             % Mutation Rate

Initialization

empty_particle.Position = [];
empty_particle.Velocity = [];
empty_particle.Cost = [];
empty_particle.Best.Position = [];
empty_particle.Best.Cost = [];
empty_particle.IsDominated = [];
empty_particle.GridIndex = [];
empty_particle.GridSubIndex = [];

pop = repmat(empty_particle, nPop, 1);

for i = 1:nPop
    
    pop(i).Position = unifrnd(VarMin, VarMax, VarSize); % 产生范围内的连续随机数
    
    pop(i).Velocity = zeros(VarSize);
    
    pop(i).Cost = CostFunction(pop(i).Position);
    
    
    % Update Personal Best
    pop(i).Best.Position = pop(i).Position;
    pop(i).Best.Cost = pop(i).Cost;
    
end

% Determine Domination
pop = DetermineDomination(pop);

rep = pop(~[pop.IsDominated]); % 选出当前非支配个体

Grid = CreateGrid(rep, nGrid, alpha); % 定义网格

for i = 1:numel(rep)
    rep(i) = FindGridIndex(rep(i), Grid); % 给每个个体分配网格位置
end

MOPSO Main Loop

for it = 1:MaxIt
    
    for i = 1:nPop
        
        leader = SelectLeader(rep, beta); % 轮盘赌选择 gbest
        
        pop(i).Velocity = w*pop(i).Velocity ...
            +c1*rand(VarSize).*(pop(i).Best.Position-pop(i).Position) ...
            +c2*rand(VarSize).*(leader.Position-pop(i).Position);
        
        % 更新位置
        pop(i).Position = pop(i).Position + pop(i).Velocity;
        
        % 越界判断
        pop(i).Position = max(pop(i).Position, VarMin);
        pop(i).Position = min(pop(i).Position, VarMax);
        
        % 计算新的目标值
        pop(i).Cost = CostFunction(pop(i).Position);
        
        if Dominates(pop(i), pop(i).Best) % 如果 i 支配 Best,则更新 Best
            pop(i).Best.Position = pop(i).Position;
            pop(i).Best.Cost = pop(i).Cost;
            
        elseif Dominates(pop(i).Best, pop(i)) % 若 Best 支配 i ,则不更新
            % Do Nothing
            
        else % 若互不支配,则产生随机数判断是否更新
            if rand<0.5
                pop(i).Best.Position = pop(i).Position;
                pop(i).Best.Cost = pop(i).Cost;
            end
        end
        
    end
    
    % Add Non-Dominated Particles to REPOSITORY
    rep = [rep
         pop(~[pop.IsDominated])]; %#ok
    
    % Determine Domination of New Resository Members
    rep = DetermineDomination(rep);
    
    % Keep only Non-Dminated Memebrs in the Repository
    rep = rep(~[rep.IsDominated]);
    
    % Update Grid
    Grid = CreateGrid(rep, nGrid, alpha);

    % Update Grid Indices
    for i = 1:numel(rep)
        rep(i) = FindGridIndex(rep(i), Grid);
    end
    
    % Check if Repository is Full
    if numel(rep)>nRep
        
        Extra = numel(rep)-nRep;
        for e = 1:Extra
            rep = DeleteOneRepMemebr(rep, gamma);
        end
        
    end
    
    % Plot Costs
    figure(1);
    PlotCosts(pop, rep);
    pause(0.01);
    
    % Show Iteration Information
    disp(['Iteration ' num2str(it) ': Number of Rep Members = ' num2str(numel(rep))]);
    
    % Damping Inertia Weight
    w = w*wdamp;
    
end

ZDT.m:测试函数 ZDT1

function z = ZDT(x)
% Function: z = ZDT(x)
%
% Description:  此系列的测试函数总共有 6 个,ZDT1 ~ ZDT6, 属于数值型测试函数,
%               当前实现的测试函数为 ZDT1
%
%
% Syntax:
%   
%
% Parameters:
%   x:决策变量
%
% Return:
%   z:函数结果 f1, f2
%
%                  Young99
%         Revision:    Data: 
%*************************************************************************

    n = numel(x);

    f1 = x(1);
    
    g = 1+9/(n-1)*sum(x(2:end));
    
    h = 1-sqrt(f1/g);
    
    f2 = g*h;
    
    z = [f1
       f2];

end

DetermineDomination.m:判断是否为非支配个体

function pop = DetermineDomination(pop)
% Function: pop = DetermineDomination(pop)
%
% Description: 计算个体之间的支配关系,若被其他个体支配,将 IsDominated 设置为 true
%
%
% Syntax:
%   
%
% Parameters:
%   pop:种群
%
% Return:
%   pop:进行非支配标记后的种群
%
%                  Young99
%         Revision:1.0     Data: 2022-12-07
%*************************************************************************

    nPop = numel(pop);
    
    % 初始化每个个体均为非支配个体
    for i = 1:nPop
        pop(i).IsDominated = false;
    end
    
    % 两两个体比较
    for i = 1:nPop-1
        for j = i+1:nPop
            
            if Dominates(pop(i), pop(j))
               pop(j).IsDominated = true;
            end
            
            if Dominates(pop(j), pop(i))
               pop(i).IsDominated = true;
            end
            
        end
    end

end

Dominates.m:两两个体之间比较大小

function b = Dominates(x, y)
% Function: b = Dominates(x, y)
%
% Description: 比较两个个体的函数值
%
%
% Syntax:
%   
%
% Parameters:
%   pop:种群
%
% Return:
%   b:比较结果,为布尔型
%
%                  Young99
%         Revision:1.0     Data: 2022-12-07
%*************************************************************************
    if isstruct(x)
        x = x.Cost;
    end
    
    if isstruct(y)
        y = y.Cost;
    end

    b = all(x <= y) && any(x<y);

end

CreateGrid.m:创建自适应网格

function Grid = CreateGrid(pop, nGrid, alpha)
% Function: Grid = CreateGrid(pop, nGrid, alpha)
%
% Description: 为每一个目标函数,选出 pop 中个体目标函数值的最小及最大值
%              将最小最大值利用 alpha 参数扩展一定的范围,作为当前维度网格的上下限
%
%
% Syntax:
%   
%
% Parameters:
%   pop:rep 即为当前轮的非支配个体
%   nGrid:网格的维度大小
%   alpha:自定义参数,用于调整网格的最大最小上下线
%
% Return:
%   Grid:定义后的网格
%
%                  Young99
%         Revision:1.0     Data: 2022-12-07
%*************************************************************************

    c = [pop.Cost];
    
    cmin = min(c, [], 2);
    cmax = max(c, [], 2);
    
    dc = cmax-cmin;
    cmin = cmin-alpha*dc;
    cmax = cmax+alpha*dc;
    
    nObj = size(c, 1);
    
    empty_grid.LB = [];
    empty_grid.UB = [];
    Grid = repmat(empty_grid, nObj, 1);
    
    for j = 1:nObj
        
        cj = linspace(cmin(j), cmax(j), nGrid+1);
        
        Grid(j).LB = [-inf cj];
        Grid(j).UB = [cj +inf];
        
    end

end

FindGridIndex.m:为每个个体确定在网格中的位置

function particle = FindGridIndex(particle, Grid)
% Function: particle = FindGridIndex(particle, Grid)
%
% Description: 为 rep 中的每个个体划分所在的网格,其中 
%              GridSubIndex 表示每维目标所对应的网格位置
%              GridIndex 表示将 GridSubIndex 归并为一个数来表示
%
%
% Syntax:
%   
%
% Parameters:
%   particle:当前非支配集中的一个个体
%   Grid:已经划分好的网格,用于自适应网格算法
%
% Return:
%   particle:划分到对应网格后的个体
%
%                  Young99
%         Revision:1.0     Data: 2022-12-07
%*************************************************************************
    nObj = numel(particle.Cost);
    
    nGrid = numel(Grid(1).LB);
    
    particle.GridSubIndex = zeros(1, nObj);
    
    for j = 1:nObj
        
        particle.GridSubIndex(j) = ...
            find(particle.Cost(j)<Grid(j).UB, 1, 'first');
        
    end
    
    % 将高维转化为一维的空间索引
    particle.GridIndex = particle.GridSubIndex(1);
    for j = 2:nObj
        particle.GridIndex = particle.GridIndex-1;
        particle.GridIndex = nGrid*particle.GridIndex;
        particle.GridIndex = particle.GridIndex+particle.GridSubIndex(j);
    end
    
end

SelectLeader.m:利用网格聚集密度选择 gBest

function leader = SelectLeader(rep, beta)
% Function: leader = SelectLeader(rep, beta)
%
% Description: 利用轮盘赌选出其中一个网格,网格聚集密度越小,越容易被选中,
%              再在选中的网格中随机选出一个个体作为 leader 即 gbest
%
%
% Syntax:
%   
%
% Parameters:
%   rep:当前迭代的非支配个体
%   beta:自定义参数
%
% Return:
%   leader:被选中的 gbest 
%
%                  Young99
%         Revision:1.0     Data: 2022-12-07
%*************************************************************************


    % Grid Index of All Repository Members
    GI = [rep.GridIndex];
    
    % Occupied Cells
    OC = unique(GI);
    
    % Number of Particles in Occupied Cells
    N = zeros(size(OC));
    for k = 1:numel(OC)
        N(k) = numel(find(GI == OC(k)));
    end
    
    % Selection Probabilities
    P = exp(-beta*N);  % 注意这是有负数,表示个体数越多的网格被选择的概率越小
    P = P/sum(P); % 转化为和为 1 的概率
    
    % Selected Cell Index
    sci = RouletteWheelSelection(P);
    
    % Selected Cell
    sc = OC(sci);
    
    % Selected Cell Members
    SCM = find(GI == sc);
    
    % Selected Member Index,random selection
    smi = randi([1 numel(SCM)]);
    
    % Selected Member
    sm = SCM(smi);
    
    % Leader
    leader = rep(sm);

end

RouletteWheelSelection.m: 轮盘赌

function i = RouletteWheelSelection(P)
% 轮盘赌用于选择某个网格
    r = rand;
    
    C = cumsum(P);
    
    i = find(r <= C, 1, 'first');

end

DeleteOneRepMemebr.m:当 rep 超出阈值,进行删除操作

function rep = DeleteOneRepMemebr(rep, gamma)
% Function: rep = DeleteOneRepMemebr(rep, gamma)
%
% Description: 利用轮盘赌选出其中一个网格,网格聚集密度越大,越容易被选中,
%              再在选中的网格中随机选出一个个体删除
%
%
% Syntax:
%   
%
% Parameters:
%   rep:当前迭代的非支配个体
%   beta:自定义参数
%
% Return:
%   leader:被选中的 gbest 
%
%                  Young99
%         Revision:1.0     Data: 2022-12-07
%*************************************************************************
    % Grid Index of All Repository Members
    GI = [rep.GridIndex];
    
    % Occupied Cells
    OC = unique(GI);
    
    % Number of Particles in Occupied Cells
    N = zeros(size(OC));
    for k = 1:numel(OC)
        N(k) = numel(find(GI == OC(k)));
    end
    
    % Selection Probabilities
    P = exp(gamma*N);
    P = P/sum(P);
    
    % Selected Cell Index
    sci = RouletteWheelSelection(P);
    
    % Selected Cell
    sc = OC(sci);
    
    % Selected Cell Members
    SCM = find(GI == sc);
    
    % Selected Member Index
    smi = randi([1 numel(SCM)]);
    
    % Selected Member
    sm = SCM(smi);
    
    % Delete Selected Member
    rep(sm) = [];

end

PlotCosts.m:画图可视化

function PlotCosts(pop, rep)

    pop_costs = [pop.Cost];
    plot(pop_costs(1, :), pop_costs(2, :), 'ko');
    hold on;
    
    rep_costs = [rep.Cost];
    plot(rep_costs(1, :), rep_costs(2, :), 'r*');
    
    xlabel('1^{st} Objective');
    ylabel('2^{nd} Objective');
    
    grid on;
    
    hold off;

end

部分理论来源于网络,如有侵权请联系删除。

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

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

相关文章

一个简单的WEB网页制作作业——黑色的山河旅行社网站(5个页面)HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

2022年各国程序员编程水平排行榜出炉,排名第一的国家没听说过

哪个地方的程序员编程水平最高&#xff1f;相信很多人对这个问题感兴趣&#xff0c;今天就来聊一聊这个话题。 Pentalog 是一个全球数字服务平台&#xff0c;主要帮助企业寻找世界上一流的IT人才&#xff0c;每年都会发布一份全球IT行业报告&#xff0c;今天文章的数据也是来自…

单片机控制马达驱动IC的应用

8位机最常见的应用单片机驱动马达IC工作&#xff0c;马达可支持无级调速&#xff08;PWM&#xff09;&#xff0c;正转&#xff0c;反转&#xff0c;刹车。该应用简单高效适应于各种应用&#xff0c;节约成本的不二选择。 今天就跟大家分享曾经做过的马达驱动IC的应用。 主电…

类的加载器

文章目录1. 概述1.1 大厂面试题1.2 类加载的分类1.3 类加载器的必要性1.4 命名空间1.5 类加载机制的基本特征2. 类的加载器分类2.1 引导类加载器2.2 扩展类加载器2.3 系统类加载器2.4 用户自定义类加载器3. 测试不同的类的加载器4. ClassLoader源码解析4.1 ClassLoader的主要方…

测量电源纹波-正确测量方法

测量纹波需要注意的点&#xff1a; 1、用弹簧探针&#xff1b; 2、测量位置在输出电容两端&#xff1b; 3、示波器选择‘20M’&#xff1b; 4、示波器选择‘交流耦合’&#xff1b; 5、示波器探头‘X1’&#xff0c;示波器设置‘X1’&#xff1b;(10:1的探头&#xff0c;实际上…

Stable Diffusion V2.1非标准分辨率图像高清渲染

Stable Diffusion V2.1非标准分辨率图像高清渲染 Stable Diffusion V2.1发布&#xff0c;支持非标准分辨率图像高清渲染。 SD2.1在线体验 在线体验地址:Stable Diffusion 模型包括&#xff1a; NovelAI&#xff0c;NovelAI的模型训练使用了数千个网站的数十亿张图片&#xf…

如何给图片加水印?分享怎么给图片加水印的方法

当我们在平台上发布自己精心拍摄的照片&#xff0c;或分享自己总结的知识点时&#xff0c;难免会遇到一些人盗用自己图片的情况。这时候&#xff0c;我们就会给图片添加上水印&#xff0c;从而来防止自己的图片被盗&#xff0c;那要怎么给图片加水印呢&#xff1f;别着急&#…

《自己动手写CPU》学习记录(3)——第4章/Part 1

目录 引言 致谢 平台 ori 指令 流水线结构建立 模型 简单的MIPS五级流水线结构 设计 宏定义 程序计数器 译码 通用寄存器 指令执行 内存访问 指令ROM 顶层文件 处理器顶层 SOPC顶层 功能仿真 TestBench 仿真结果 执行时间 时序细节 引言 本篇学习书本…

Java大型企业进销存系统源码带文字搭建教程

技术架构 技术框架&#xff1a;SpringBoot Spring Data Jpa SpringMvc Shiro安全认证 完整权限系统 easyui 运行环境&#xff1a;jdk8 IntelliJ IDEA maven 宝塔面板 本地搭建教程&#xff1a; 1.下载源码&#xff0c;小皮面板创建一个数据库&#xff0c;导入db_jxc2.…

nodejs模板引擎的使用

前后端不分离的情况(数据都来源于后端,前后端不可以分离使用) npm i express art-template express-art-template --S 先下载模板引擎,模板渲染,还有experss服务器的包 js代码 //导入express服务器第三方的包 const express require("express") //导入模板引擎 con…

Spring Cloud(十六):微服务分布式唯一ID

分布式唯一ID 特点方案 雪花算法 特点开源实现优缺点 替代方案 UUIDMongdbSeata数据库生成Redis 基于美团的 Leaf分布式 ID 微服务 Leaf-segment 数据库方案 双 buffer 优化 — TP999 数据波动大 Leaf 高可用容灾 — DB 可用性Leaf-snowflake 雪花方案 弱依赖 ZooKeeper 解决时…

加减大师-第10届蓝桥杯Scratch选拔赛真题精选

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第98讲。 蓝桥杯选拔赛每一届都要举行4~5次&#xff0c;和省赛、国赛相比&#xff0c;题目要简单不少&#xff0c;再加上篇幅有限&#xff0c;因此我精挑细选…

Vue学习笔记--第一章(尚硅谷学习视频总结)

目录 一、第一章 Vue核心 1.1. Vue简介 1.1.1. 官网 1.1.2. 介绍与描述 1.1.3. Vue 的特点 1.1.4. 与其它 JS 框架的关联 1.1.5. Vue 周边库 1.2.初识Vue 1.3. 模板语法 1.4. 数据绑定 1.5 el与data的两种写法 1.6 MVVM模型 1.7 Vue中的数据代理 1.8.事件处理 1.…

从零学习 InfiniBand-network架构(九) —— IB协议中子网本地地址

从零学习 InfiniBand-network架构&#xff08;九&#xff09; —— IB协议中子网本地地址 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN主页 &#x1f511;未经作者允许&#xff0c;禁止转载 &#x1f6a9;本专题部分内容源于《InfiniBand-n…

鸿蒙3.0应用开发若干问题及上架总结

1.如何去掉默认标题栏&#xff0c;实现全屏显示&#xff1f; 在config.json中的ability配置信息中添加属性&#xff1a; "abilities": [ {..."metaData": {"customizeData": [{"name": "hwc-theme","value": &q…

Buildroot系列开发(五)bootloader简述

参考&#xff1a;百问网 文章目录1.什么是Boot-loader?2.有哪些bootloader?哪些支持linux&#xff1f;3.Bootloader支持的Flash设备4.Bootloader支持的文件系统类型4.Bootloader支持的CPU架构5.Bootloader总结1.什么是Boot-loader? 2.有哪些bootloader?哪些支持linux&#…

广州蓝景分享——前端学习5 种在 JavaScript 中获取字符串第一个字符的方法

在本文中&#xff0c;我们将研究多种方法来轻松获取 JavaScript 中字符串的第一个字符。 1.charAt() 方法 要获取字符串的第一个字符&#xff0c;我们可以在字符串上调用 charAt() &#xff0c;将 0 作为参数传递。例如&#xff0c;str.charAt(0) 返回 str 的第一个字符。 c…

AT1106S(PHS/EN输入接口通道0.8A低压H桥直流刷式电机驱动IC)

描述 泛海微AT1106S为摄像机、消费类产品、玩具和其它低电压或者电池供电的运动控制类应用提供了一个集成的电机驱动器解决方案。泛海微AT1106S能够驱动一个直流电机或其他诸 如螺线管的器件。输出驱动模块由N MOS功率管构成的H桥组成&#xff0c;以驱动电机绕组。泛海微AT110…

车企接连押注「重感知」 ,高精地图真会被弃用?

实现高阶智能驾驶&#xff0c;“重感知”是否为大势所趋&#xff1f; 答案正日益明晰。 2022年&#xff0c;以特斯拉为代表的“重感知”阵营&#xff0c;押注者正日趋增多。以在2022年尝试落地城市NOA的三家厂商为例&#xff1a;毫末智行一早便属“重感知”阵营&#xff1b;小…

【20221208】【每日一题】目标和

给你一个整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 &#xff0c;在 1 之前添加 - &#xff0c;然后串…