[英]Converting a Jagged Array that represents a Neural Network to a 2D Array the represents its Neural Pathways C#
[英]Converting jagged array to 2D array C#
我正在尝试将此功能从锯齿状数组转换为2D数组,但无法将所有原始函数都转换为:
public static double[][] InvertMatrix(double[][] A)
{
int n = A.Length;
//e will represent each column in the identity matrix
double[] e;
//x will hold the inverse matrix to be returned
double[][] x = new double[n][];
for (int i = 0; i < n; i++)
{
x[i] = new double[A[i].Length];
}
/*
* solve will contain the vector solution for the LUP decomposition as we solve
* for each vector of x. We will combine the solutions into the double[][] array x.
* */
double[] solve;
//Get the LU matrix and P matrix (as an array)
Tuple<double[][], int[]> results = LUPDecomposition(A);
double[][] LU = results.Item1;
int[] P = results.Item2;
/*
* Solve AX = e for each column ei of the identity matrix using LUP decomposition
* */
for (int i = 0; i < n; i++)
{
e = new double[A[i].Length];
e[i] = 1;
solve = LUPSolve(LU, P, e);
for (int j = 0; j < solve.Length; j++)
{
x[j][i] = solve[j];
}
}
return x;
}
到现在为止我已经转换了什么
public static double[,] InvertMatrix(double[,] A)
{
int n = A.Length;
//e will represent each column in the identity matrix
double[] e;
//x will hold the inverse matrix to be returned
double[,] x = new double[n][];
for (int i = 0; i < n; i++)
{
//how to convert this line?
x[i] = new double[A[i].Length];
}
/*
* solve will contain the vector solution for the LUP decomposition as we solve
* for each vector of x. We will combine the solutions into the double[][] array x.
* */
double[] solve;
//Get the LU matrix and P matrix (as an array)
Tuple<double[,], int[]> results = LUPDecomposition(A);
double[,] LU = results.Item1;
int[] P = results.Item2;
/*
* Solve AX = e for each column ei of the identity matrix using LUP decomposition
* */
for (int i = 0; i < n; i++)
{
//This one too?!
e = new double[A[i].Length];
e[i] = 1;
solve = LUPSolve(LU, P, e);
for (int j = 0; j < solve.Length; j++)
{
x[j,i] = solve[i,j];
}
}
return x;
}
如何将x [i] =新double [A [i] .Length]转换为2D数组?
此代码段可能会有所帮助
static T[,] To2D<T>(T[][] source)
{
try
{
int FirstDim = source.Length;
int SecondDim = source.GroupBy(row => row.Length).Single().Key; // throws InvalidOperationException if source is not rectangular
var result = new T[FirstDim, SecondDim];
for (int i = 0; i < FirstDim; ++i)
for (int j = 0; j < SecondDim; ++j)
result[i, j] = source[i][j];
return result;
}
catch (InvalidOperationException)
{
throw new InvalidOperationException("The given jagged array is not rectangular.");
}
}
用法:
double[][] array = { new double[] { 52, 76, 65 }, new double[] { 98, 87, 93 }, new double[] { 43, 77, 62 }, new double[] { 72, 73, 74 } };
double[,] D2 = To2D(array);
UPD:对于那些可以接受不安全上下文的情况,有一个更快的解决方案,感谢Styp: https ://stackoverflow.com/a/51450057/3909293
注意:锯齿状数组应正交,因此子数组的长度应全部相等,否则无法将其转换为2D数组。
那个部分:
double[,] x = new double[n][];
for (int i = 0; i < n; i++)
{
//how to convert this line?
x[i] = new double[A[i].Length];
}
仅用于初始化一个新的锯齿状数组,可以轻松地将其替换为
double[,] x = new double[A.GetLength(0),A.GetLength(1)];
和在
//This one too?!
e = new double[A[i].Length];
您实际上是在A
创建具有相同长度的子数组i
数组,因此我们可以将其替换为
e = new double[A.GetLength(1)]; //NOTE: second dimension
如前所述,所有子数组的长度都相等,因此我们可以使用第二维长度。
整个方法将是:
public static double[,] InvertMatrix2D(double[,] A)
{
int n = A.Length;
//e will represent each column in the identity matrix
double[] e;
//x will hold the inverse matrix to be returned
double[,] x = new double[A.GetLength(0),A.GetLength(1)];
/*
* solve will contain the vector solution for the LUP decomposition as we solve
* for each vector of x. We will combine the solutions into the double[][] array x.
* */
double[] solve;
//Get the LU matrix and P matrix (as an array)
Tuple<double[,], int[]> results = LUPDecomposition(A);
double[,] LU = results.Item1;
int[] P = results.Item2;
/*
* Solve AX = e for each column ei of the identity matrix using LUP decomposition
* */
for (int i = 0; i < n; i++)
{
e = new double[A.GetLength(1)]; //NOTE: second dimension
e[i] = 1;
solve = LUPSolve(LU, P, e);
for (int j = 0; j < solve.Length; j++)
{
x[j,i] = solve[j];
}
}
return x;
}
如果运行时不重要,则勤奋的按键答案是正确的答案。 我在3D阵列上进行了大量工作,并且了解到按值复制操作的成本非常高! 记住这一点! 另一件事是Linq速度很慢,前提条件也正在消耗时间!
我认为,如果时间很重要,则此解决方案可能会有用:
using System;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace ArrayConverter {
public class Benchmark {
[Params(10, 100, 1000, 10000)]
public int size;
public double[][] data;
[GlobalSetup]
public void Setup() {
var rnd = new Random();
data = new double[size][];
for (var i = 0; i < size; i++) {
data[i] = new double[size];
for (var j = 0; j < size; j++) {
data[i][j] = rnd.NextDouble();
}
}
}
[Benchmark]
public void ComputeTo2D() {
var output = To2D(data);
}
[Benchmark]
public void ComputeTo2DFast() {
var output = To2DFast(data);
}
public static T[,] To2DFast<T>(T[][] source) where T : unmanaged{
var dataOut = new T[source.Length, source.Length];
var assertLength = source[0].Length;
unsafe {
for (var i=0; i<source.Length; i++){
if (source[i].Length != assertLength) {
throw new InvalidOperationException("The given jagged array is not rectangular.");
}
fixed (T* pDataIn = source[i]) {
fixed (T* pDataOut = &dataOut[i,0]) {
CopyBlockHelper.SmartCopy<T>(pDataOut, pDataIn, assertLength);
}
}
}
}
return dataOut;
}
public static T[,] To2D<T>(T[][] source) {
try {
var FirstDim = source.Length;
var SecondDim =
source.GroupBy(row => row.Length).Single()
.Key; // throws InvalidOperationException if source is not rectangular
var result = new T[FirstDim, SecondDim];
for (var i = 0; i < FirstDim; ++i)
for (var j = 0; j < SecondDim; ++j)
result[i, j] = source[i][j];
return result;
}
catch (InvalidOperationException) {
throw new InvalidOperationException("The given jagged array is not rectangular.");
}
}
}
public class Programm {
public static void Main(string[] args) {
BenchmarkRunner.Run<Benchmark>();
// var rnd = new Random();
//
// var size = 100;
// var data = new double[size][];
// for (var i = 0; i < size; i++) {
// data[i] = new double[size];
// for (var j = 0; j < size; j++) {
// data[i][j] = rnd.NextDouble();
// }
// }
//
// var outSafe = Benchmark.To2D(data);
// var outFast = Benchmark.To2DFast(data);
//
// for (var i = 0; i < outSafe.GetLength(0); i++) {
// for (var j = 0; j < outSafe.GetLength(1); j++) {
// if (outSafe[i, j] != outFast[i, j]) {
// Console.WriteLine("Error at: {0}, {1}", i, j);
// }
// }
// }
//
// Console.WriteLine("All Good!");
}
}
}
可从此处获得CopyBlock Helper: https ://gist.github.com/theraot/1bfd0deb4a1aab0a27d8
我刚刚为IL函数制作了一个包装器:
using System;
using System.Reflection.Emit;
namespace ArrayConverter {
// Inspired by:
// http://xoofx.com/blog/2010/10/23/high-performance-memcpy-gotchas-in-c/
public class CopyBlockHelper {
private const int BlockSize = 16384;
private static readonly CopyBlockDelegate CpBlock = GenerateCopyBlock();
private unsafe delegate void CopyBlockDelegate(void* des, void* src, uint bytes);
private static unsafe void CopyBlock(void* dest, void* src, uint count) {
var local = CpBlock;
local(dest, src, count);
}
static CopyBlockDelegate GenerateCopyBlock() {
// Don't ask...
var method = new DynamicMethod("CopyBlockIL", typeof(void),
new[] {typeof(void*), typeof(void*), typeof(uint)}, typeof(CopyBlockHelper));
var emitter = method.GetILGenerator();
// emit IL
emitter.Emit(OpCodes.Ldarg_0);
emitter.Emit(OpCodes.Ldarg_1);
emitter.Emit(OpCodes.Ldarg_2);
emitter.Emit(OpCodes.Cpblk);
emitter.Emit(OpCodes.Ret);
// compile to delegate
return (CopyBlockDelegate) method.CreateDelegate(typeof(CopyBlockDelegate));
}
public static unsafe void SmartCopy<T>(T* pointerDataOutCurrent, T* pointerDataIn, int length) where T : unmanaged {
var sizeOfType = sizeof(T);
var numberOfBytesInBlock = Convert.ToUInt32(sizeOfType * length);
var numOfIterations = numberOfBytesInBlock / BlockSize;
var overheadOfLastIteration = numberOfBytesInBlock % BlockSize;
uint offset;
for (var idx = 0u; idx < numOfIterations; idx++) {
offset = idx * BlockSize;
CopyBlock(pointerDataOutCurrent + offset / sizeOfType, pointerDataIn + offset / sizeOfType, BlockSize);
}
offset = numOfIterations * BlockSize;
CopyBlock(pointerDataOutCurrent + offset / sizeOfType, pointerDataIn + offset / sizeOfType, overheadOfLastIteration);
}
}
}
结果如下:
Method | size | Mean | Error | StdDev |
---------------- |------ |-----------------:|-----------------:|-----------------:|
ComputeTo2D | 10 | 972.2 ns | 18.981 ns | 17.755 ns |
ComputeTo2DFast | 10 | 233.1 ns | 6.672 ns | 6.852 ns |
ComputeTo2D | 100 | 21,082.5 ns | 278.679 ns | 247.042 ns |
ComputeTo2DFast | 100 | 6,100.2 ns | 66.566 ns | 62.266 ns |
ComputeTo2D | 1000 | 2,481,061.0 ns | 13,724.850 ns | 12,166.721 ns |
ComputeTo2DFast | 1000 | 1,939,575.1 ns | 18,519.845 ns | 16,417.358 ns |
ComputeTo2D | 10000 | 340,687,083.2 ns | 1,671,837.229 ns | 1,563,837.429 ns |
ComputeTo2DFast | 10000 | 279,996,210.4 ns | 955,032.923 ns | 745,626.822 ns |
如果可能,请尝试使用ArrayCopy,BlockCopy或IL-CopyBlock来提高转换性能。 逐值复制操作很慢,因此不是最佳选择! 通过优化一些内容并删除if子句,可以进一步提高速度。 至少应达到2倍!
为了确保我们有相同的理解,锯齿状的数组就是数组的数组。 所以当你这样做
for (int i = 0; i < n; i++)
{
//how to convert this line?
x[i] = new double[A[i].Length];
}
您正在为第一个维度的数组的每个位置添加一个数组。
在您的情况下(在锯齿状数组中) A.Length
表示数组的第一维的长度,而A[i].Length
表示包含在数组的索引(i)中的第二维的数组的长度。第一维。 如果使用2D数组,则A.Length
表示两个维度的长度相乘。 尽管带有锯齿的每个第二维数组的长度可以不同,但是二维数组在两个维上的长度必须相同。
因此,在您的情况下,您将必须获得n = A.GetLength(0)
(均值获得第一维的长度)和m = A.GetLength(1)
(均值获得第二维的长度)。 然后,您将初始化' double[,] x = new double[n, m];
并且您将不再需要for
循环。
您的代码应如下所示:
public static double[,] InvertMatrix(double[,] A)
{
int n = A.Length;
//e will represent each column in the identity matrix
double[] e;
//x will hold the inverse matrix to be returned
double[,] x = new double[n, m];
/*
* solve will contain the vector solution for the LUP decomposition as we solve
* for each vector of x. We will combine the solutions into the double[][] array x.
* */
double[] solve;
//Get the LU matrix and P matrix (as an array)
Tuple<double[,], int[]> results = LUPDecomposition(A);
double[,] LU = results.Item1;
int[] P = results.Item2;
/*
* Solve AX = e for each column ei of the identity matrix using LUP decomposition
* */
for (int i = 0; i < n; i++)
{
//This one too?! /// this one would become
e = new double[m];
e[i] = 1;
solve = LUPSolve(LU, P, e);
for (int j = 0; j < solve.Length; j++)
{
x[j,i] = solve[i,j];
}
}
return x;
}
因此,如果我做的还可以,则可以解决您的问题并回答您的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.