飞桨分子动力学模拟-论文复现第六期:复现TorchMD

飞桨分子动力学模拟-论文复现第六期:复现TorchMD

Paddle for MD 飞桨分子动力学模拟科学计算

复现论文-TorchMD: A deep learning framework for molecular simulations
本项目可在AIStudio一键运行:飞桨分子动力学模拟PaddleMD-复现TorchMD
在这里插入图片描述

【论文复现第六期】相关信息

飞桨第六期论文复现赛128 https://aistudio.baidu.com/aistudio/competition/detail/205/0/task-definition

issue报名地址:https://github.com/PaddlePaddle/Paddle/issues/41482

验收标准:Di-alanine 688 8 min 44 s, Trypsin 3,248 13 min 2 s。(后改为去掉速度要求)

成功后会合入 https://github.com/X4Science

飞桨顶会论文挑战赛第9号 https://www.educoder.net/competitions/index/paddlepaddle-02

torchMD代码学习:https://github.com/torchmd/torchmd

论文地址
论文中文版地址

复现工作

复现工作第一步PaddleMD
第一步完成后运行Tutorial指导手册 复现第二步2PaddleMD提速 复现第三步集成测试

复现相关几个手写API速度测试 经测试,代码中有for循环的,一般速度比没有for循环都要慢30倍左右。

当前复现代码github地址PaddleMd https://github.com/skywalk163/INFINITY/tree/main/examples/PaddleMD

准备论文复现工作

下载论文原作源码

首先git clone下载论文原作的源码,使用命令git clone https://github.com/torchmd/torchmd

相关库安装。

在AIStudio下有些库使用pip无法安装,或者安装好之后不起作用,需要conda或者源码安装。
在AIStudio下如果pip无法安装,基本上我们就只剩下一个选择,就是源码安装。

pip安装moleculukit

使用这条命令pip install "moleculekit<=0.9.14"
如果安装不成功,使用源码安装。

源码安装ParmEd

源码安装ase

ase需要高版本的matplotlib,但是我用pip升级不成功(显示成功,但是版本就是没变)。
后来通过右侧工具条“包管理”,将matplotlib升级到最新版本3.5.1
因为,若安装中报错matplotlib,升级到最新版本,然后再源码安装ase。

pip安装openmm

这个是集成测试的时候使用,若不集成测试,可以不装这个库!
使用命令为:pip install openmm-systems

如果分子结构文件读取的时候报pandas出错,则需要相应降低pandas版本试试。

安装完成后,可以使用import xx的方式,验证是否安装成功。就作者本人的经验来说,运气好的时候,一路顺!运气不好的时候,有些包可能会有反复。

!pip install molkitten pyyaml tqdm pandas networkx scipy parmed ase  # Only needed for minimizers
!pip install pyyaml tqdm pandas networkx scipy parmed ase  # Only needed for minimizers
pip install "moleculekit<=0.9.14"
!cd work && wget https://files.pythonhosted.org/packages/56/75/422fa404b42999d6346545b63542d8c1e30f1cc31e5fc884bb7c9a3995c8/ParmEd-3.4.3.tar.gz 
!cd work && tar -xzvf ParmEd-3.4.3.tar.gz 
!cd work/ParmEd-3.4.3/ && python setup.py install 
# import matplotlib
# matplotlib.__version__
!cd work && wget https://files.pythonhosted.org/packages/69/64/096410b2e0b58aee082b40a37cdd61e708ed722a7471d7cf0e2dcb01cade/ase-3.22.1.tar.gz
!cd work && tar -xzvf ase-3.22.1.tar.gz
!cd work/ase-3.22.1 && python setup.py install 
# 安装之后需要重启内核
!pip install openmm-systems 
import moleculekit
# import ParmEd
import parmed
import ase
import openmm

若不成功,则按照下面安装openmm等,学习于这个项目:h
ttps://aistudio.baidu.com/aistudio/projectdetail/2694076

! mkdir 1
!wget https://repo.anaconda.com/miniconda/Miniconda3-py37_4.8.2-Linux-x86_64.sh
! chmod +x Miniconda3-py37_4.8.2-Linux-x86_64.sh
! bash ./Miniconda3-py37_4.8.2-Linux-x86_64.sh -b -f -p /home/aistudio/1
#! conda install -c rdkit rdkit -y
!yes| /home/aistudio/1/bin/conda install -c conda-forge openmm
!yes |/home/aistudio/1/bin/conda install -c conda-forge pdbfixer
import sys
sys.path.append('/home/aistudio/1/bin/')

import sys
sys.path.append('/home/aistudio/1/lib/python3.7/site-packages/') 

跑通原论文torchmd

先跑通原作代码,对整个流程有个基本了解

开始复现

第一阶段 手工开始单个文件转换

将项目所有核心.py文件,使用%%writefile xx.py的格式,放到notebook cell中,这样可以通过查找替换,快速修改所有的代码。

  • 优点是:代码修改效率高。发现一个问题,解决问题,并可以全部查找、替换,将同类问题全部解决。
  • 缺点是:调试效率较低。需要另开一个notebook文件进行测试,且修改代码后,需要重新执行,甚至要重启测试项目的内核。

代码复现第二阶段

像常规notebook下的调试流程

1、对疑点文件拆分,将函数放到Cell进行测试

测试中可以加入测试代码,验证函数是否正确。最终保证所有函数测试通过

2、测试通过后,将修改写回文件

3、在tutorial.ipynb文件中总测试

优点是,基本不修改tutorial.ipynb文件代码。

代码复现第三阶段

调试精度和速度
速度提高工具
https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/guides/performance_improving/profiling_model.html#profiler
当然最终这个项目里没有使用。

1、速度提高

有些手工写的算子使用了for循环,需要找到并提速。

提升paddleindex_add

5.12日确认了paddleindex_add对速度的影响非常大,这个算子要处理!

其次,在屏蔽掉paddleindex_add后,程序运行速度较快提高,非常利于调试!
目前的思路,是找到黑客马拉松项目里面的index_add代码,然后自己动手写成单独的算子。

6.1日,官方提供put_along_axis算子,可以实现index_add功能!

6.2日,好像put_along算子只支持1D index,以后不能用,后来发现可以使用。

6.4日 使用put_alone_axis函数重写了paddleindex_add,速度提升非常多!基本上跟以前测试的时候使用透传的的速度相当!

质疑numpy()函数

使用了太多的numpy()转换函数,这会大大降低速度。要看看这些转换的原因是什么,能否去掉。

提高paddleindexjia

修改paddleindexjia函数,将其修改成由numpy实现:

#             pos[:, self.nongrouped] -= offset.unsqueeze(1)
#             pos = paddleindexjia(pos, -offset, self.nongrouped)
            pos = pos.numpy()
            offset = offset.unsqueeze(1).numpy()
            pos[:, group] -= offset # 尝试使用numpy来处理 相关语句共4句
            pos = paddle.to_tensor(pos)

最终这一大段应该还有提升空间

        if len(self.nongrouped):
            offset = paddle.floor(pos[:, self.nongrouped] / box) * box
#             pos[:, self.nongrouped] -= offset.unsqueeze(1)
#             pos = paddleindexjia(pos, -offset, self.nongrouped)
            pos = pos.numpy()
            offset = offset.unsqueeze(1).numpy()
            pos[:, group] -= offset # 尝试使用numpy来处理 相关语句共4句
            pos = paddle.to_tensor(pos)
性能分析cProfile

import cProfile
import re
cProfile.run(‘re.compile(“foo|bar”)’)

def my_on_trace_ready(prof): # 定义回调函数,性能分析器结束采集数据时会被调用
  callback = profiler.export_chrome_tracing('./profiler_demo') # 创建导出性能数据到profiler_demo文件夹的回调函数
  callback(prof)  # 执行该导出函数
  prof.summary(sorted_by=profiler.SortedKeys.GPUTotal) # 打印表单,按GPUTotal排序表单项

p = profiler.Profiler(scheduler = [3,14], on_trace_ready=my_on_trace_ready, timer_only=True) # 初始化Profiler对象

p.start() # 性能分析器进入第0个step
测试paddle.profiler

paddle.profiler是飞桨自带的性能分析套件。
但是我在启智平台使用的时候,内核直接重启。
后来发现是最后使用了exit()指令的缘故。

但是分析套件需要数据集部分,没有就报错。曾设想加上一个空的数据集指令来骗过去,但最终没有动手做。

2、精度测试

每个文件分别写调试命令,验证精度。

这个并没有做

对tutorial.ipynb文件中的变量输出,跟torchmd的比对。
print(Epot)
print(system.forces)

在使用同一随机种子的情况,paddlemd和torchmd精度对齐。

集成测试

跟openmm的力场能量进行比较,差别不大,在可接受范围

Running test: test-data/benzamidine/
  angle Energy diff: 1.599e-06 Force diff: 6.954e-05
  bond Energy diff: -2.731e-06 Force diff: 1.177e-04
  dihedral Energy diff: -1.608e-06 Force diff: 7.054e-06
  lennardjones Energy diff: 6.798e-06 Force diff: 1.794e-05
  electrostatic Energy diff: -6.766e-07 Force diff: 1.272e-07
All forces. Total energy: 20.914 Energy diff: 3.382e-06 Force diff 1.458e-04

成功复现

复现成功后,即可进行飞桨分子动力学模拟

使用PaddleMD进行分子动力学模拟

参考PaddleMD指引手册,以前丙氨酸二肽为例,进行分子动力学模拟。1000step大约需要4分钟。

首先编译安装PaddleMD

若有报错缺库,缺啥装啥。

编译安装后,需要重启一下环境。

!cd ~/INFINITY/examples/PaddleMD/ && python setup.py develop 

参考指引手册,进行前丙氨酸二肽分子模拟

INFINITY/examples/PaddleMD/test-data/目录中有各种分子结构文件,比如二面角、水分子、苯甲脒、凝血酶配体等。这里以前丙氨酸二肽为例。

读取前丙氨酸二肽分子结构文件

使用“moleculekit”库读取输入拓扑和起始坐标

from moleculekit.molecule import Molecule
import os
import paddle

testdir = "INFINITY/examples/PaddleMD/test-data/prod_alanine_dipeptide_amber/"
mol = Molecule(os.path.join(testdir, "structure.prmtop"))  # Reading the system topology
mol.read(os.path.join(testdir, "input.coor"))  # Reading the initial simulation coordinates
mol.read(os.path.join(testdir, "input.xsc"))  # Reading the box dimensions

from paddlemd.forcefields.forcefield import ForceField
from paddlemd.parameters import Parameters


precision = paddle.float32
# 加载forcefield力场文件,并使用上述拓扑提取将用于模拟的相关参数
ff = ForceField.create(mol, os.path.join(testdir, "structure.prmtop"))
parameters = Parameters(ff, mol, precision=precision)


创建系统

我们可以创建一个“System”系统对象,该对象将包含模拟期间系统的状态,包括:
1、当前原子坐标
1.当前的盒子大小
1、当前原子速度
1、当前原子力场

from paddlemd.integrator import maxwell_boltzmann
from paddlemd.systems import System

system = System(mol.numAtoms, nreplicas=1, precision=precision)
system.set_positions(mol.coords)
system.set_box(mol.box)
system.set_velocities(maxwell_boltzmann(parameters.masses, T=300, replicas=1))
from paddlemd.forces import Forces
bonded = ["bonds", "angles", "dihedrals", "impropers", "1-4"]
# bonded = ["dihedrals"]
# forces = Forces(parameters, cutoff=9, rfa=True, switch_dist=7.5)
forces = Forces(parameters, cutoff=9, rfa=True, switch_dist=7.5, terms=bonded)
# Evaluate current energy and forces. Forces are modified in-place
Epot = forces.compute(system.pos, system.box, system.forces, returnDetails=True)

print(Epot)
print(system.forces)

动力学积分器

为了执行动力学,我们将创建一个“积分器”对象,用于集成模拟的时间步,以及一个“包装器”对象,用于包装周期单元内的系统坐标

from paddlemd.integrator import Integrator
from paddlemd.wrapper import Wrapper

langevin_temperature = 300  # K
langevin_gamma = 0.1
timestep = 1  # fs

integrator = Integrator(system, forces, timestep, gamma=langevin_gamma, T=langevin_temperature)
wrapper = Wrapper(mol.numAtoms, mol.bonds if len(mol.bonds) else None)

from paddlemd.minimizers import minimize_bfgs

minimize_bfgs(system, forces, steps=500)  # Minimize the system steps=500
from paddlemd.utils import LogWriter

logger = LogWriter(path="logs/", keys=('iter','ns','epot','ekin','etot','T'), name='monitor.csv')

开始集成模拟

from tqdm import tqdm 
import numpy as np

FS2NS = 1E-6 # Femtosecond to nanosecond conversion

steps = 1000 # 1000 
output_period = 10
save_period = 100
traj = []

trajectoryout = "mytrajectory.npy"

iterator = tqdm(range(1, int(steps / output_period) + 1))
# print(f"iterator={iterator}")
Epot = forces.compute(system.pos, system.box, system.forces)
for i in iterator:
    Ekin, Epot, T = integrator.step(niter=output_period)
    wrapper.wrap(system.pos, system.box)
#     currpos = system.pos.detach().cpu().numpy().copy()
#     currpos = system.pos.detach()
    currpos = system.pos
#     print(currpos.shape)
    traj.append(currpos)
#     print(len(traj) )
#     print(f"iterator={iterator}")
    
    if (i*output_period) % save_period  == 0:
        np.save(trajectoryout, np.stack(traj, axis=2))

    logger.write_row({'iter':i*output_period,'ns':FS2NS*i*output_period*timestep,'epot':Epot,'ekin':Ekin,'etot':Epot+Ekin,'T':T})

集成测试

INFINITY/examples/PaddleMD/3集成测试.ipynb/集成测试.ipynb 为集成测试文件,在AIStudio中,到相应位置点开该文件即可。也可以在终端使用命令执行。

集成测试的步骤:

首先使用python setup.py develop安装paddlemd开发模式。

在实际使用中,可以使用普通模式,命令为:python setup.py install

执行测试命令

可以使用python tests/test_paddlemd.py进行集成测试,使用./bin/paddlemd --conf tests/water/water_conf.yaml测试水分子,使用./bin/paddlemd --conf tests/prod_alanine_dipeptide_amber/conf.yaml测试prod alanine dipeptide前丙氨酸二肽,使用./bin/paddlemd --conf tests/trypsin/conf.yaml测试Trypsin胰蛋白酶。

3集成测试.ipynb文件中,上述命令已经放入,直接运行即可。也可以到相应目录,在控制台直接使用相应命令执行。

目前这三个单项测试都可以正常运行不报错。速度大约是torchmd的十六分之一。还有较大提升空间。

集成测试,可以测试一部分,可看到势能和力场等数值跟openmm的较接近。但是后面还是会报错,大约是训练求导那块还有问题。

复现过程中的一些工作留档

手动适配的飞桨API

有些API飞桨没有适配,先手写顶上。

def paddlerandn_like(x) : # 添加飞桨的randn_like函数
    return paddle.randn(x.shape)

# 后来发现飞桨2.3版本已经有了atan2函数,直接用即可
def paddleatan2(input, other): # 飞桨的atan2函数
    atan = paddle.atan(input/other)
    atan[1] = atan[1] + pi
    atan[2] = atan[2] + pi
    return atan

def paddlescatter(x, dim, index, src): # scatter支持1D版本
    
    updates = src
    if len(index.shape) == 1 :
#         for i in index:
#             x[i] += updates[i]
        for i in range(index.shape[0]):
            x[index[i]] += updates[i]
        return x
                                
    i, j = index.shape
    grid_x , grid_y = paddle.meshgrid(paddle.arange(i), paddle.arange(j))
    if dim == 0 :
        index = paddle.stack([index.flatten(), grid_y.flatten()], axis=1)
    elif dim == 1:
        index = paddle.stack([grid_x.flatten(), index.flatten()], axis=1)
        
    # PaddlePaddle updates 的 shape 大小必须与 index 对应
    updates_index = paddle.stack([grid_x.flatten(), grid_y.flatten()], axis=1)
    updates = paddle.gather_nd(updates, index=updates_index)
    return paddle.scatter_nd_add(x, index, updates)

# 这个要使用飞桨黑客松的代码,对速度影响非常大
def paddleindex_add(x, dim, index, source): # 飞桨的index_add
    for i in range(len(index)):
        x[index[i]] += source[i]
    return x

# 最终没有等到黑客松的index_add算子,自己用put_alone_axis写了一个
# 飞桨的put_alone_axis不支持shape不一致的情况,即indices和value比arr长或者短的情况。
# 需要做的,就是要把短的补齐,长的分段传入。
def paddleput_alone_axis(arr, indices, value, axis, reduce="add"):
    #     print(f"==arr.shape:{arr.shape} indices.shape:{indices.shape} value.shape:{value.shape}")
    lenarr = arr.shape[0]
    lenindices = indices.shape[0]
    while lenarr < lenindices:
        arr = paddle.put_along_axis(
            arr, indices[:lenarr].reshape([-1, 1]), value[:lenarr], axis, reduce=reduce
        )
        indices = indices[lenarr:]
        value = value[lenarr:]
        lenarr = arr.shape[0]
        lenindices = indices.shape[0]
    xs = lenarr - lenindices
    if xs >= 1:
        newindices = paddle.concat(
            [indices, paddle.zeros([xs], dtype=paddle.int64)]
        ).reshape([-1, 1])
        newvalue = paddle.concat([value, paddle.zeros([xs, value.shape[-1]])])
    else:
        newindices = indices.reshape([-1, 1])
        newvalue = value
    out = paddle.put_along_axis(arr, newindices, newvalue, axis, reduce=reduce)
    return out


# 为了跟程序里的参数序列对齐,尽量不修改代码,写paddleindex_add
def paddleindex_add(x, dim, index, source):
    return paddleput_alone_axis(x, index, source, dim)

# paddleeye这个不用了,全部用变量乘以paddle.eye(3)实现,解决shape首位>1的情况。
#         box = paddleeye(box, 3)
        box = box*paddle.eye(3) # 可以很好的处理box[2, 3, 3]类型数据
        box = box.sum(1)

def paddleeye(x, n): # 针对[1, 3, 3]输入的特供eye函数
    tmp =x[0][paddle.eye(n).astype(paddle.bool)]
    return tmp.unsqueeze_(0)

# paddleindexjia,使用专为numpy计算的方式,速度比paddleindexjia提高30%以上
#             pos[:, self.nongrouped] -= offset.unsqueeze(1)
#             pos = paddleindexjia(pos, -offset, self.nongrouped)
            pos = pos.numpy()
            offset = offset.unsqueeze(1).numpy()
            pos[:, group] -= offset # 尝试使用numpy来处理 相关语句共4句
            pos = paddle.to_tensor(pos)

def paddleindexjia (x, y, xindex): # 索引/切片/赋值特供版本
    '''
    切片+索引,使用循环来解决切片问题,然后使用中间变量,来实现按照索引赋值
    支持类似的语句pos[:, group] -= offset.unsqueeze(1)
    '''
    xlen = len(x)
    assert len(x.shape) == 3 , "维度不一致,必须为3D数据"
#     if len(y.shape) == 3 and y.shape[0] ==1 :
#         y = paddle.squeeze(y)
    assert len(y.shape) ==2 , "维度不一致,必须为2D数据"
    for i in range(xlen):
        tmp = x[i]
        tmp[xindex] += y
        x[i] = tmp
    return x

# 写飞桨版本的笛卡尔直积函数cartesian_prod
from itertools import product
def paddlecartesian_prod(x,y): # 飞桨版本的笛卡尔直积函数
    z = list(product(x,y))
    z = paddle.to_tensor(z)
    return z.squeeze(axis=-1)
    
# 最终版本笛卡尔直积函数支持变长变量输入
from itertools import product
def paddlecartesian_prod(*x): # 飞桨版本的笛卡尔直积函数
    z = list(product(*x))
    z = paddle.to_tensor(z)
    return z.squeeze(axis=-1)

学习paddlemd里面的几句话

# 这句什么意思        self.require_distances = any(f in self.nonbonded for f in self.energies)
# 也就是力场里面有任何一个nobonded值,则self.require_distances为True,也就是有”长距力“ ?
bonded = ["bonds", "angles", "dihedrals", "impropers", "1-4"]
nonbonded = ["electrostatics", "lj", "repulsion", "repulsioncg"]
terms = bonded + nonbonded

class TestClass():
    bonded = ["bonds", "angles", "dihedrals", "impropers", "1-4"]
    nonbonded = ["electrostatics", "lj", "repulsion", "repulsioncg"]
    terms = bonded + nonbonded
    def __init__(self, terms=None):
        self.energies = [ene.lower() for ene in terms]
        self.require_distances = any(f in self.nonbonded for f in self.energies)
        print(f"self.require_distances:{self.require_distances}")
tmp = TestClass(terms=terms)

提速思考

像类似这样,应该都可以用张量直接操作

for i in range(nsystems):
    if explicit_forces:
        forces[i] = paddleindex_add(forces[i], 0, self.par.angles[:, 0], angle_forces[0])
        forces[i] = paddleindex_add(forces[i], 0, self.par.angles[:, 1], angle_forces[1])
        forces[i] = paddleindex_add(forces[i], 0, self.par.angles[:, 2], angle_forces[2])

调试与总结

复现心得

刚开始选这个复现题目的时候,我承认我大意了,分子动力学模拟这个跟平时接触的机器学习和神经网络有较大的不同,而且有几个算子不支持,导致复现工作几度陷入困境。

在低谷期,只好自己鼓励自己:如果我碰到坎,别人也会碰到;如果我想放弃,那别人也会想放弃。坚持,才能胜利!最终跌跌撞撞,在自己写了几个算子(只求功能,不求速度)之后,程序终于能跑通了!

除了自我鼓励之外,问题拆分也是一个非常有效的解决问题的法宝。几乎所有问题,都可以拆分为小问题,进而拆分为更小更易于解决的问题,最终完成开始看起来几乎不可能完成的任务!

一些技术问题存档

大部分碰到的技术问题,都存档了。比如一些分子库pip无法安装的问题,一些算子的问题等。可以在复现三步走对应的文档下部,看到问题存档。

当前遗留的一些问题

1 集成测试无法完全通过。

2 AI自动求导优化那块可能还有问题。

3 运行速度大约是torchmd的十六分之一,还有很大提升空间。

其中有几个算子需要飞桨官方开发出来。另外整个项目的计算(代码表达式)可能还有较大的改进空间。

引用Citation

Please cite:

@misc{doerr2020torchmd,
      title={TorchMD: A deep learning framework for molecular simulations}, 
      author={Stefan Doerr and Maciej Majewsk and Adrià Pérez and Andreas Krämer and Cecilia Clementi and Frank Noe and Toni Giorgino and Gianni De Fabritiis},
      year={2020},
      eprint={2012.12106},
      archivePrefix={arXiv},
      primaryClass={physics.chem-ph}
}

To reproduce the paper go to the tutorial notebook https://github.com/torchmd/torchmd-cg/blob/master/tutorial/Chignolin_Coarse-Grained_Tutorial.ipynb

结束语

用飞桨,划时代!让我们荡起双桨,在AI的海洋乘风破浪!

飞桨官网:https://www.paddlepaddle.org.cn

因为水平有限,难免有不足之处,还请大家多多帮助。

作者: 网名skywalk 或 天马行空,济宁市极快软件科技有限公司的AI架构师,百度飞桨PPDE。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】HAL库的RCC复位状态判断及NVIC系统软件复位

【STM32】HAL库的RCC复位状态判断及NVIC系统软件复位 在实际开发中 有时候会遇到复位状态不同 导致结果不同的情况 比如在上电复位时 电压不稳定 可能导致一些外部芯片无法正常工作 从而导致进行了错误的操作流程 所以 可以在程序运行后 加一个复位状态判断 用来检测是否正常复…

linux 如何创建文件

我们在写一些教程的时候&#xff0c;经常会需要创建一些用于演示的文档&#xff0c;这些文档往往需要填充一些不特定的内容。那么如何快速的创建演示用的文档呢&#xff1f; docfaker.py docfaker.py是一个py脚本&#xff0c;用于创建一个简单的txt文档&#xff0c;docfaker.…

力扣每日一练(24-1-13)

如果用列表生成式&#xff0c;可以满足输出的型式&#xff0c;但是不满足题意&#xff1a; nums[:] [i for i in nums if i ! val]return len(nums) 题意要求是&#xff1a; 你需要原地修改数组&#xff0c;并且只使用O(1)的额外空间。这意味着我们不能创建新的列表&#xff…

vivado 指定顶部模块和重新排序源

指定顶部模块和重新排序源 文件夹默认情况下&#xff0c;Vivado Design Suite会自动确定设计的顶层添加到的源文件的层次结构和细化、合成和模拟的顺序项目这可以通过右键单击中的“层次更新”设置进行控制“源”窗口的菜单。请参阅中的“源”窗口中的“层次更新”命令Vivado …

从AAAI 2024看人工智能研究的最新热点

图 1 由AAAI 2024论文列表生成的词云 AAAI会议作为全球AI领域的顶级学术盛会&#xff0c;被中国计算机学会&#xff08;CCF&#xff09;评为A类会议。AAAI2024的会议论文投稿量达到了历史新高&#xff0c;主赛道收到了12100篇投稿论文&#xff0c;9862篇论文经过严格评审后共有…

基于Python的二氧化碳排放量数据分析系统

项目背景&#xff1a; 随着全球气候变化问题日益严重&#xff0c;减少温室气体排放已成为全球共识。我国作为全球最大的碳排放国&#xff0c;承担着重要的国际责任。为了更好地控制和减少碳排放&#xff0c;需要对全国的碳排放情况进行深入研究和分析。本项目旨在构建一个基于P…

腾讯云优惠券(代金券)领取方法及最新优惠活动汇总

腾讯云作为国内领先的云计算服务提供商&#xff0c;一直致力于为用户提供优质、高效、安全可靠的云计算服务。为了回馈广大用户&#xff0c;腾讯云会不定期地推出各种优惠活动&#xff0c;其中包括优惠券的发放。本文将分享腾讯云优惠券的领取方法并汇总最新优惠活动&#xff0…

uniapp小程序当页面内容超出时显示滚动条,不超出时不显示---样式自定义

使用scroll-view中的show-scrollbar属性 注意:需要搭配enhanced使用 否则无效 <scroll-view class"contentshow" scroll-y :show-scrollbartrue :enhancedtrue><view class"content" :show-scrollbartrue><text>{{vehicleCartinfo}}<…

阿里云云服务器u1实例和e实例有什么区别?

阿里云服务器u1和e实例有什么区别&#xff1f;ECS通用算力型u1实例是企业级独享型云服务器&#xff0c;ECS经济型e实例是共享型云服务器&#xff0c;所以相比较e实例&#xff0c;云服务器u1性能更好一些。e实例为共享型云服务器&#xff0c;共享型实例采用非绑定CPU调度模式&am…

【python入门】day26: 模拟高铁售票系统

界面 代码 #-*- coding:utf-8 -*- import prettytable as pt#---------导入漂亮表格 import os.path filename ticket.txt#更新座位状态 def update(row_num):#------更新购票状态with open(filename,w,encodingutf-8) as wfile:for i in range(row_num):lst1 [f{i1},有票,有…

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点面试题 02.07. 链表相交、142.环形链表II

文档讲解&#xff1a;虚拟头节点&#xff0c;三指针&#xff0c;快慢指针&#xff0c;链表相交&#xff0c;环形链表&#xff0c; 技巧&#xff1a; 1、对于指针的操作要画图&#xff0c;明确步骤后好做了 2、使用虚拟头节点可以避免对头节点单独讨论&#xff0c;且方便对头节点…

Linux 系统之部署 ZFile 在线网盘服务

一、ZFile 介绍 1&#xff09;ZFile 简介 官网&#xff1a;https://www.zfile.vip/ GitHub&#xff1a;https://github.com/zfile-dev/zfile ZFile 是一款基于 Java 的在线网盘程序&#xff0c;支持对接 S3、OneDrive、SharePoint、又拍云、本地存储、FTP 等存储源&#xff0…

oracle 19c容器数据库data dump数据泵传输数据(3)---完全传输

目录 查看pdb1 创建pdb2 从pdb1 中导出元数据 在pdb2中导入元数据&#xff08;dmp文件&#xff09; Full Transportable Export/Import: Example 只传输除了system&#xff0c;sysaux&#xff0c;temp&#xff0c;undo以外的用户表空间&#xff0c;這種方式傳輸的是用戶自定…

xtu oj 1329 连分式

题目描述 连分式是形如下面的分式&#xff0c;已知a,b和迭代的次数n&#xff0c;求连分式的值。 输入 第一行是一个整数T(1≤T≤1000)&#xff0c;表示样例的个数。 每行一个样例&#xff0c;为a,b,n(1≤a,b,n≤9) 输出 每行输出一个样例的结果&#xff0c;使用x/y分式表达…

计算机网络NCEPU复习资料

目录 一&#xff0e;概述&#xff1a; 计算机网络组成&#xff1a; 计算机网络分类&#xff1a; 计算机网络体系结构&#xff1a; C/S架构与P2P架构区别&#xff1a; OSI开放式系统互连参考模型&#xff1a; OSI开放式系统互连参考模型 相关协议&#xff1a; 五层协议网…

UML-类图和类图转化为代码

提示&#xff1a;文章详细的讲解了类图的四种关系&#xff0c;以及每种关系如何转化为对应的代码。 UML-类图和类图转化为代码 一、类于类之间的关系1.依赖关系2.关联关系(1) 单向关联(2) 双向关联(3) 自关联(4) 聚合关联(has-a)(5) 组合关联&#xff08;contains-a&#xff09…

Windows Server 2019配置多用户远程桌面登录服务器

正文共&#xff1a;1234 字 21 图&#xff0c;预估阅读时间&#xff1a;2 分钟 很久之前&#xff0c;在介绍显卡直通的时候我们简单介绍过RDP&#xff08;Remote Desktop Protocol&#xff0c;远程桌面协议&#xff09;&#xff08;前人栽树&#xff1a;失败的服务器显卡操作&a…

day17 平衡二叉树 二叉树的所有路径 左叶子之和

题目1&#xff1a;110 平衡二叉树 题目链接&#xff1a;110 平衡二叉树 题意 判断二叉树是否为平衡二叉树&#xff08;每个节点的左右两个子树的高度差绝对值不超过1&#xff09; 递归遍历 递归三部曲 1&#xff09;确定递归函数的参数和返回值 2&#xff09;确定终止条…

【LabVIEW FPGA入门】LabVIEW FPGA实现I2S解码器

该示例演示了如何使用 LabVIEW FPGA 解码 IS 信号。该代码可用于大多数支持高速数字输入的LabVIEW FPGA 目标&#xff08;例如R 系列、CompactRIO&#xff09;。IS 用于对系统和组件内的数字音频数据进行编码。例如&#xff0c;MP3 播放器或 DVD 播放器内部的数字音频通常使用 …

CentOS系统中如何配置Nginx作为静态HTTP服务器

在CentOS系统中&#xff0c;Nginx是一个流行的Web服务器软件&#xff0c;它可以高效地提供静态HTTP服务。以下是在CentOS中配置Nginx作为静态HTTP服务器的步骤&#xff1a; 1. 安装Nginx 首先&#xff0c;您需要确保已安装Nginx。可以使用以下命令安装Nginx&#xff1a; bas…