//
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2013 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using IStation.Numerics.LinearAlgebra.Storage;
namespace IStation.Numerics.LinearAlgebra
{
[DebuggerDisplay("Vector {" + nameof(Count) + "}")]
public abstract partial class Vector
{
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
///
/// true if the current object is equal to the parameter; otherwise, false.
///
public bool Equals(Vector other)
{
return other != null && Storage.Equals(other.Storage);
}
///
/// Determines whether the specified is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public sealed override bool Equals(object obj)
{
return obj is Vector other && Storage.Equals(other.Storage);
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public sealed override int GetHashCode()
{
return Storage.GetHashCode();
}
#if !NETSTANDARD1_3
///
/// Creates a new object that is a copy of the current instance.
///
///
/// A new object that is a copy of this instance.
///
object ICloneable.Clone()
{
return Clone();
}
#endif
int IList.IndexOf(T item)
{
for (int i = 0; i < Count; ++i)
{
if (At(i).Equals(item))
return i;
}
return -1;
}
void IList.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
bool ICollection.IsReadOnly => false;
void ICollection.Add(T item)
{
throw new NotSupportedException();
}
bool ICollection.Remove(T item)
{
throw new NotSupportedException();
}
bool ICollection.Contains(T item)
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var x in this)
{
if (x.Equals(item))
return true;
}
return false;
}
void ICollection.CopyTo(T[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
Storage.CopySubVectorTo(new DenseVectorStorage(array.Length, array), 0, arrayIndex, Count);
}
bool IList.IsReadOnly => false;
bool IList.IsFixedSize => true;
object IList.this[int index]
{
get => Storage[index];
set => Storage[index] = (T) value;
}
int IList.IndexOf(object value)
{
if (!(value is T))
{
return -1;
}
return ((IList) this).IndexOf((T) value);
}
bool IList.Contains(object value)
{
if (!(value is T))
{
return false;
}
return ((ICollection) this).Contains((T) value);
}
void IList.Insert(int index, object value)
{
throw new NotSupportedException();
}
int IList.Add(object value)
{
throw new NotSupportedException();
}
void IList.Remove(object value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => Storage;
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
if (array.Rank != 1)
{
throw new ArgumentException("Array must have exactly one dimension (and not be null).", nameof(array));
}
Storage.CopySubVectorTo(new DenseVectorStorage(array.Length, (T[]) array), 0, index, Count);
}
///
/// Returns an enumerator that iterates through the collection.
///
///
/// A that can be used to iterate through the collection.
///
IEnumerator IEnumerable.GetEnumerator()
{
return Enumerate().GetEnumerator();
}
///
/// Returns an enumerator that iterates through a collection.
///
///
/// An object that can be used to iterate through the collection.
///
IEnumerator IEnumerable.GetEnumerator()
{
return Enumerate().GetEnumerator();
}
///
/// Returns a string that describes the type, dimensions and shape of this vector.
///
public virtual string ToTypeString()
{
return FormattableString.Invariant($"{GetType().Name} {Count}-{typeof(T).Name}");
}
public string[,] ToVectorStringArray(int maxPerColumn, int maxCharactersWidth, int padding, string ellipsis, Func formatValue)
{
// enforce minima to avoid pathetic cases
maxPerColumn = Math.Max(maxPerColumn, 3);
maxCharactersWidth = Math.Max(maxCharactersWidth, 16);
var columns = new List>();
int chars = 0;
int offset = 0;
while (offset < Count)
{
// full column
int height = Math.Min(maxPerColumn, Count - offset);
var candidate = FormatCompleteColumn(offset, height, formatValue);
chars += candidate.Item1 + padding;
if (chars > maxCharactersWidth && offset > 0)
{
break;
}
columns.Add(candidate);
offset += height;
}
if (offset < Count)
{
// we're not done yet, but adding the last column has failed
// --> make the last column partial
var last = columns[columns.Count - 1];
var c = last.Item2;
c[c.Length - 2] = ellipsis;
c[c.Length - 1] = formatValue(At(Count - 1));
}
int rows = columns[0].Item2.Length;
int cols = columns.Count;
var array = new string[rows, cols];
int colIndex = 0;
foreach (var column in columns)
{
for (int k = 0; k < column.Item2.Length; k++)
{
array[k, colIndex] = column.Item2[k];
}
for (int k = column.Item2.Length; k < rows; k++)
{
array[k, colIndex] = "";
}
colIndex++;
}
return array;
}
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++)
{
widths[j] = Math.Max(widths[j], array[i, j].Length);
}
}
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++)
{
sb.Append(columnSeparator);
sb.Append(array[i, j].PadLeft(widths[j]));
}
sb.Append(rowSeparator);
}
return sb.ToString();
}
Tuple FormatCompleteColumn(int offset, int height, Func formatValue)
{
var c = new string[height];
int index = 0;
for (var k = 0; k < height; k++)
{
c[index++] = formatValue(At(offset + k));
}
int w = c.Max(x => x.Length);
return new Tuple(w, c);
}
///
/// Returns a string that represents the content of this vector, column by column.
///
/// Maximum number of entries and thus lines per column. Typical value: 12; Minimum: 3.
/// Maximum number of characters per line over all columns. Typical value: 80; Minimum: 16.
/// Character to use to print if there is not enough space to print all entries. Typical value: "..".
/// Character to use to separate two columns on a line. Typical value: " " (2 spaces).
/// Character to use to separate two rows/lines. Typical value: Environment.NewLine.
/// Function to provide a string for any given entry value.
public string ToVectorString(int maxPerColumn, int maxCharactersWidth, string ellipsis, string columnSeparator, string rowSeparator, Func formatValue)
{
return FormatStringArrayToString(
ToVectorStringArray(maxPerColumn, maxCharactersWidth, columnSeparator.Length, ellipsis, formatValue),
columnSeparator, rowSeparator);
}
///
/// Returns a string that represents the content of this vector, column by column.
///
/// Maximum number of entries and thus lines per column. Typical value: 12; Minimum: 3.
/// Maximum number of characters per line over all columns. Typical value: 80; Minimum: 16.
/// Floating point format string. Can be null. Default value: G6.
/// Format provider or culture. Can be null.
public string ToVectorString(int maxPerColumn, int maxCharactersWidth, string format = null, IFormatProvider provider = null)
{
if (format == null)
{
format = "G6";
}
return ToVectorString(maxPerColumn, maxCharactersWidth, "..", " ", Environment.NewLine, x => x.ToString(format, provider));
}
///
/// Returns a string that represents the content of this vector, column by column.
///
/// Floating point format string. Can be null. Default value: G6.
/// Format provider or culture. Can be null.
public string ToVectorString(string format = null, IFormatProvider provider = null)
{
if (format == null)
{
format = "G6";
}
return ToVectorString(12, 80, "..", " ", Environment.NewLine, x => x.ToString(format, provider));
}
///
/// Returns a string that summarizes this vector, column by column and with a type header.
///
/// Maximum number of entries and thus lines per column. Typical value: 12; Minimum: 3.
/// Maximum number of characters per line over all columns. Typical value: 80; Minimum: 16.
/// Floating point format string. Can be null. Default value: G6.
/// Format provider or culture. Can be null.
public string ToString(int maxPerColumn, int maxCharactersWidth, string format = null, IFormatProvider provider = null)
{
return string.Concat(ToTypeString(), Environment.NewLine, ToVectorString(maxPerColumn, maxCharactersWidth, format, provider));
}
///
/// Returns a string that summarizes this vector.
/// The maximum number of cells can be configured in the class.
///
public sealed override string ToString()
{
return string.Concat(ToTypeString(), Environment.NewLine, ToVectorString());
}
///
/// Returns a string that summarizes this vector.
/// The maximum number of cells can be configured in the class.
/// The format string is ignored.
///
public string ToString(string format = null, IFormatProvider formatProvider = null)
{
return string.Concat(ToTypeString(), Environment.NewLine, ToVectorString(format, formatProvider));
}
}
}