计算 Hermitian 矩阵的特征值和特征向量 cusolver 示例 DnCheevj

news2024/10/6 18:20:42

1,原理

计算Hermitian 矩阵的特征值,使用Jacobi 旋转法,每次调整两个对称元素为0,通过迭代,使得非对角线上的值总体越来越趋近于0.

示例扩展了 nv 的 cusolverDsyevj 的示例

由于特征向量是正交的,故V*V^c = E,以此作为正确性的验证准则

2,源码

ex_cusolverDnCheevj_exe.cpp


#include <cstdio>
#include <cstdlib>
#include <vector>

#include <cuda_runtime.h>
#include <cusolverDn.h>
#include <cuComplex.h>
#include "cusolver_utils.h"


void print_complex_matrix(cuComplex* A, int m, int n, int lda)
{
    for(int i=0; i<(m<12? m:12); i++){
        for(int j=0; j<(n<12? n:12); j++){
            printf("(%6.3f+(", A[i + j*lda].x);
            printf("%6.3f*j)), ", A[i + j*lda].y);
        }
        printf("; ...\n");
    }
}

void init_Hermitian_matrix(cuComplex *A, int m, int n ,int lda, int seed)
{
    srand(seed);

    for(int i=0; i<lda; i++){
        for(int j=0; j<m; j++){
            if(i<=j){
                A[i + j*lda].x = (rand()%2000)/1000.0f;
                A[i + j*lda].y = (rand()%2000)/1000.0f;
                if(i==j)
                    A[i + j*lda].y = 0.0f;
            }else{
                A[i + j*lda].x = A[j + i*lda].x;
                A[i + j*lda].y = -A[j + i*lda].y;
            }
        }
    }
}

void complex_gemm_NT(cuComplex *A, int lda, cuComplex *B, int ldb, cuComplex *C, int ldc, int M, int N, int K)
{
    cuComplex zero_c;
    zero_c.x = 0.0f;
    zero_c.y = 0.0f;

    for(int i=0; i<M; i++){
        for(int j=0; j<N; j++){
            cuComplex sigma = zero_c;
            for(int k=0; k<K; k++){
                sigma = cuCaddf(sigma, cuCmulf(A[i + k*lda], cuConjf(B[j+ k*ldb])));
            }
            C[i + j*ldc] = sigma;
        }
    }
}

int main(int argc, char *argv[]) {
    cusolverDnHandle_t cusolverH = NULL;
    cudaStream_t stream = NULL;
    syevjInfo_t syevj_params = NULL;

    const int m = 7;
    const int lda = m;

    cuComplex *A = nullptr;
    A = (cuComplex*)malloc(lda*m*sizeof(cuComplex));
    cuComplex *V = nullptr;
    V = (cuComplex*)malloc(lda*m*sizeof(cuComplex));
    float *W = nullptr;
    W = (float*)malloc(m*sizeof(float));

    init_Hermitian_matrix(A, m, m, lda, 2024);

    cuComplex *d_A = nullptr;
    float *d_W = nullptr;
    int *devInfo = nullptr;
    cuComplex *d_work = nullptr;
    int lwork = 0;
    int info_gpu = 0;

    /* configuration of syevj  */
    const double tol = 1.e-7;
    const int max_sweeps = 15;
    const cusolverEigMode_t jobz = CUSOLVER_EIG_MODE_VECTOR; // compute eigenvectors.
    //const cublasFillMode_t uplo = CUBLAS_FILL_MODE_LOWER;
    const cublasFillMode_t uplo = CUBLAS_FILL_MODE_UPPER;

    /* numerical results of syevj  */
    double residual = 0;
    int executed_sweeps = 0;

    printf("tol = %E, default value is machine zero \n", tol);
    printf("max. sweeps = %d, default value is 100\n", max_sweeps);

    printf("A = (matlab base-1)\n");
    //print_matrix(m, m, A, lda);
    print_complex_matrix(A, m, m, lda);
    printf("=====\n");

    /* step 1: create cusolver handle, bind a stream */
    CUSOLVER_CHECK(cusolverDnCreate(&cusolverH));

    CUDA_CHECK(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
    CUSOLVER_CHECK(cusolverDnSetStream(cusolverH, stream));

    /* step 2: configuration of syevj */
    CUSOLVER_CHECK(cusolverDnCreateSyevjInfo(&syevj_params));

    /* default value of tolerance is machine zero */
    CUSOLVER_CHECK(cusolverDnXsyevjSetTolerance(syevj_params, tol));

    /* default value of max. sweeps is 100 */
    CUSOLVER_CHECK(cusolverDnXsyevjSetMaxSweeps(syevj_params, max_sweeps));

    /* step 3: copy A to device */
    CUDA_CHECK(cudaMalloc(reinterpret_cast<void **>(&d_A), sizeof(cuComplex) * lda * m));
    CUDA_CHECK(cudaMalloc(reinterpret_cast<void **>(&d_W), sizeof(float) * m));
    CUDA_CHECK(cudaMalloc(reinterpret_cast<void **>(&devInfo), sizeof(int)));

    CUDA_CHECK(cudaMemcpyAsync(d_A, A, sizeof(cuComplex) * lda * m, cudaMemcpyHostToDevice, stream));

    /* step 4: query working space of syevj */
    CUSOLVER_CHECK(cusolverDnCheevj_bufferSize(cusolverH, jobz, uplo, m, d_A, lda, d_W, &lwork, syevj_params));
    printf("LL:: lwork = %d\n", lwork);
    CUDA_CHECK(cudaMalloc(reinterpret_cast<void **>(&d_work), sizeof(cuComplex) * lwork));

    /* step 5: compute eigen-pair   */
    CUSOLVER_CHECK(cusolverDnCheevj(cusolverH, jobz, uplo, m, d_A, lda, d_W, d_work, lwork, devInfo,
                                    syevj_params));

    CUDA_CHECK(cudaMemcpyAsync(V, d_A, sizeof(cuComplex) * lda * m, cudaMemcpyDeviceToHost, stream));
    CUDA_CHECK(cudaMemcpyAsync(W, d_W, sizeof(float) * m, cudaMemcpyDeviceToHost, stream));
    CUDA_CHECK(cudaMemcpyAsync(&info_gpu, devInfo, sizeof(int), cudaMemcpyDeviceToHost, stream));

    CUDA_CHECK(cudaStreamSynchronize(stream));

    if (0 == info_gpu) {
        printf("syevj converges \n");
    } else if (0 > info_gpu) {
        printf("%d-th parameter is wrong \n", -info_gpu);
        exit(1);
    } else {
        printf("WARNING: info = %d : syevj does not converge \n", info_gpu);
    }

    printf("Eigenvalue = (matlab base-1), ascending order\n");
    for (int i = 0; i < m; i++) {
        printf("W[%d] = %E\n", i + 1, W[i]);
    }
#if 1
    printf("V = (matlab base-1)\n");
    print_complex_matrix(V, m, m, lda);
    printf("=====\n");
#endif

    cuComplex *E = nullptr;
    E = (cuComplex*)malloc(m*m*sizeof(cuComplex));

    //void complex_gemm_NT(cuComplex *A, int lda, cuComplex *B, int ldb, cuComplex *C, int ldc, int M, int N, int K)
    complex_gemm_NT(V, lda, V, lda, E, m, m, m, m);
    printf("E =\n");
    print_complex_matrix(E, m, m, m);

    CUSOLVER_CHECK(cusolverDnXsyevjGetSweeps(cusolverH, syevj_params, &executed_sweeps));

    CUSOLVER_CHECK(cusolverDnXsyevjGetResidual(cusolverH, syevj_params, &residual));

    printf("residual |A - V*W*V**H|_F = %E \n", residual);
    printf("number of executed sweeps = %d \n", executed_sweeps);

    /* free resources */
    CUDA_CHECK(cudaFree(d_A));
    CUDA_CHECK(cudaFree(d_W));
    CUDA_CHECK(cudaFree(devInfo));
    CUDA_CHECK(cudaFree(d_work));

    CUSOLVER_CHECK(cusolverDnDestroySyevjInfo(syevj_params));

    CUSOLVER_CHECK(cusolverDnDestroy(cusolverH));

    CUDA_CHECK(cudaStreamDestroy(stream));

    CUDA_CHECK(cudaDeviceReset());

    return EXIT_SUCCESS;
}

cusolver_utils.h :

/*
 * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <cmath>
#include <functional>
#include <iostream>
#include <random>
#include <stdexcept>
#include <string>

#include <cuComplex.h>
#include <cuda_runtime_api.h>
#include <cublas_api.h>
#include <cusolverDn.h>
#include <library_types.h>

// CUDA API error checking
#define CUDA_CHECK(err)                                                                            \
    do {                                                                                           \
        cudaError_t err_ = (err);                                                                  \
        if (err_ != cudaSuccess) {                                                                 \
            printf("CUDA error %d at %s:%d\n", err_, __FILE__, __LINE__);                          \
            throw std::runtime_error("CUDA error");                                                \
        }                                                                                          \
    } while (0)

// cusolver API error checking
#define CUSOLVER_CHECK(err)                                                                        \
    do {                                                                                           \
        cusolverStatus_t err_ = (err);                                                             \
        if (err_ != CUSOLVER_STATUS_SUCCESS) {                                                     \
            printf("cusolver error %d at %s:%d\n", err_, __FILE__, __LINE__);                      \
            throw std::runtime_error("cusolver error");                                            \
        }                                                                                          \
    } while (0)

// cublas API error checking
#define CUBLAS_CHECK(err)                                                                          \
    do {                                                                                           \
        cublasStatus_t err_ = (err);                                                               \
        if (err_ != CUBLAS_STATUS_SUCCESS) {                                                       \
            printf("cublas error %d at %s:%d\n", err_, __FILE__, __LINE__);                        \
            throw std::runtime_error("cublas error");                                              \
        }                                                                                          \
    } while (0)

// cublas API error checking
#define CUSPARSE_CHECK(err)                                                                        \
    do {                                                                                           \
        cusparseStatus_t err_ = (err);                                                             \
        if (err_ != CUSPARSE_STATUS_SUCCESS) {                                                     \
            printf("cusparse error %d at %s:%d\n", err_, __FILE__, __LINE__);                      \
            throw std::runtime_error("cusparse error");                                            \
        }                                                                                          \
    } while (0)

// memory alignment
#define ALIGN_TO(A, B) (((A + B - 1) / B) * B)

// device memory pitch alignment
static const size_t device_alignment = 32;

// type traits
template <typename T> struct traits;

template <> struct traits<float> {
    // scalar type
    typedef float T;
    typedef T S;

    static constexpr T zero = 0.f;
    static constexpr cudaDataType cuda_data_type = CUDA_R_32F;
#if CUDART_VERSION >= 11000
    static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_R_32F;
#endif

    inline static S abs(T val) { return fabs(val); }

    template <typename RNG> inline static T rand(RNG &gen) { return (S)gen(); }

    inline static T add(T a, T b) { return a + b; }

    inline static T mul(T v, double f) { return v * f; }
};

template <> struct traits<double> {
    // scalar type
    typedef double T;
    typedef T S;

    static constexpr T zero = 0.;
    static constexpr cudaDataType cuda_data_type = CUDA_R_64F;
#if CUDART_VERSION >= 11000
    static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_R_64F;
#endif

    inline static S abs(T val) { return fabs(val); }

    template <typename RNG> inline static T rand(RNG &gen) { return (S)gen(); }

    inline static T add(T a, T b) { return a + b; }

    inline static T mul(T v, double f) { return v * f; }
};

template <> struct traits<cuFloatComplex> {
    // scalar type
    typedef float S;
    typedef cuFloatComplex T;

    static constexpr T zero = {0.f, 0.f};
    static constexpr cudaDataType cuda_data_type = CUDA_C_32F;
#if CUDART_VERSION >= 11000
    static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_C_32F;
#endif

    inline static S abs(T val) { return cuCabsf(val); }

    template <typename RNG> inline static T rand(RNG &gen) {
        return make_cuFloatComplex((S)gen(), (S)gen());
    }

    inline static T add(T a, T b) { return cuCaddf(a, b); }
    inline static T add(T a, S b) { return cuCaddf(a, make_cuFloatComplex(b, 0.f)); }

    inline static T mul(T v, double f) { return make_cuFloatComplex(v.x * f, v.y * f); }
};

template <> struct traits<cuDoubleComplex> {
    // scalar type
    typedef double S;
    typedef cuDoubleComplex T;

    static constexpr T zero = {0., 0.};
    static constexpr cudaDataType cuda_data_type = CUDA_C_64F;
#if CUDART_VERSION >= 11000
    static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_C_64F;
#endif

    inline static S abs(T val) { return cuCabs(val); }

    template <typename RNG> inline static T rand(RNG &gen) {
        return make_cuDoubleComplex((S)gen(), (S)gen());
    }

    inline static T add(T a, T b) { return cuCadd(a, b); }
    inline static T add(T a, S b) { return cuCadd(a, make_cuDoubleComplex(b, 0.)); }

    inline static T mul(T v, double f) { return make_cuDoubleComplex(v.x * f, v.y * f); }
};

template <typename T> void print_matrix(const int &m, const int &n, const T *A, const int &lda);

template <> void print_matrix(const int &m, const int &n, const float *A, const int &lda) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            std::printf("%0.2f ", A[j * lda + i]);
        }
        std::printf("\n");
    }
}

template <> void print_matrix(const int &m, const int &n, const double *A, const int &lda) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            std::printf("%0.2f ", A[j * lda + i]);
        }
        std::printf("\n");
    }
}

template <> void print_matrix(const int &m, const int &n, const cuComplex *A, const int &lda) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            std::printf("%0.2f + %0.2fj ", A[j * lda + i].x, A[j * lda + i].y);
        }
        std::printf("\n");
    }
}

template <>
void print_matrix(const int &m, const int &n, const cuDoubleComplex *A, const int &lda) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            std::printf("%0.2f + %0.2fj ", A[j * lda + i].x, A[j * lda + i].y);
        }
        std::printf("\n");
    }
}

template <typename T>
void generate_random_matrix(cusolver_int_t m, cusolver_int_t n, T **A, int *lda) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<typename traits<T>::S> dis(-1.0, 1.0);
    auto rand_gen = std::bind(dis, gen);

    *lda = n;

    size_t matrix_mem_size = static_cast<size_t>(*lda * m * sizeof(T));
    // suppress gcc 7 size warning
    if (matrix_mem_size <= PTRDIFF_MAX)
        *A = (T *)malloc(matrix_mem_size);
    else
        throw std::runtime_error("Memory allocation size is too large");

    if (*A == NULL)
        throw std::runtime_error("Unable to allocate host matrix");

    // random matrix and accumulate row sums
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            T *A_row = (*A) + *lda * i;
            A_row[j] = traits<T>::rand(rand_gen);
        }
    }
}

// Makes matrix A of size mxn and leading dimension lda diagonal dominant
template <typename T>
void make_diag_dominant_matrix(cusolver_int_t m, cusolver_int_t n, T *A, int lda) {
    for (int i = 0; i < std::min(m, n); ++i) {
        T *A_row = A + lda * i;
        auto row_sum = traits<typename traits<T>::S>::zero;
        for (int j = 0; j < n; ++j) {
            row_sum += traits<T>::abs(A_row[j]);
        }
        A_row[i] = traits<T>::add(A_row[i], row_sum);
    }
}

// Returns cudaDataType value as defined in library_types.h for the string containing type name
cudaDataType get_cuda_library_type(std::string type_string) {
    if (type_string.compare("CUDA_R_16F") == 0)
        return CUDA_R_16F;
    else if (type_string.compare("CUDA_C_16F") == 0)
        return CUDA_C_16F;
    else if (type_string.compare("CUDA_R_32F") == 0)
        return CUDA_R_32F;
    else if (type_string.compare("CUDA_C_32F") == 0)
        return CUDA_C_32F;
    else if (type_string.compare("CUDA_R_64F") == 0)
        return CUDA_R_64F;
    else if (type_string.compare("CUDA_C_64F") == 0)
        return CUDA_C_64F;
    else if (type_string.compare("CUDA_R_8I") == 0)
        return CUDA_R_8I;
    else if (type_string.compare("CUDA_C_8I") == 0)
        return CUDA_C_8I;
    else if (type_string.compare("CUDA_R_8U") == 0)
        return CUDA_R_8U;
    else if (type_string.compare("CUDA_C_8U") == 0)
        return CUDA_C_8U;
    else if (type_string.compare("CUDA_R_32I") == 0)
        return CUDA_R_32I;
    else if (type_string.compare("CUDA_C_32I") == 0)
        return CUDA_C_32I;
    else if (type_string.compare("CUDA_R_32U") == 0)
        return CUDA_R_32U;
    else if (type_string.compare("CUDA_C_32U") == 0)
        return CUDA_C_32U;
    else
        throw std::runtime_error("Unknown CUDA datatype");
}

// Returns cusolverIRSRefinement_t value as defined in cusolver_common.h for the string containing
// solver name
cusolverIRSRefinement_t get_cusolver_refinement_solver(std::string solver_string) {
    if (solver_string.compare("CUSOLVER_IRS_REFINE_NONE") == 0)
        return CUSOLVER_IRS_REFINE_NONE;
    else if (solver_string.compare("CUSOLVER_IRS_REFINE_CLASSICAL") == 0)
        return CUSOLVER_IRS_REFINE_CLASSICAL;
    else if (solver_string.compare("CUSOLVER_IRS_REFINE_GMRES") == 0)
        return CUSOLVER_IRS_REFINE_GMRES;
    else if (solver_string.compare("CUSOLVER_IRS_REFINE_CLASSICAL_GMRES") == 0)
        return CUSOLVER_IRS_REFINE_CLASSICAL_GMRES;
    else if (solver_string.compare("CUSOLVER_IRS_REFINE_GMRES_GMRES") == 0)
        return CUSOLVER_IRS_REFINE_GMRES_GMRES;
    else
        printf("Unknown solver parameter: \"%s\"\n", solver_string.c_str());

    return CUSOLVER_IRS_REFINE_NOT_SET;
}

Makefile:


EXE = hello_DnDsyevj  ex_cusolverDnCheevj_exe

all: $(EXE)
INC :=-I /usr/local/cuda/include 
LD_FLAGS := -L /usr/local/cuda/lib64 -lcudart -lcusolver


%: %.cpp
	g++ $< -o $@ $(INC) $(LD_FLAGS)

.PHONY: clean
clean:
	rm -rf $(EXE)

3,运行

make

4,参考

CUDALibrarySamples/cuSOLVER/syevj/cusolver_syevj_example.cu at master · NVIDIA/CUDALibrarySamples · GitHub

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

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

相关文章

预训练任务

预训练任务 - Mask Language Model jieba预分词长度小于4的词直接mask&#xff08;mask_ids就是input_ids&#xff09; if rands > self.mask_rate and len(word) < 4:word word_list[i]word_encode tokenizer.encode(word, add_special_tokensFalse)for token in wo…

Leetcode面试经典150_Q122买卖股票的最佳时机II

题目&#xff1a; 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&#xff0c;然后在 同一天 出售。 返回 你能获得的 最大…

快速为App打造Android端聊天室,节省80%开发成本(一)

前言 环信 ChatroomUIKit 提供 UIKit 的各种组件&#xff0c;能帮助开发者根据实际业务需求快速搭建聊天室应用&#xff0c;有效节约开发成本&#xff01;通过该 UIKit&#xff0c;聊天室中的用户可实时交互&#xff0c;发送普通弹幕消息、打赏消息和全局广播等功能。 本文详…

紫叶写作能用吗 #微信#知识分享

紫叶写作是一款非常好用、靠谱的论文写作工具&#xff0c;它旨在帮助用户快速高效地完成论文写作任务&#xff0c;并提供查重降重的功能。它不仅操作简单方便&#xff0c;而且功能强大&#xff0c;能够有效提高论文写作的效率和质量。 首先&#xff0c;紫叶写作提供了丰富的模板…

10款白嫖党必备的ai写作神器,你都知道吗? #媒体#人工智能#其他

从事自媒体运营光靠自己手动操作效率是非常低的&#xff0c;想要提高运营效率就必须要学会合理的使用一些辅助工具。下面小编就跟大家分享一些自媒体常用的辅助工具&#xff0c;觉得有用的朋友可以收藏分享。 1.飞鸟写作 这是一个微信公众号 面向专业写作领域的ai写作工具&am…

jmeter压测websocket协议

一、jmeter 安装websocket插件 1、选项--插件管理 2、搜索WebSocket Samplers by Peter Doornbosch插件 进行安装 3、 重启 jmeter 二、jmeter压测websocket协议实战 2.1、以网站为例&#xff1a; websocket在线测试 1、断开连接 2、打开F12&#xff0c;查看WS数据 3、…

基于Socket简单的UDP网络程序

⭐小白苦学IT的博客主页 ⭐初学者必看&#xff1a;Linux操作系统入门 ⭐代码仓库&#xff1a;Linux代码仓库 ❤关注我一起讨论和学习Linux系统 1.前言 网络编程前言 网络编程是连接数字世界的桥梁&#xff0c;它让计算机之间能够交流信息&#xff0c;为我们的生活和工作带来便利…

电路基础-电容-电感

电路基础 电容 通交流阻直流&#xff0c;滤波&#xff0c;旁路&#xff0c;退耦&#xff0c;作驱动电源&#xff08;洗衣机电机启动时需要一个强电启动&#xff09; 电容选型的工程值&#xff1b;参考以往开发板的选型&#xff1b;抄作业。 电源并连多个电容的作用 保证单…

thinkphp6使用阿里云SDK发送短信

使用composer安装sdk "alibabacloud/dysmsapi-20170525": "2.0.24"封装发送短信类 发送到的短信参数写在env文件里面的 #发送短信配置 [AliyunSms] AccessKeyId "" AccessKeySecret "" signName"" templateCode"&…

泛微OA 自定义多选浏览框

1、建模引擎-》应用建模-》表单 2、建模引擎-》应用建模-》模块 3、建模引擎-》应用建模-》查询 4、把查询页面挂到前端页面。 效果展示&#xff1a; 5、建模引擎-》应用建模-》浏览框 6、流程表单中字段应用

Java环境变量配置说明

1、右键点击“此电脑”&#xff0c;选择“属性”项。 2、点击“高级系统设置”&#xff0c;在弹出的系统属性框中&#xff0c;选择“高级”选项卡&#xff08;默认即显示该选项卡&#xff09;&#xff0c;点击“环境变量”。 3、在弹出的“环境变量”框&#xff0c;中选择下方…

武汉凯迪正大—红外SF6检漏仪

产品概述 KDWG-III高精度SF6气体检漏仪&#xff08;手持式&#xff09;是测量SF6气体泄漏的新产品&#xff0c;采用进口传感器&#xff0c;它具有灵敏度高、稳定性好、响应速度快、操作简便、移动范围大&#xff0c;可迅速、准确的定性和定量检测SF6断路器和GIS的泄漏点及年泄…

如何利用Anaconda管理ArcGISPro相关环境

1.查看 目标下载scikit-learn以及scikit-image&#xff0c;以下是在ArcGISPro中查询库的结果 我们发现原始环境中不存在这两个库 2.修改 向Anaconda的Channels中添加esri的channel&#xff0c;点击add...直接输入esri即可 3.下载 接下来就可以直接下载自己需要的库了

说说对WebSocket的理解?应用场景?

一、是什么 WebSocket&#xff0c;是一种网络传输协议&#xff0c;位于OSI模型的应用层。可在单个TCP连接上进行全双工通信&#xff0c;能更好的节省服务器资源和带宽并达到实时通迅 客户端和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c…

2024通信技术与航空航天工程国际会议(ICCTAE2024)

2024通信技术与航空航天工程国际会议(ICCTAE2024) 会议简介 通信技术和航空航天领域有着密切的关联和深远的意义。 随着通信技术和航空航天工程的快速发展&#xff0c;这两个领域的交叉融合为学术界和工业界提供了广阔的研究空间和实际应用前景。为了进一步推动相关领域的发…

手把手教你免费领取雨云游戏云服务器

随着云计算技术的快速发展&#xff0c;云服务器已经成为许多开发者和创业者的首选。雨云游戏云服务器作为一款专为游戏开发者打造的高性能、低成本的云服务&#xff0c;吸引了越来越多的用户&#xff0c;本文将手把手教你如何免费领取雨云游戏云服务器。 1、访问雨云官网并注册…

SpringBoot快速入门笔记(5)

文章目录 一、elemetnUI1、main.js2、App.vue3、fontAwesome 一、elemetnUI 开源前端框架&#xff0c;安装 npm i element-ui -S 建议查看官方文档 Element组件&#xff0c;这里是Vue2搭配elementUI&#xff0c;如果是vue3就搭配elementPlus&#xff0c;这里初学就以Vue2为例子…

【JavaWeb】Day32.SpringBootWeb请求响应——分层解耦(二)

3.IOC&DI 3.1 IOC&DI入门 完成Controller层、Service层、Dao层的代码解耦 思路&#xff1a; 1. 删除Controller层、Service层中new对象的代码 2. Service层及Dao层的实现类&#xff0c;交给IOC容器管理 3. 为Controller及Service注入运行时依赖的对象 Controller程序…

健身房如何通过软文获客?媒介盒子告诉你

如今全民健康意识上升&#xff0c;大家越来越重视运动带给人的获得感以及成就感&#xff0c;对于健身房来说&#xff0c;适当进行推广&#xff0c;不仅可以提高品牌知名度&#xff0c;还能吸引更多的潜在客户。今天媒介盒子就从专业角度和大家聊聊&#xff1a;健身房如何通过软…

手机软件何时统一--桥接模式

1.1 凭什么你的游戏我不能玩 2007年苹果手机尚未出世&#xff0c;机操作系统多种多样&#xff08;黑莓、塞班、Tizen等&#xff09;&#xff0c;互相封闭。而如今&#xff0c;存世的手机操作系统只剩下苹果OS和安卓&#xff0c;鸿蒙正在稳步进场。 1.2 紧耦合的程序演化 手机…