遗传算法(GA)

news2024/10/5 14:05:07

理论:

遗传算法是一种通过模拟生物进化的方式来寻找最优解的一类优化算法。这种算法主要依靠遗传、突变和自然选择的机制对问题求解进行高效的迭代搜索。

遗传算法的基本思想是将问题的解表示成一个个个体,然后根据适应度函数的定义来评估每个个体的适应性并确定其在繁殖中的概率。经过交叉与变异等操作,新的代替原有的个体,继续与其他生成的个体竞争下去。这一过程不断迭代直至找到最优解或达到迭代次数上限。

遗传算法具有全局搜索能力强、对复杂非线性问题较为适用、支持并行优化计算等特点,在许多领域中得到了广泛的应用,如机器学习、图像处理、网络优化、工程设计等等。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
顺时针转动:0.2 0.1 0.4 0.3
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从区间[0,1]随机产生4个随机数:R1=45.3% ,14.7%<45.3%<64.79,所以选择个体2
为了避免陷入局部最优的情况,我们通常会按照一定的概率对少量个体进行变异操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:遗传算法是通过对种群个体迭代的复制、交叉、变异的过程,是新种群继承父带种群的优良特征,而不断完善和优化的过程,我们将它称为遗传算法。

遗传算法中对个体操作有哪些?

在遗传算法中,对个体的操作主要包括选择、交叉和变异三种类型。以下是对这三种操作的简要介绍:

  1. 选择(Selection):根据适应度函数,从种群中选择一部分个体作为下一代的父代。选择的方式一般有轮盘赌选择、竞赛选择、锦标赛选择等。

  2. 交叉(Crossover):将上一步选择出的父代个体进行交叉,生成新的子代个体。交叉的方式有单点交叉、多点交叉、均匀交叉等。

  3. 变异(Mutation):在交叉后生成的子代个体中,以一定的概率对某些基因进行变异操作,引入新的遗传信息。变异一般采用随机的方式,如单点变异、多点变异、位变异等。

以上三种操作结合起来,就可以产生出一组新的个体来进行下一代的优化。在遗传算法中,这些操作的选择和调整会影响算法的搜索效率和结果质量。

遗传算法中对种群操作有哪些?

在遗传算法中,对种群的操作主要包括初始化和淘汰两类。

  1. 初始化(Initialization):在遗传算法开始前,需要先生成一个初始的种群。一般来说,这个种群是由一些随机的个体组成的。随机程度要适当,不能过于杂乱,也不能过于单一。

  2. 淘汰(Survival of the fittest):在遗传算法的迭代过程中,需要通过一些策略对种群进行淘汰,以避免种群陷入局部最优解。常见的淘汰策略有精英保留、种群大小控制、截断选择等。

其中,精英保留的策略是将前几代中表现最好的个体直接留用到下一代种群中,以保持种群中的优秀个体,提升算法的搜索效率。

种群大小控制的策略是设定一个种群大小的上限,当种群中个体数目超过这个数值时,需要淘汰一部分个体,保持种群规模的合适。

截断选择的策略是按一定比例将个体按照适应度的大小从高到低排序,只保留前面的几个个体,淘汰后面的个体。

对种群操作要灵活,不同的问题需要采用不同的操作策略。

算法:

Individual


public class Individual {
	private int[] chromosome;	// chromosome染色体
	private double fitness = -1;

	public Individual(int[] chromosome) {
		// 创造单个染色体
		this.chromosome = chromosome;
	}

	public Individual(int chromosomeLength) {	// 初始化随机个体

		this.chromosome = new int[chromosomeLength];
		for (int gene = 0; gene < chromosomeLength; gene++) {
			if (0.7 < Math.random()) {
				this.setGene(gene, 2);
			} else if(0.4 < Math.random()){
				this.setGene(gene, 1);
			}
			else
			{
				this.setGene(gene, 0);
			}
		}

	}

	public int[] getChromosome() {	// 获得个体的染色体
		return this.chromosome;
	}

	public int getChromosomeLength() {	 // 得到个体的染色体长度
		return this.chromosome.length;
	}

	public void setGene(int offset, int gene) {	 // 将基因置于偏移位置
		this.chromosome[offset] = gene;
	}

	public int getGene(int offset) {	// 获得基因偏移
		return this.chromosome[offset];
	}

	public void setFitness(double fitness) {	// 储存个体适合度
		this.fitness = fitness;
	}

	public double getFitness() {	// 得到个体的适合度
		return this.fitness;
	}
	
	public String toString() {	// 将染色体显示为字符串。
		String output = "";
		for (int gene = 0; gene < this.chromosome.length; gene++) {
			output += this.chromosome[gene];
		}
		return output;	// 染色体的字符串表示
	}
}

Population

import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;


// 种群是个体的抽象集合。人口类通常用于对其个人执行组级操作,比如找到最强壮的个体,收集种群的统计数据作为一个整体,选择个体进行变异或交叉。

public class Population {
	private Individual population[];
	private double populationFitness = -1;

	
	public Population(int populationSize) {		// 种群中个体的数量
		this.population = new Individual[populationSize];
	}

	public Population(int populationSize, int chromosomeLength) {	// 种群中个体的数量   染色体长度
		// 将种群初始化为个体数组
		this.population = new Individual[populationSize];

		// 依次创建每个个体
		for (int individualCount = 0; individualCount < populationSize; individualCount++) {
			// 创建一个个体,将其染色体初始化为给定的
			Individual individual = new Individual(chromosomeLength);
			// 将个体添加到种群中
			this.population[individualCount] = individual;
		}
	}

	public Individual[] getIndividuals() {		// 从种群中挑选个体
		return this.population;
	}

	/**
	 * 根据适应度在种群中找到一个个体
	 * 
		根据适应度在种群中找到一个个体。
		这个方法可以让你按照适合度的顺序选择个体。
		这可以用来表示最强壮的个体(例如,如果你是。测试解决方案),但它也可以用来寻找弱势个体(如果你想剔除种群)或者一些最强的个人(如果你用的是“精英主义”的话)。
	 * 
	 * @param offset
	 *            The offset of the individual you want, sorted by fitness. 0 is
	 *            the strongest, population.length - 1 is the weakest.
	 *            你想要的个体的偏移量,根据适应度排序。0是最强的,人口。长度- 1是最弱的。
	 * @return individual Individual at offset
	 */
	
	public Individual getFittest(int offset) {
		// 适应度排序种群
		Arrays.sort(this.population, new Comparator<Individual>() {
			@Override
			public int compare(Individual o1, Individual o2) {
				if (o1.getFitness() > o2.getFitness()) {
					return -1;
				} else if (o1.getFitness() < o2.getFitness()) {
					return 1;
				}
				return 0;
			}
		});

		return this.population[offset];	 // 返回最适合的个体
	}

	public void setPopulationFitness(double fitness) {	// 设置种群的群体适应度
		this.populationFitness = fitness;
	}

	public double getPopulationFitness() {	// 得到种群的群体适应度
		return this.populationFitness;
	}

	public int size() {		// 得到种群的规模
		return this.population.length;
	}

	public Individual setIndividual(int offset, Individual individual) {	// 设置个体的偏移量
		return population[offset] = individual;
	}

	public Individual getIndividual(int offset) {
		return population[offset];
	}
	
	public void shuffle() {		// 变换位置
		Random rnd = new Random();
		for (int i = population.length - 1; i > 0; i--) {
			int index = rnd.nextInt(i + 1);
			Individual a = population[index];
			population[index] = population[i];
			population[i] = a;
		}
	}
}

GeneticAlgorithm

import java.util.ArrayList;
import java.util.List;

import org.cloudbus.cloudsim.CloudletSchedulerTimeShared;
import org.cloudbus.cloudsim.UtilizationModel;
import org.cloudbus.cloudsim.UtilizationModelFull;

public class GeneticAlgorithm {
	private int populationSize;		// 种群规模

	private double mutationRate; 	// 突变率
	
	private double crossoverRate;	// 交叉
	
	private int elitismCount;	// 精英数

	public GeneticAlgorithm(int populationSize, double mutationRate, double crossoverRate, int elitismCount) {
		this.populationSize = populationSize;
		this.mutationRate = mutationRate;
		this.crossoverRate = crossoverRate;
		this.elitismCount = elitismCount;
	}

	public Population initPopulation(int chromosomeLength) {
		// Initialize population  初始化种群数
		Population population = new Population(this.populationSize, chromosomeLength);
		return population;
	}

	public double calcFitness(Individual individual) {	// 计算个体的适应度
		ArrayList<vm3> vmlist = new ArrayList<vm3>();

		//VM description
		int vmid = 0;
		int mips = 250;
		long size = 10000; //image size (MB)
		int ram = 2048; //vm memory (MB)
		long bw = 1000;
		int pesNumber = 1; //number of cpus
		String vmm = "Xen"; //VMM name
		double[] executioncost1= {1.23,1.12,1.15};

		int[] datasize1= {30,30};
		vm3 Vm1 = new vm3(vmid, brokerId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared(), executioncost1, datasize1);

		// the second VM will have twice the priority of VM1 and so will receive twice CPU time
		// 第二个VM的优先级将是VM1的两倍,因此将获得两倍的CPU时间
		
		vmid++;
		double[] executioncost2= {1.17,1.17,1.28};
		int[] datasize2= {10,10};
		vm3 Vm2 = new vm3(vmid, brokerId, mips , pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared(), executioncost2, datasize2);
		vmid++;
		double[] executioncost3= {1.13,1.11,1.11};
		int[] datasize3= {10,10};
		vm3 Vm3 = new vm3(vmid, brokerId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared(), executioncost3, datasize3);
		vmid++;
		double[] executioncost4= {1.26,1.12,1.14};
		int[] datasize4= {10,10};
		vm3 Vm4 = new vm3(vmid, brokerId, mips , pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared(), executioncost4, datasize4);
		vmid++;
		double[] executioncost5= {1.19,1.14,1.22};
		int[] datasize5= {10,10};
		vm3 Vm5 = new vm3(vmid, brokerId, mips , pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared(), executioncost5, datasize5);

		//add the VMs to the vmList
		vmlist.add(Vm1);
		vmlist.add(Vm2);
		vmlist.add(Vm3);
		vmlist.add(Vm4);
		vmlist.add(Vm5);
		
		//submit vm list to the broker
		broker.submitVmList(vmlist);

		// properties 属性
		int id = 0;
		long length = 40000;
		long fileSize = 300;
		long outputSize = 300;
		UtilizationModel utilizationModel = new UtilizationModelFull();
		
        double[] comcost1= {0.00,0.17,0.21};
        
		cloudlet3 Cloudlet1 = new cloudlet3(id, length, pesNumber, fileSize, outputSize, utilizationModel, utilizationModel, utilizationModel, comcost1);
		Cloudlet1.setUserId(brokerId);

		id++;
		double[] comcost2= {0.17,0.00,0.22};
		
		cloudlet3 Cloudlet2 = new cloudlet3(id, length, pesNumber, fileSize, outputSize, utilizationModel, utilizationModel, utilizationModel, comcost2);
		Cloudlet2.setUserId(brokerId);

		id++;
		double[] comcost3= {0.21,0.22,0.00};
		
		cloudlet3 Cloudlet3 = new cloudlet3(id, length, pesNumber, fileSize, outputSize, utilizationModel, utilizationModel, utilizationModel, comcost3);
		Cloudlet3.setUserId(brokerId);
		List<cloudlet3> cloudletList=new ArrayList<cloudlet3>();

		//将Cloudlet添加到列表中
		cloudletList.add(Cloudlet1);
		cloudletList.add(Cloudlet2);
		cloudletList.add(Cloudlet3);

		// 正确基因的轨迹数
		double cost = 0.0;

		// 计算的成本
		for (int geneIndex = 0; geneIndex < individual.getChromosomeLength(); geneIndex++) {
			// 每找到一个“1”,就增加一个适应度点
			cost=cost+vmlist[geneIndex].executioncost[individual[geneIndex]];
		}
		//	通信成本
		for(int geneIndex = 1; geneIndex < individual.getChromosomeLength(); geneIndex++)
		{
			cost=cost+cloudletList[individual[geneIndex]].comcost[individual[geneIndex-1]]*vmlist[geneIndex].datasize[0];
		}

		// 计算适应度
		double fitness = (double) cost;

		// 存储适应度
		individual.setFitness(fitness);

		return fitness;
	}

	// 本质上,就是循环遍历种群中的个体,计算每个个体的适应度,然后计算整个种群的适应度。种群的适合度可能重要也可能不重要,但重要的是确保每个个体都得到评估。
	public void evalPopulation(Population population) {		// 评估整个群体
		double populationFitness = 0;

		// 在种群上循环评估个体和种群适应度
		for (Individual individual : population.getIndividuals()) {
			populationFitness += calcFitness(individual);
		}

		population.setPopulationFitness(populationFitness);
	}

	/**
	 * 检查种群是否满足终止条件
	 * 
	 * 对于这个简单的问题,我们知道完美的解决方案是什么样子的,所以我们可以简单地停止进化,一旦我们达到了一个适应度。
	 * 
	 * @param population
	 * @return boolean True if termination condition met, otherwise, false
	 */
	
	/**
	 * Select parent for crossover	选择父级进行交叉
	 * 
	 * @param population
	 *            The population to select parent from
	 * @return The individual selected as a parent
	 */
	public Individual selectParent(Population population) {
		// Get individuals
		Individual individuals[] = population.getIndividuals();

		// 旋转轮盘赌
		double populationFitness = population.getPopulationFitness();
		double rouletteWheelPosition = Math.random() * populationFitness;

		// Find parent
		double spinWheel = 0;
		for (Individual individual : individuals) {
			spinWheel += individual.getFitness();
			if (spinWheel >= rouletteWheelPosition) {
				return individual;
			}
		}
		return individuals[population.size() - 1];
	}

	/**
	 * Apply crossover to population	将交叉应用于种群
	 * 
	 * 
	 * 
	 * @param population
	 *            The population to apply crossover to
	 * @return The new population
	 */
	public Population crossoverPopulation(Population population) {
		// 创造新种群
		Population newPopulation = new Population(population.size());

		// 根据适应度对当前种群进行循环
		for (int populationIndex = 0; populationIndex < population.size(); populationIndex++) {
			Individual parent1 = population.getFittest(populationIndex);

			// 把交叉应用到个体身上
			if (this.crossoverRate > Math.random() && populationIndex >= this.elitismCount) {
				// 初始化的后代
				Individual offspring = new Individual(parent1.getChromosomeLength());
				
				// Find second parent
				Individual parent2 = selectParent(population);

				// 基因组环
				for (int geneIndex = 0; geneIndex < parent1.getChromosomeLength(); geneIndex++) {
					// Use half of parent1's genes and half of parent2's genes
					if (0.5 > Math.random()) {
						offspring.setGene(geneIndex, parent1.getGene(geneIndex));
					} else {
						offspring.setGene(geneIndex, parent2.getGene(geneIndex));
					}
				}

				// 给新种群增加后代
				newPopulation.setIndividual(populationIndex, offspring);
			} else {
				// 在不使用交叉的情况下将个体添加到新种群中
				newPopulation.setIndividual(populationIndex, parent1);
			}
		}

		return newPopulation;
	}

	/**
	 * 将突变应用于种群
	 * 
	 * This method will consider the GeneticAlgorithm instance's mutationRate
	 * and elitismCount
	 * 
	 * @param population
	 *            The population to apply mutation to
	 * @return The mutated population
	 */
	public Population mutatePopulation(Population population) {
		// 初始化新种群
		Population newPopulation = new Population(this.populationSize);

		// 根据适应度对当前种群进行循环
		for (int populationIndex = 0; populationIndex < population.size(); populationIndex++) {
			Individual individual = population.getFittest(populationIndex);

			// 在个体基因上进行循环
			for (int geneIndex = 0; geneIndex < individual.getChromosomeLength(); geneIndex++) {
				// 如果这是一个精英个体,跳过突变
				if (populationIndex > this.elitismCount) {
					// Does this gene need mutation?
					if (this.mutationRate > Math.random()) {
						// 获得新基因
						int newGene = 1;
						if (individual.getGene(geneIndex) == 1) {
							newGene = 0;
						}
						// 变异的基因
						individual.setGene(geneIndex, newGene);
					}
				}
			}

			// 将个体添加到种群中
			newPopulation.setIndividual(populationIndex, individual);
		}

		// 返回突变种群
		return newPopulation;
	}

}

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

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

相关文章

【数组排序算法】

目录 一、数组排序算法1、冒泡排序算法1.1、图形解释1.2、冒泡算法的脚本写法 二、直接选择排序1.1、动态图解1.2、直接选择排序算法的脚本编写 三、直接插入排序1.1、基本思想&#xff1a;1.2、动态图解1.3、直接插入排序的算法脚本编写 四、反向序列算法1.1、反向序列算法的脚…

linux:文件替换的三种方式sed、awk、perl

文章目录 背景sed语法问题1、加个空字符串2、下载gnu-sed awk语法举例 perl语法示例 总结 背景 linux 文件内容替换&#xff0c;网上看了下大致就这三种 sed、awk、perl&#xff0c;今天挨个使用一下看看怎么样 sed 语法 Linux sed 命令是利用脚本来处理文本文件。详细文档…

网络基础认知(上)

如今使用过计算机的人们都接触过网络&#xff0c;但是网络究竟是什么&#xff0c;计算机又是怎样通过网络来进行互相之间通信的&#xff0c;这还需要我们深入了解。 目录 网络发展 初识协议 什么是协议 为什么需要协议&#xff1f; 网络协议初识 协议分层 为什么网络协议要…

澳鹏与Reka AI强强联合,构建高质量的多模态LLM应用

近日&#xff0c;澳鹏Appen官宣与AI新兴公司Reka AI合作&#xff0c;以实现世界级数据服务与多模态语言模型的结合。 ChatGPT等创新应用的崛起让大型语言模型&#xff08;LLM&#xff09;实现了突飞猛进的发展。LLM可以助力企业提升运营效率&#xff0c;并为最终用户提供耳目一…

Java基础--->JVM(3)【垃圾回收】

文章目录 垃圾回收&#xff08;GC&#xff09;什么内存需要回收&#xff08;什么样的对象是垃圾&#xff09;&#xff1f;为什么要进行垃圾回收&#xff1f;内存溢出和内存泄露的区别&#xff0c;如何解决分区收集思想 Minor GC、Major GC、Full GC垃圾回收相关算法引用计数算法…

如何搭建产品操作手册

对于企业来说&#xff0c;拥有一份完备的产品操作手册无疑是至关重要的。操作手册不仅是新员工学习产品使用及维护的重要参考&#xff0c;也是产品售后服务与客户支持的必备文件。在手册编写上&#xff0c;应清晰明了地介绍产品的功能、配置及故障排除等信息&#xff0c;使用户…

统计学下的假设检验

由于本人才疏学浅&#xff0c;再加上时间仓促&#xff0c;难免有疏漏之处&#xff0c;恳请批评指正. 1,预备知识 数理统计&#xff1a;以概率论为基础&#xff0c;研究如何有效的去搜集、整理、分析带随机性影响的数据 总体与样本&#xff1a;研究对象的全体就称为总体 样本&a…

VTK交互-vtkBoxWidget2

VTK交互Widget widget包含两个重要的组成部分&#xff1a;Interaction和Representation. Interaction是一些名叫vtk*Widget的类&#xff08;比如vtkBoxWidget2&#xff09;。它包含了交互的所有选项和事件处理。 Representation是显示并与之交互的一类对象&#xff0c;以名叫v…

origin 拟合计算酶的Kcat Km 值

origin拟合计算Kcat Km值 横坐标为底物浓度&#xff0c;纵坐标为反应速率 全选X 与Y坐标数据&#xff0c;然后选择菜单栏Analysis: Fitting: Nonlinear Curve Fit&#xff1a;Open Dialog 在Setting&#xff1a;Function Selection页面内的Category选择Pharmacology, Functi…

计算机网络基础知识(三)—— 什么是OSI七层模型?

文章目录 00 | &#x1f6f8;发展史&#x1f6f8;01 | &#x1f6f8;OSI七层参考模型&#x1f6f8;02 | &#x1f6f8;OSI七层参考模型的信息流向&#x1f6f8; OSI七层模型是Open Systems Interconnection Reference Model的缩写&#xff0c;是由国际标准化组织&#xff08;IS…

vue3使用keep-alive组件,包含动态组件使用

vue3使用keep-alive组件&#xff0c;包含动态组件使用 本文目录 vue3使用keep-alive组件&#xff0c;包含动态组件使用组件不使用keep-alive组件中使用v-if切换component动态组件切换因注释导致的意外错误动态组件的使用完整示例 路由不使用keep-alive路由中使用keep-alive生命…

公司数字化转型,如何选择高效的知识管理工具?

随着企业数字化转型的加速&#xff0c;知识管理工具的重要性也日益凸显。好的知识管理工具可以帮助企业提高工作效率、降低成本、提高创新能力和竞争力。但是&#xff0c;市场上的知识管理工具繁多&#xff0c;如何选择高效的知识管理工具成为了企业面临的一大难题。本文将从以…

Jenkins 入门系列之Role-based Strategy配置Gitlab Group管理用户组

目录 背景步骤1. 安装插件2. 配置Gitlab Group3. 配置 Jenkins 授权策略4. 配置 Jenkins 角色与授权5. 验证 背景 版本 Jenkins Version&#xff1a;Jenkins 2.403Gitlab Version: Gitlab 15.6部署环境&#xff1a;群晖NAS Docker 部署JenkinsGitlab 上一篇文章Jenkins 入门…

HTML详解

HTML是什么 html是一门语言&#xff0c;所有的网页都是用它编写出来的。 他是一门超文本标记语言。可以定义图片&#xff0c;音频&#xff0c;视频等。由标签组成。 HTMl仅仅定义了网站的接口。 具体的表现还需要css来实现&#xff0c;也就是css让网页变得更加好看。 网页…

智能聊天机器人ChatGPT商业版

作为一个智能聊天机器人&#xff0c;我是由OpenAI开发的。目前&#xff0c;我的商业版需要通过OpenAI的合作伙伴计划进行许可和部署&#xff0c;以确保我被用于适当的商业用途。如果您对商业使用感兴趣&#xff0c;请联系OpenAI以获取更多信息。 智能聊天机器人是一种能够自…

如何优化golang gc

目录 一.理解GO GC机制 1.1GC的耗时 1.2堆大小对GC的影响 1.3GC算法 二 如何查看GC信息 2.1使用GODEBUG"gotrace1" 2.2 go tool trace 2.3 debug.ReadGCStats ​编辑2.4 runtime.ReadMemStats 三 GC优化技巧 2.1并发GC 一.理解GO GC机制 GO语言采用的是三…

学习网络安全的拦路虎!你遇到几个?

很多零基础的同学想要学习网络安全&#xff0c;前期会各种寻找学习资料。最后发现资料一大堆&#xff0c;但无从下手&#xff0c;于是千辛万苦收集的资料就去收藏夹吃灰了。开始学习的小伙伴们通常也会越学越迷茫&#xff0c;毕竟资料并不是完整的&#xff0c;而是东拼西凑出来…

Docker时区问题

背景 当前docker容器技术应用越来越广泛&#xff0c;但在启动容器后&#xff0c;容器内部的时间并不是东八区 Docker的基础镜像设置大多是UTC&#xff0c;也就是标准的UTC 时间&#xff0c;所以要简单的调整一下&#xff0c;变成中国标准时间CST(China Standard Time UTC8:0…

OpenCL编程指南-1.2OpenCL图形API

OpenCL与图形 OpenCL的出现是对GPCPU编程的一个响应。人们用GPU处理图形&#xff0c;并且开始使用GPU完成工作中的非图形部分。基于这种趋势&#xff0c;异构计算&#xff08;已经存在很长时间&#xff09;与图形发生冲突&#xff0c;因此迫切需要一个行业标准。 OpenCL一直与…

使用Onenote进行钓鱼攻击事件分析

以其中遇到的一个案例为例子进行展开分析: 1、使用钓鱼邮件文案.one文件附件 From: Bank Complaints <bankcomplaintshkmagov.com> Sent: Thursday, March 2, 2023 11:00 AMTo: Miles Mok XXXXSubject: [External Mail] xxxx Industry Development Survey Dear XXXX Lt…