Strassen矩阵乘法问题(Java)

news2024/12/24 21:10:45

Strassen矩阵乘法问题(Java)

文章目录

  • Strassen矩阵乘法问题(Java)
    • 1、前置介绍
    • 3、代码实现
    • 4、复杂度分析
    • 5、参考资料


在这里插入图片描述


1、前置介绍

矩阵乘法是线性代数中最常见的问题之一 ,它在数值计算中有广泛的应用。 设AB是2个nXn矩阵,
它们的乘积AB同样是一个nXn矩阵。 AB的乘积矩阵C中元素C[i][j]定义为:
C [ i ] [ j ] = ∑ k = 1 n A [ i ] [ k ] B [ k ] [ j ] C[i][j] = \sum_{k=1}^{n}A[i][k]B[k][j] C[i][j]=k=1nA[i][k]B[k][j]

在这里插入图片描述

采用传统方法,时间复杂度为:O(n3)

因为按照上述的定义来计算A和 B的乘积矩阵c,则每计算C的一个元素C[i][j],需要做n次乘法运算和n-1次加法运算。 因此,得到矩阵C的n2 个元素所需的计算时间为 O(n3) 。

为解决计算计算效率问题,Strassen算法由此出现,该算法基本思想是分治,将计算2个n阶矩阵乘积所需的计算时间改进到0(nlog7) = 0(n2.81)

我们知道,C11=A11*B11+A12*B21

在这里插入图片描述

矩阵A和B的示意图如下:

在这里插入图片描述

传统方法:

在这里插入图片描述

2个n阶方阵的乘积转换为8个n/2 阶方阵的乘积和4个n/2阶方阵的加法。

由此可得:

C11 = A11B11 + A12B21

C12 = A11B12 + A12B22

C21 = A21B11 + A22B21

C22 = A21B12 + A22B22

分治法:

为了降低时间复杂度,必须减少乘法的次数。

使用与上例类似的技术,将矩阵A,B和C中每一矩阵都分块成4个大小相等的子矩阵。由此可将方程C=AB重写为:

在这里插入图片描述

2个n阶方阵的乘积转换为7个n/2 阶方阵的乘积和18个n/2阶方阵的加减法。

伪代码如下:

// 递归维度分半算法:
public void STRASSEN(n,A,B,C);
{  
if n=2 then MATRIX-MULTIPLY(A,B,C)
/ /结束循环,计算 两个2阶方阵的乘法         
else{
  将矩阵A和B分块;
  STRASSEN(n/2,A11,B12-B22,M1);
  STRASSEN(n/2,A11+A12,B22,M2); 
  STRASSEN(n/2,A21+A22,B11,M3);
  STRASSEN(n/2,A22,B21-B11,M4);
  STRASSEN(n/2,A11+A22,B11+B22,M5);
  STRASSEN(n/2,A12-A22,B21+B22,M6);
  STRASSEN(n/2,A11-A21,B11+B12,M7);}
}                

算法导论伪代码:

在这里插入图片描述

3、代码实现

public class StrassenMatrixMultiply
{
    public static void main(String[] args)
    {
        int[] a = new int[]
        {
            1, 1, 1, 1,
            2, 2, 2, 2,
            3, 3, 3, 3,
            4, 4, 4, 4
        };

        int[] b = new int[]
        {
            1, 2, 3, 4,
            1, 2, 3, 4,
            1, 2, 3, 4,
            1, 2, 3, 4
        };

        int length = 4;

        int[] c = sMM(a, b, length);

        for(int i = 0; i < c.length; i++)
        {
            System.out.print(c[i] + " ");

            if((i + 1) % length == 0) //换行
                System.out.println();
        }
    }

    public static int[] sMM(int[] a, int[] b, int length) {
        if(length == 2) {
            return getResult(a, b);
        }
        else {
            int tlength = length / 2;
            // 把a数组分为四部分,进行分治递归
            int[] aa = new int[tlength * tlength];
            int[] ab = new int[tlength * tlength];
            int[] ac = new int[tlength * tlength];
            int[] ad = new int[tlength * tlength];
            // 把b数组分为四部分,进行分治递归
            int[] ba = new int[tlength * tlength];
            int[] bb = new int[tlength * tlength];
            int[] bc = new int[tlength * tlength];
            int[] bd = new int[tlength * tlength];

            // TODO 划分子矩阵
            for(int i = 0; i < length; i++) {
                for(int j = 0; j < length; j++) {
                    /*
                     * 划分矩阵:
                     * 例子:将 4 * 4 的矩阵,变为 2 * 2 的矩阵,
                     * 那么原矩阵左上、右上、左下、右下的四个元素分别归为新矩阵
                    */
                    if(i < tlength) {
                        if(j < tlength) {
                            aa[i * tlength + j] = a[i * length + j];
                            ba[i * tlength + j] = b[i * length + j];
                        } else {
                            ab[i * tlength + (j - tlength)] = a[i * length + j];
                            bb[i * tlength + (j - tlength)] = b[i * length + j];
                        }
                    } else {
                        if(j < tlength) {
                            //i 大于 tlength 时,需要减去 tlength,j同理
                            //因为 b,c,d三个子矩阵有对应了父矩阵的后半部分
                            ac[(i - tlength) * tlength + j] = a[i * length + j];
                            bc[(i - tlength) * tlength + j] = b[i * length + j];
                        } else {
                            ad[(i - tlength) * tlength + (j - tlength)] = a[i * length + j];
                            bd[(i - tlength) * tlength + (j - tlength)] = b[i * length + j];
                        }
                    }
                }
            }

            // TODO 分治递归
            int[] result = new int[length * length];

            // temp:4个临时矩阵
            int[] t1 = add(sMM(aa, ba, tlength), sMM(ab, bc, tlength));
            int[] t2 = add(sMM(aa, bb, tlength), sMM(ab, bd, tlength));
            int[] t3 = add(sMM(ac, ba, tlength), sMM(ad, bc, tlength));
            int[] t4 = add(sMM(ac, bb, tlength), sMM(ad, bd, tlength));

            // TODO 归并结果
            for(int i = 0; i < length; i++) {
                for(int j = 0; j < length; j++) {
                    if (i < tlength){
                        if(j < tlength) {
                            result[i * length + j] = t1[i * tlength + j];
                        } else {
                            result[i * length + j] = t2[i * tlength + (j - tlength)];
                        }
                    } else {
                        if(j < tlength) {
                            result[i * length + j] = t3[(i - tlength) * tlength + j];
                        } else {
                            result[i * length + j] = t4[(i - tlength) * tlength + (j - tlength)];
                        }
                    }
                }
            }
            return result;
        }
    }

    public static int[] getResult(int[] a, int[] b) {
        int p1 = a[0] * (b[1] - b[3]);
        int p2 = (a[0] + a[1]) * b[3];
        int p3 = (a[2] + a[3]) * b[0];
        int p4 = a[3] * (b[2] - b[0]);
        int p5 = (a[0] + a[3]) * (b[0] + b[3]);
        int p6 = (a[1] - a[3]) * (b[2] + b[3]);
        int p7 = (a[0] - a[2]) * (b[0] + b[1]);

        int c00 = p5 + p4 - p2 + p6;
        int c01 = p1 + p2;
        int c10 = p3 + p4;
        int c11 = p5 + p1 -p3 - p7;

        return new int[] {c00, c01, c10, c11};
    }

    public static int[] add(int[] a, int[] b) {
        int[] c = new int[a.length];
        for(int i = 0; i < a.length; i++) {
            c[i] = a[i] + b[i];
	    }
        return c;
    }

    // TODO 返回一个数是不是2的幂次方
    public static boolean adjust(int x) {
        return (x & (x - 1)) == 0;
    }
}

4、复杂度分析

传统方法和分治法的复杂度比较,如下图所示;

在这里插入图片描述

T ( n ) = { O ( 1 ) , n = 2 7 T ( n / 2 ) + O ( n 2 ) , n > 2 T(n) = \left\{ \begin{matrix} O(1), n = 2 \\ 7T(n/2) + O(n^2), n > 2\\ \end{matrix} \right. T(n)={O(1),n=27T(n/2)+O(n2),n>2

T(n) = 0(nlog7 ) = 0(n2.81)

5、参考资料

  • 算法分析与设计(第四版)
  • 算法导论第三版
  • 博客园

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

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

相关文章

搭建灾情快速分析系统 | Bigemap助力防灾减灾重点工作

Bigemap国产基础软件凭借自身强大的新GIS引擎技术与完善的产品链&#xff0c;为相关部门提供了集"灾情采集-灾情监测-灾害快速评估-应急指挥"于一体的灾害防灾减灾解决方案&#xff0c;搭建了灾情快速分析系统&#xff0c;该系统成为相关部门应对灾情的重要支撑平台。…

虚拟号码认证如何开通?

近年来&#xff0c;经常会接到外卖、房产中介、信用贷款等电话&#xff0c;让顾客不胜其扰。现在电话标记功能使用越来越普遍&#xff0c;可以大概了解电话“来意”&#xff0c;同时也会让误标记、恶意标记很方便。对于开展业务或办公司或企业的人&#xff0c;更加不能让自己的…

排序算法之选择排序

今天来给大家介绍一下排序算法之选择排序 选择排序&#xff1a;&#xff08;Selection sort&#xff09;是一种简单直观的排序算法&#xff0c;也是一种不稳定的排序方法。 选择排序的原理&#xff1a; 一组无序待排数组&#xff0c;做升序排序&#xff0c;我们先假定第一个…

【生成模型】Diffusion Models:概率扩散模型

---前言一、Diffusion Model 基本介绍二、生成模型对比三、直观理解Diffusion model四、形式化解析Diffusion model五、详解 Diffusion Model&#xff08;数学推导&#xff09;1.前向过程(扩散过程)2.逆扩散过程3.逆扩散条件概率推导4.训练损失六、训练、测试伪代码1. 训练2.测…

鲲鹏devkit编译调试工具——《sudoku》作业解析

《sudoku》作业解析 本次实验以sudoku项目为例介绍鲲鹏编译调试插件的基本使用方法 本次实验的步骤主要为 获取源码安装鲲鹏编译调试插件服务器配置进行代码同步配置配置测试任务进行编译调试 接下来我们先获取本次实验所需要的源码 获取源码 sudoku项目已经上传到github使…

stata外部命令大全(包含面板门槛、系统GMM、空间计量、Pvar、中介效应等)

1、数据来源&#xff1a;自主整理 2、时间跨度&#xff1a;无 3、区域范围&#xff1a;无 4、指标说明&#xff1a; 该些外部命令包含面板门槛、系统GMM、空间计量、pvar、中介效应等涵盖全部 以下是部分命令截图&#xff1a; 空间计量&#xff1a; 系统GMM&#xff08;动…

Allure使用手册

一. 简介 Allure是一款支持多语言的测试结果可视化软件&#xff0c;支持Java、Python&#xff0c;搭配Junit、pytest等测试框架食用更香。本文主要讲解搭配Junit4。 二. 下载、安装部署 2.1 下载 百度搜索Allure2&#xff01;&#xff01;&#xff01; 敲重点&#xff1a;…

基于Qlearning强化学习的倒立摆控制系统matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 强化学习通常包括两个实体agent和environment。两个实体的交互如下&#xff0c;在environment的statestst下&#xff0c;agent采取actionatat进而得到rewardrtrt 并进入statest1st1。Q-l…

【头歌实验】五、Python循环结构

文章目录>>>第1关&#xff1a;达依尔的麦子数任务描述案例分析相关知识for循环测试说明参考答案>>>第2关&#xff1a;四级单词查询任务描述案例分析相关知识如何处理文件文件打开文件循环文件关闭遍历文件测试说明第3关&#xff1a;出租车车费计算任务描述案…

Monaco Editor教程(十八):使用api来完成某些键盘操作,格式化,查找,显示右侧菜单等。

背景 在一般的Web IDE中&#xff0c;我们需要将经常用到的一些操作放到顶部操作栏里&#xff0c;类似语雀的文档编辑。 代码编辑器&#xff0c;一般也会放一些查找&#xff0c;格式化&#xff0c;撤销&#xff0c;恢复。有些人喜欢用快捷键来进行这些操作&#xff0c;但由于mo…

Packet Tracer - 配置 OSPF 高级功能

地址分配表 设备 接口 IPv4 地址 子网掩码 默认网关 R1 G0/0 172.16.1.1 255.255.255.0 不适用 S0/0/0 172.16.3.1 255.255.255.252 不适用 S0/0/1 192.168.10.5 255.255.255.252 不适用 R2 G0/0 172.16.2.1 255.255.255.0 不适用 S0/0/0 172.16.3.2 …

论文笔记: 全波形反演的无监督学习: 将 CNN 与偏微分方程做成一个环

摘要: 分享对论文的理解, 原文见 Peng Jin, Xitong Zhang, Yinpeng Chen, Sharon Xiaolei Huang, Zicheng Liu, Youzuo Lin, Unsupervised learning of full-waveform inversion: connecting CNN and partial differential equation in a loop. 论文发表于计算机方面的顶会 ICL…

(续)SSM整合之SSM整合笔记(Spring整合MyBatis)(P179-188)

一 准备工作 1 新建模块ssm com.atguigu.ssm 2 导入依赖 <packaging>war</packaging><properties><spring.version>5.3.1</spring.version> </properties><dependencies><dependency><groupId>org.springframewo…

Linux:进程(二)

文章目录前言一、环境变量1.概念2.常见环境变量3.一个疑问4.通过系统调用获取或设置环境变量二、地址空间1.引入2.分页&进程地址空间1.页表2.写时拷贝3.为什么要有地址空间总结前言 今天我们继续学习进程相关知识。 一、环境变量 1.概念 环境变量(environment variables)…

从理解路由到实现一套Router(路由)

平时在Vue项目中经常用到路由&#xff0c;但是也仅仅处于会用的层面&#xff0c;很多基础知识并不是真正的理解。于是就趁着十一”小长假“查阅了很多资料&#xff0c;总结下路由相关的知识&#xff0c;查缺不漏&#xff0c;加深自己对路由的理解。 路由 在 Web 开发过程中&a…

Redis中最简单的存储类型:String

String类型&#xff0c;也就是字符串类型&#xff0c;是Redis中最简单的存储类型。 其value是字符串&#xff0c;不过根据字符串的格式不同&#xff0c;又可以分为3类&#xff1a; string&#xff1a;普通字符串 int&#xff1a;整数类型&#xff0c;可以做自增、自减操作 f…

CentOS虚拟机装完了,不能粘贴window命令行?不能上网?

文章目录前言关于CentOS安装版本如何实现粘贴命令行CentOS命令行模式下如何联网&#xff1f;结尾前言 最近想系统学习Linux环境下系统运维&#xff0c;所以安装了CentOS 7虚拟机&#xff0c;但是个人笔记本上和工作电脑上无意中下载了不同镜像进行安装&#xff0c;有一台机器无…

Nerf三维重建Pytorch使用Pycharm运行0基础教程

Nerf三维重建Pytorch使用Pycharm运行0基础教程 你好&#xff01; 这里是“出门吃三碗饭”本人&#xff0c;本文章接下来将介绍如何从0运行2020会议Nerf的Pytorch版本&#xff0c;让你自己动手渲染第一个三维模型。视频解说可以关注B站&#xff0c;搜索 出门吃三碗饭 &#xff…

Improving Inductive Link Prediction Using Hyper-Relational Facts

摘要 多年来,知识图(KGs)上的链接预测一直是一个纯粹的转换任务,不允许对看不见的实体进行推理。最近,越来越多的努力被投入到探索半和全归纳场景,使推理能够对不可见的和新兴的实体。然而,所有这些方法都只考虑基于三元组的kg,而它们更丰富的对应,超关系KG(如Wikidata…

OWASP ZAP mac chrome代理配置取消URL强制Https【已解决】

1.OWASP ZAP OWASP Zed攻击代理&#xff08;ZAP&#xff09;是世界上最受欢迎的免费安全审计工具之一&#xff0c;由数百名国际志愿者积极维护。它可以帮助你在开发和测试应用程序时自动查找Web应用程序中的安全漏洞。 也可以说ZAP是一个中间人代理。它能够获取你对Web应用程…