![](/img/trans.png)
[英]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.