diff --git a/build.fsx b/build.fsx index dfc3fd33..b7581440 100644 --- a/build.fsx +++ b/build.fsx @@ -361,6 +361,7 @@ let provideReadme title releasenotes path = |> ReplaceFile (path @@ "readme.txt") let provideFsLoader includes path = + // inspired by FsLab/tpetricek let fullScript = ReadFile "src/FSharp/MathNet.Numerics.fsx" |> Array.ofSeq let startIndex = fullScript |> Seq.findIndex (fun s -> s.Contains "***MathNet.Numerics.fsx***") let extraScript = fullScript .[startIndex + 1 ..] |> List.ofSeq diff --git a/src/Numerics/LinearAlgebra/Matrix.BCL.cs b/src/Numerics/LinearAlgebra/Matrix.BCL.cs index aa8dfeff..af555eba 100644 --- a/src/Numerics/LinearAlgebra/Matrix.BCL.cs +++ b/src/Numerics/LinearAlgebra/Matrix.BCL.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2014 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -29,7 +29,9 @@ // using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Text; namespace MathNet.Numerics.LinearAlgebra @@ -91,7 +93,7 @@ namespace MathNet.Numerics.LinearAlgebra #endif /// - /// Returns a that describes the type, dimensions and shape of this matrix. + /// Returns a string that describes the type, dimensions and shape of this matrix. /// public virtual string ToTypeString() { @@ -99,131 +101,274 @@ namespace MathNet.Numerics.LinearAlgebra } /// - /// Returns a that represents the content of this matrix. + /// Returns a string 2D array that summarizes the content of this matrix. /// - public string ToMatrixString(int maxRows, int maxColumns, IFormatProvider provider = null) + public string[,] ToMatrixStringArray(int upperRows, int lowerRows, int leftColumns, int rightColumns, + string horizontalEllipsis, string verticalEllipsis, string diagonalEllipsis, Func formatValue) { - return ToMatrixString(maxRows, maxColumns, 12, "G6", provider); + int upper = RowCount <= upperRows ? RowCount : upperRows; + int lower = RowCount <= upperRows ? 0 : RowCount <= upperRows + lowerRows ? RowCount - upperRows : lowerRows; + bool rowEllipsis = RowCount > upper + lower; + int rows = rowEllipsis ? upper + lower + 1 : upper + lower; + + int left = ColumnCount <= leftColumns ? ColumnCount : leftColumns; + int right = ColumnCount <= leftColumns ? 0 : ColumnCount <= leftColumns + rightColumns ? RowCount - leftColumns : rightColumns; + bool colEllipsis = ColumnCount > left + right; + int cols = colEllipsis ? left + right + 1 : left + right; + + var array = new string[rows, cols]; + for (int i = 0; i < upper; i++) + { + for (int j = 0; j < left; j++) + { + array[i, j] = formatValue(At(i, j)); + } + if (colEllipsis) + { + array[i, left] = horizontalEllipsis; + } + for (int j = 0; j < right; j++) + { + array[i, left + 1 + j] = formatValue(At(i, ColumnCount - right + j)); + } + } + if (rowEllipsis) + { + for (int j = 0; j < left; j++) + { + array[upper, j] = verticalEllipsis; + } + if (colEllipsis) + { + array[upper, left] = diagonalEllipsis; + } + for (int j = 0; j < right; j++) + { + array[upper, left + 1 + j] = verticalEllipsis; + } + } + for (int i = 0; i < lower; i++) + { + for (int j = 0; j < left; j++) + { + array[upper + 1 + i, j] = formatValue(At(RowCount - lower + i, j)); + } + if (colEllipsis) + { + array[upper + 1 + i, left] = horizontalEllipsis; + } + for (int j = 0; j < right; j++) + { + array[upper + 1 + i, left + 1 + j] = formatValue(At(RowCount - lower + i, ColumnCount - right + j)); + } + } + return array; } /// - /// Returns a that represents the content of this matrix. + /// Returns a string 2D array that summarizes the content of this matrix. /// - public string ToMatrixString(int maxRows, int maxColumns, int padding, string format = null, IFormatProvider provider = null) + public string[,] ToMatrixStringArray(int upperRows, int lowerRows, int minLeftColumns, int rightColumns, int maxWidth, int padding, + string horizontalEllipsis, string verticalEllipsis, string diagonalEllipsis, Func formatValue) { - int rowN = RowCount <= maxRows ? RowCount : maxRows < 3 ? maxRows : maxRows - 1; - bool rowDots = maxRows < RowCount; - bool rowLast = rowDots && maxRows > 2; + int upper = RowCount <= upperRows ? RowCount : upperRows; + int lower = RowCount <= upperRows ? 0 : RowCount <= upperRows + lowerRows ? RowCount - upperRows : lowerRows; + bool rowEllipsis = RowCount > upper + lower; + int rows = rowEllipsis ? upper + lower + 1 : upper + lower; - int colN = ColumnCount <= maxColumns ? ColumnCount : maxColumns < 3 ? maxColumns : maxColumns - 1; - bool colDots = maxColumns < ColumnCount; - bool colLast = colDots && maxColumns > 2; + int left = ColumnCount <= minLeftColumns ? ColumnCount : minLeftColumns; + int right = ColumnCount <= minLeftColumns ? 0 : ColumnCount <= minLeftColumns + rightColumns ? RowCount - minLeftColumns : rightColumns; - const string separator = " "; - const string dots = "..."; - string pdots = "...".PadLeft(padding); + var columnsLeft = new List>(); + for (int j = 0; j < left; j++) + { + columnsLeft.Add(FormatColumn(j, rows, upper, lower, rowEllipsis, verticalEllipsis, formatValue)); + } - if (format == null) + var columnsRight = new List>(); + for (int j = 0; j < right; j++) { - format = "G8"; + columnsRight.Add(FormatColumn(ColumnCount - right + j, rows, upper, lower, rowEllipsis, verticalEllipsis, formatValue)); } - var stringBuilder = new StringBuilder(); + int chars = columnsLeft.Sum(t => t.Item1 + padding) + columnsRight.Sum(t => t.Item1 + padding); + for (int j = left; j < ColumnCount - right; j++) + { + var candidate = FormatColumn(j, rows, upper, lower, rowEllipsis, verticalEllipsis, formatValue); + chars += candidate.Item1 + padding; + if (chars > maxWidth) + { + break; + } + columnsLeft.Add(candidate); + } - for (var row = 0; row < rowN; row++) + int cols = columnsLeft.Count + columnsRight.Count; + bool colEllipsis = ColumnCount > cols; + if (colEllipsis) { - if (row > 0) + cols++; + } + + var array = new string[rows, cols]; + int colIndex = 0; + foreach (var column in columnsLeft) + { + for (int i = 0; i < column.Item2.Length; i++) { - stringBuilder.Append(Environment.NewLine); + array[i, colIndex] = column.Item2[i]; } - stringBuilder.Append(At(row, 0).ToString(format, provider).PadLeft(padding)); - for (var column = 1; column < colN; column++) + colIndex++; + } + if (colEllipsis) + { + int rowIndex = 0; + for (var row = 0; row < upper; row++) { - stringBuilder.Append(separator); - stringBuilder.Append(At(row, column).ToString(format, provider).PadLeft(padding)); + array[rowIndex++, colIndex] = horizontalEllipsis; } - if (colDots) + if (rowEllipsis) { - stringBuilder.Append(separator); - stringBuilder.Append(dots); - if (colLast) - { - stringBuilder.Append(separator); - stringBuilder.Append(At(row, ColumnCount - 1).ToString(format, provider).PadLeft(12)); - } + array[rowIndex++, colIndex] = diagonalEllipsis; } - } - - if (rowDots) - { - stringBuilder.Append(Environment.NewLine); - stringBuilder.Append(pdots); - for (var column = 1; column < colN; column++) + for (var row = RowCount - lower; row < RowCount; row++) { - stringBuilder.Append(separator); - stringBuilder.Append(pdots); + array[rowIndex++, colIndex] = horizontalEllipsis; } - if (colDots) + colIndex++; + } + foreach (var column in columnsRight) + { + for (int i = 0; i < column.Item2.Length; i++) { - stringBuilder.Append(separator); - stringBuilder.Append(dots); - if (colLast) - { - stringBuilder.Append(separator); - stringBuilder.Append(pdots); - } + array[i, colIndex] = column.Item2[i]; } + colIndex++; } + return array; + } - if (rowLast) + Tuple FormatColumn(int column, int height, int upper, int lower, bool withEllipsis, string ellipsis, Func formatValue) + { + var c = new string[height]; + int index = 0; + for (var row = 0; row < upper; row++) { - stringBuilder.Append(Environment.NewLine); - stringBuilder.Append(At(RowCount - 1, 0).ToString(format, provider).PadLeft(padding)); - for (var column = 1; column < colN; column++) + c[index++] = formatValue(At(row, column)); + } + if (withEllipsis) + { + c[index++] = ""; + } + for (var row = RowCount - lower; row < RowCount; row++) + { + c[index++] = formatValue(At(row, column)); + } + int w = c.Max(x => x.Length); + if (withEllipsis) + { + c[upper] = ellipsis; + } + return new Tuple(w, c); + } + + static string FormatStringArrayToString(string[,] array, string columnSeparator, string rowSeparator) + { + var rows = array.GetLength(0); + var cols = array.GetLength(1); + + var widths = new int[cols]; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < cols; j++) { - stringBuilder.Append(separator); - stringBuilder.Append(At(RowCount - 1, column).ToString(format, provider).PadLeft(padding)); + widths[j] = Math.Max(widths[j], array[i, j].Length); } - if (colDots) + } + + var sb = new StringBuilder(); + for (int i = 0; i < rows; i++) + { + sb.Append(array[i, 0].PadLeft(widths[0])); + for (int j = 1; j < cols; j++) { - stringBuilder.Append(separator); - stringBuilder.Append(dots); - if (colLast) - { - stringBuilder.Append(separator); - stringBuilder.Append(At(RowCount - 1, ColumnCount - 1).ToString(format, provider).PadLeft(padding)); - } + sb.Append(columnSeparator); + sb.Append(array[i, j].PadLeft(widths[j])); } + sb.Append(rowSeparator); + } + return sb.ToString(); + } + + public string ToMatrixString(int upperRows, int lowerRows, int leftColumns, int rightColumns, + string horizontalEllipsis, string verticalEllipsis, string diagonalEllipsis, + string columnSeparator, string rowSeparator, Func formatValue) + { + return FormatStringArrayToString( + ToMatrixStringArray(upperRows, lowerRows, leftColumns, rightColumns, horizontalEllipsis, verticalEllipsis, diagonalEllipsis, formatValue), + columnSeparator, rowSeparator); + } + + public string ToMatrixString(int upperRows, int lowerRows, int minLeftColumns, int rightColumns, int maxWidth, + string horizontalEllipsis, string verticalEllipsis, string diagonalEllipsis, + string columnSeparator, string rowSeparator, Func formatValue) + { + return FormatStringArrayToString( + ToMatrixStringArray(upperRows, lowerRows, minLeftColumns, rightColumns, maxWidth, columnSeparator.Length, horizontalEllipsis, verticalEllipsis, diagonalEllipsis, formatValue), + columnSeparator, rowSeparator); + } + + /// + /// Returns a string that summarizes the content of this matrix. + /// + public string ToMatrixString(int maxRows, int maxColumns, string format = null, IFormatProvider provider = null) + { + if (format == null) + { + format = "G6"; + } + + return ToMatrixString(maxRows - 2, 2, maxColumns - 2, 2, "..", "..", "..", " ", Environment.NewLine, x => x.ToString(format, provider)); + } + + /// + /// Returns a string that summarizes the content of this matrix. + /// + public string ToMatrixString(string format = null, IFormatProvider provider = null) + { + if (format == null) + { + format = "G6"; } - return stringBuilder.ToString(); + return ToMatrixString(8, 4, 5, 2, 76, "..", "..", "..", " ", Environment.NewLine, x => x.ToString(format, provider)); } /// - /// Returns a that summarizes this matrix. + /// Returns a string that summarizes this matrix. /// - public string ToString(int maxRows, int maxColumns, IFormatProvider provider = null) + public string ToString(int maxRows, int maxColumns, string format = null, IFormatProvider formatProvider = null) { - return string.Concat(ToTypeString(), Environment.NewLine, ToMatrixString(maxRows, maxColumns, provider)); + return string.Concat(ToTypeString(), Environment.NewLine, ToMatrixString(maxRows, maxColumns, format, formatProvider)); } /// - /// Returns a that summarizes this matrix. + /// Returns a string that summarizes this matrix. /// The maximum number of cells can be configured in the class. /// public override sealed string ToString() { - return string.Concat(ToTypeString(), Environment.NewLine, ToMatrixString(Control.MaxToStringRows, Control.MaxToStringColumns)); + return string.Concat(ToTypeString(), Environment.NewLine, ToMatrixString()); } /// - /// Returns a that summarizes this matrix. + /// Returns a string that summarizes this matrix. /// The maximum number of cells can be configured in the class. /// The format string is ignored. /// - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string format = null, IFormatProvider formatProvider = null) { - return string.Concat(ToTypeString(), Environment.NewLine, ToMatrixString(Control.MaxToStringRows, Control.MaxToStringColumns, formatProvider)); + return string.Concat(ToTypeString(), Environment.NewLine, ToMatrixString(format, formatProvider)); } } }