/// <summary>
        ///     Calculates inverse matrix.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ndArray"></param>
        /// <returns></returns>
        public static NdArray <T> Inverse <T>(this INdArray <T> ndArray)
        {
            Guard.AssertShapeMatch((bool)(ndArray.Rank == 2 & ndArray.Shape[0] == ndArray.Shape[1]), "ndArray.Rank == 2 & ndArray.Shape[0] == ndArray.Shape[1]");

            var b = Identity <T>((int)ndArray.Shape[0]);

            var(l, u, perms) = NdLinAlg.LUWithPermutationsLegacy <T>(ndArray);
            var xx  = NdArray.CreateMutable(new T[b.Shape[0], b.Shape[1]]);
            var x   = xx.Entity;
            var row = b.Shape[0];
            var col = b.Shape[1];

            for (var j = 0; j < col; ++j)
            {
                var bj = b[Range.Whole, new Index(j, false)];
                var xj = xx[Range.Whole, new Index(j, false)];
                SolveCore(l, u, perms, bj, xj);
            }

            for (var k = perms.Count - 1; k >= 0; --k)
            {
                var(p, q) = perms[k];
                for (var i = 0; i < row; ++i)
                {
                    Span <int> idx1 = stackalloc int[] { i, p };
                    Span <int> idx2 = stackalloc int[] { i, q };
                    InternalUtils.Exchange(ref x[idx1], ref x[idx2]);
                }
            }
            for (var k = perms.Count - 1; k >= 0; --k)
            {
                var(p, q) = perms[k];
                for (var i = 0; i < row; ++i)
                {
                    Span <int> idx1 = stackalloc int[] { i, p };
                    Span <int> idx2 = stackalloc int[] { i, q };
                    InternalUtils.Exchange(ref x[idx1], ref x[idx2]);
                }
            }
            return(xx.MoveToImmutable());
        }