/// <summary> /// Creates a new view in which the cols of the matrices are merged. The cols will be in the order /// of the input matrices. If two matrices contain a rows with the same colKey, an exception is thrown. All matricies must have the same /// MissingValue. /// This is a 'view' in the sense that changes to the values in either matrix will be reflected in both. /// </summary> /// <param name="rowsMustMatch">true, to require all matrices to have the same rowKeys in the same order; false, use an intersection of the /// rowKeys in the order of RowKeys of the first matrix.</param> /// <param name="matrices">One or more matricies with which to concatinate cols.</param> public MergeColsView(bool rowsMustMatch, params Matrix <TRowKey, TColKey, TValue>[] matrices) { Helper.CheckCondition(matrices.All(m => m.IsMissing(matrices[0].MissingValue)), () => string.Format(CultureInfo.InvariantCulture, Properties.Resource.ExpectedAllMatricesToHaveSameMissingValue)); _missingValue = matrices[0].MissingValue; IEnumerable <TRowKey> rowKeys = matrices[0].RowKeys; var colKeys = matrices[0].ColKeys.ToList(); _colKeyToMatrix = new Dictionary <TColKey, Matrix <TRowKey, TColKey, TValue> >(); matrices[0].ColKeys.ForEach(colKey => _colKeyToMatrix.Add(colKey, matrices[0])); for (int i = 1; i < matrices.Length; i++) { if (rowsMustMatch) { Helper.CheckCondition(Helper.KeysEqual(matrices[0].IndexOfRowKey, matrices[i].IndexOfRowKey), () => string.Format(CultureInfo.InvariantCulture, Properties.Resource.ExpectedRowsOfMatricesToMatch)); } else { rowKeys = rowKeys.Intersect(matrices[i].RowKeys); } colKeys.AddRange(matrices[i].ColKeys); matrices[i].ColKeys.ForEach(colKey => _colKeyToMatrix.Add(colKey, matrices[i])); } Helper.CheckCondition(colKeys.Count == colKeys.Distinct().Count(), () => string.Format(CultureInfo.InvariantCulture, Properties.Resource.ExpectedUniqueRowKeysInMatrix)); _rowKeys = rowKeys.ToList().AsReadOnly(); _colKeys = colKeys.AsReadOnly(); _indexOfRowKey = _rowKeys.Select((key, i) => new KeyValuePair <TRowKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); _indexOfColKey = _colKeys.Select((key, i) => new KeyValuePair <TColKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); }
/// <summary> /// Creates a new view in which the rows of the matrices are merged. The rows will be in the order /// of the input matrices. If two matrices contain a rows with the same rowKey, an exception is thrown. All matricies must have the same /// MissingValue. /// This is a 'view' in the sense that changes to the values in either matrix will be reflected in both. /// </summary> /// <param name="colsMustMatch">true, to require all matrices to have the same colKeys in the same order; false, use an intersection of the /// colKeys in the order of ColKeys of the first matrix.</param> /// <param name="matrices">One or more matricies with which to concatinate rows.</param> public MergeRowsView(bool colsMustMatch, params Matrix <TRowKey, TColKey, TValue>[] matrices) { Helper.CheckCondition(matrices.Length > 0, Properties.Resource.ExpectedNonZeroLengthArrayOfMatrices); Helper.CheckCondition(matrices.All(m => m.IsMissing(matrices[0].MissingValue)), Properties.Resource.ExpectedAllMatricesToHaveSameMissingValue); _missingValue = matrices[0].MissingValue; IEnumerable <TColKey> colKeys = matrices[0].ColKeys; var rowKeys = matrices[0].RowKeys.ToList(); _rowKeyToMatrix = new Dictionary <TRowKey, Matrix <TRowKey, TColKey, TValue> >(); matrices[0].RowKeys.ForEach(rowKey => _rowKeyToMatrix.Add(rowKey, matrices[0])); for (int i = 1; i < matrices.Length; i++) { if (colsMustMatch) { Helper.CheckCondition(Helper.KeysEqual(matrices[0].IndexOfColKey, matrices[i].IndexOfColKey), Properties.Resource.ExpectedColumnsToMatch); } else { colKeys = colKeys.Intersect(matrices[i].ColKeys); } rowKeys.AddRange(matrices[i].RowKeys); matrices[i].RowKeys.ForEach(rowKey => _rowKeyToMatrix.Add(rowKey, matrices[i])); } Helper.CheckCondition(rowKeys.Count == rowKeys.Distinct().Count(), Properties.Resource.ExpectedUniqueRowKeysInMatrix); _rowKeys = rowKeys.AsReadOnly(); _colKeys = colKeys.ToList().AsReadOnly(); _indexOfRowKey = _rowKeys.Select((key, i) => new KeyValuePair <TRowKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); _indexOfColKey = _colKeys.Select((key, i) => new KeyValuePair <TColKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); }
/// <summary> /// Creates a new view in which the cols of the matrices are merged. The cols will be in the order /// of the input matrices. If two matrices contain a rows with the same colKey, an exception is thrown. All matricies must have the same /// MissingValue. /// This is a 'view' in the sense that changes to the values in either matrix will be reflected in both. /// </summary> /// <param name="rowsMustMatch">true, to require all matrices to have the same rowKeys in the same order; false, use an intersection of the /// rowKeys in the order of RowKeys of the first matrix.</param> /// <param name="matrices">One or more matricies with which to concatinate cols.</param> public MergeColsView(bool rowsMustMatch, params Matrix <TRowKey, TColKey, TValue>[] matrices) { Helper.CheckCondition(matrices.All(m => m.IsMissing(matrices[0].MissingValue)), "Not all matrices have the same missing value."); _missingValue = matrices[0].MissingValue; IEnumerable <TRowKey> rowKeys = matrices[0].RowKeys; var colKeys = matrices[0].ColKeys.ToList(); _colKeyToMatrix = new Dictionary <TColKey, Matrix <TRowKey, TColKey, TValue> >(); matrices[0].ColKeys.ForEach(colKey => _colKeyToMatrix.Add(colKey, matrices[0])); for (int i = 1; i < matrices.Length; i++) { if (rowsMustMatch) { Helper.CheckCondition(Helper.KeysEqual(matrices[0].IndexOfRowKey, matrices[i].IndexOfRowKey), "The rows of the matrices do not match"); } else { rowKeys = rowKeys.Intersect(matrices[i].RowKeys); } colKeys.AddRange(matrices[i].ColKeys); matrices[i].ColKeys.ForEach(colKey => _colKeyToMatrix.Add(colKey, matrices[i])); } Helper.CheckCondition(colKeys.Count == colKeys.Distinct().Count(), "There are duplicate rows in the matrices."); _rowKeys = rowKeys.ToList().AsReadOnly(); _colKeys = colKeys.AsReadOnly(); _indexOfRowKey = _rowKeys.Select((key, i) => new KeyValuePair <TRowKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); _indexOfColKey = _colKeys.Select((key, i) => new KeyValuePair <TColKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); }
/// <summary> /// Creates a new view in which the rows of the matrices are merged. The rows will be in the order /// of the input matrices. If two matrices contain a rows with the same rowKey, an exception is thrown. All matricies must have the same /// MissingValue. /// This is a 'view' in the sense that changes to the values in either matrix will be reflected in both. /// </summary> /// <param name="colsMustMatch">true, to require all matrices to have the same colKeys in the same order; false, use an intersection of the /// colKeys in the order of ColKeys of the first matrix.</param> /// <param name="matrices">One or more matricies with which to concatinate rows.</param> public MergeRowsView(bool colsMustMatch, params Matrix <TRowKey, TColKey, TValue>[] matrices) { Helper.CheckCondition(matrices.Length > 0, () => Properties.Resource.ExpectedNonZeroLengthArrayOfMatrices); Helper.CheckCondition(matrices.All(m => m.IsMissing(matrices[0].MissingValue)), () => Properties.Resource.ExpectedAllMatricesToHaveSameMissingValue); _missingValue = matrices[0].MissingValue; IEnumerable <TColKey> colKeys = matrices[0].ColKeys; var rowKeys = matrices[0].RowKeys.ToList(); _rowKeyToMatrix = new Dictionary <TRowKey, Matrix <TRowKey, TColKey, TValue> >(); matrices[0].RowKeys.ForEach(rowKey => _rowKeyToMatrix.Add(rowKey, matrices[0])); for (int i = 1; i < matrices.Length; i++) { if (colsMustMatch) { Helper.CheckCondition(Helper.KeysEqual(matrices[0].IndexOfColKey, matrices[i].IndexOfColKey), () => Properties.Resource.ExpectedColumnsToMatch); } else { colKeys = colKeys.Intersect(matrices[i].ColKeys); } //rowKeys.AddRange(matrices[i].RowKeys); foreach (var rowKey in matrices[i].RowKeys) { if (_rowKeyToMatrix.ContainsKey(rowKey)) { var prevMatrix = _rowKeyToMatrix[rowKey]; // check that all the values are identical. not that GetValueOrMissing().Equals is not safe because missing value may be null. Helper.CheckCondition <System.ArgumentException>(colKeys.All(colKey => prevMatrix.IsMissing(rowKey, colKey) ? matrices[i].IsMissing(rowKey, colKey) : prevMatrix[rowKey, colKey].Equals(matrices[i].GetValueOrMissing(rowKey, colKey))), Properties.Resource.ThereAreDuplicateRowsWhichDoNotHDupRowsNonIdenticalValues); } else { _rowKeyToMatrix.Add(rowKey, matrices[i]); rowKeys.Add(rowKey); } } //matrices[i].RowKeys.ForEach(rowKey => _rowKeyToMatrix.Add(rowKey, matrices[i])); } Helper.CheckCondition(rowKeys.Count == rowKeys.Distinct().Count(), () => Properties.Resource.ExpectedUniqueRowKeysInMatrix); _rowKeys = rowKeys.AsReadOnly(); _colKeys = colKeys.ToList().AsReadOnly(); _indexOfRowKey = _rowKeys.Select((key, i) => new KeyValuePair <TRowKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); _indexOfColKey = _colKeys.Select((key, i) => new KeyValuePair <TColKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); }
/// <summary> /// Creates a new view in which the rows of the matrices are merged. The rows will be in the order /// of the input matrices. If two matrices contain a rows with the same rowKey, an exception is thrown. All matricies must have the same /// MissingValue. /// This is a 'view' in the sense that changes to the values in either matrix will be reflected in both. /// </summary> /// <param name="colsMustMatch">true, to require all matrices to have the same colKeys in the same order; false, use an intersection of the /// colKeys in the order of ColKeys of the first matrix.</param> /// <param name="matrices">One or more matricies with which to concatinate rows.</param> public MergeRowsView(bool colsMustMatch, params Matrix <TRowKey, TColKey, TValue>[] matrices) { Helper.CheckCondition(matrices.Length > 0, "At least once matrix expected."); Helper.CheckCondition(matrices.All(m => m.IsMissing(matrices[0].MissingValue)), "Not all matrices have the same missing value."); _missingValue = matrices[0].MissingValue; IEnumerable <TColKey> colKeys = matrices[0].ColKeys; var rowKeys = matrices[0].RowKeys.ToList(); _rowKeyToMatrix = new Dictionary <TRowKey, Matrix <TRowKey, TColKey, TValue> >(); matrices[0].RowKeys.ForEach(rowKey => _rowKeyToMatrix.Add(rowKey, matrices[0])); for (int i = 1; i < matrices.Length; i++) { if (colsMustMatch) { Helper.CheckCondition(Helper.KeysEqual(matrices[0].IndexOfColKey, matrices[i].IndexOfColKey), "The columns of the two matrices do not match"); } else { colKeys = colKeys.Intersect(matrices[i].ColKeys); } //rowKeys.AddRange(matrices[i].RowKeys); foreach (var rowKey in matrices[i].RowKeys) { if (_rowKeyToMatrix.ContainsKey(rowKey)) { var prevMatrix = _rowKeyToMatrix[rowKey]; // check that all the values are identical. not that GetValueOrMissing().Equals is not safe because missing value may be null. Helper.CheckCondition <System.ArgumentException>(colKeys.All(colKey => prevMatrix.IsMissing(rowKey, colKey) ? matrices[i].IsMissing(rowKey, colKey) : prevMatrix[rowKey, colKey].Equals(matrices[i].GetValueOrMissing(rowKey, colKey))), "There are duplicate rows which do not have identical values."); } else { _rowKeyToMatrix.Add(rowKey, matrices[i]); rowKeys.Add(rowKey); } } //matrices[i].RowKeys.ForEach(rowKey => _rowKeyToMatrix.Add(rowKey, matrices[i])); } Helper.CheckCondition(rowKeys.Count == rowKeys.Distinct().Count(), "There are duplicate rows in the matrices."); _rowKeys = rowKeys.AsReadOnly(); _colKeys = colKeys.ToList().AsReadOnly(); _indexOfRowKey = _rowKeys.Select((key, i) => new KeyValuePair <TRowKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); _indexOfColKey = _colKeys.Select((key, i) => new KeyValuePair <TColKey, int>(key, i)).ToDictionary().AsRestrictedAccessDictionary(); }
//private Converter<int, TVal> _fnStateToTVal; //private Converter<TVal, int> _fnTValToState; /// <summary> /// Creates a this wrapper. /// </summary> /// <param name="binaryMatrixToWrap">Must have values that map to 0/1</param> /// <param name="multistateKeyToOrderedBinaryKeys">First key is multistate name (e.g. 1@A#B#C), the value is an enumeration of binary keys that map to the multistate keys. /// The order specifies the state value in multistate space. (e.g. 1@A is state 0, 1@B is state 2, 1@C is state 2)</param> /// <param name="convertTValToMultinomial">Specifies how to convert from TVal to 0,1,2,3... and back. 0/1 are used for binary, 0..N are assumed to be used by the multistate matrix.</param> public BinaryToMultistateView( Matrix <TRowKey, TColKey, TVal> binaryMatrixToWrap, IEnumerable <KeyValuePair <TRowKey, IEnumerable <TRowKey> > > multistateKeyToOrderedBinaryKeys, ValueConverter <TVal, Multinomial> convertTValToMultinomial) { _binaryMatrix = binaryMatrixToWrap; _multKeyToBinaryKeys = multistateKeyToOrderedBinaryKeys.Select(pair => new KeyValuePair <TRowKey, List <TRowKey> >(pair.Key, pair.Value.ToList())).ToDictionary(); //_fnStateToTVal = fnStateToTVal; //_fnTValToState = fnTValToBinaryState; _cnvrtTValToState = convertTValToMultinomial; _rowKeys = new ReadOnlyCollection <TRowKey>(multistateKeyToOrderedBinaryKeys.Select(pair => pair.Key).ToList()); _indexOfRowKey = new RestrictedAccessDictionary <TRowKey, int>(_rowKeys.Select((key, idx) => new KeyValuePair <TRowKey, int>(key, idx)).ToDictionary()); }
//private Converter<int, TVal> _fnStateToTVal; //private Converter<TVal, int> _fnTValToState; /// <summary> /// Creates a this wrapper. /// </summary> /// <param name="multistateMatrixToWrap"></param> /// <param name="multistateKeyToOrderedBinaryKeys">First key is multistate name (e.g. 1@A#B#C), the value is an enumeration of binary keys that map to the multistate keys. /// The order specifies the state value in multistate space. (e.g. 1@A is state 0, 1@B is state 2, 1@C is state 2)</param> /// <param name="convertTValToInt">Specifies how to convert from TVal to 0,1,2,3... and back. 0/1 are used for binary, 0..N are assumed to be used by the multistate matrix.</param> public MultistateToBinaryView( Matrix <TRowKey, TColKey, TVal> multistateMatrixToWrap, IEnumerable <KeyValuePair <TRowKey, IEnumerable <TRowKey> > > multistateKeyToOrderedBinaryKeys, ValueConverter <TVal, int> convertTValToInt) //Converter<int, TVal> fnStateToTVal, //Converter<TVal, int> fnTValToBinaryState) { _multistateMatrix = multistateMatrixToWrap; _binaryKeyToMultKeyAndState = multistateKeyToOrderedBinaryKeys.SelectMany(mAndB => mAndB.Value.Select((b, idx) => new KeyValuePair <TRowKey, KeyValuePair <TRowKey, int> >(b, new KeyValuePair <TRowKey, int>(mAndB.Key, idx)))).ToDictionary(); _cnvrtTValToState = convertTValToInt; //_fnStateToTVal = fnStateToTVal; //_fnTValToState = fnTValToBinaryState; _rowKeys = new ReadOnlyCollection <TRowKey>(multistateKeyToOrderedBinaryKeys.SelectMany(pair => pair.Value).ToList()); _indexOfRowKey = new RestrictedAccessDictionary <TRowKey, int>(_rowKeys.Select((key, idx) => new KeyValuePair <TRowKey, int>(key, idx)).ToDictionary()); }
private void RenameColsViewInternal(Matrix <TRowKey, TColKey, TValue> parentMatrix, IEnumerable <KeyValuePair <TColKey, TColKey> > newNameAndOldNameSequence) { NewKeyToOldKey = newNameAndOldNameSequence.ToDictionary(pair => pair.Key, pair => pair.Value).AsRestrictedAccessDictionary(); var unmatchedCols = NewKeyToOldKey.Values.Except(parentMatrix.ColKeys).ToList(); Helper.CheckCondition(unmatchedCols.Count == 0, Properties.Resource.ExpectedEveryRemappedColKeyToBeInOriginalMatrix, unmatchedCols.StringJoin(",")); ParentMatrix = parentMatrix; _colKeys = NewKeyToOldKey.Select(pair => pair.Key).ToList().AsReadOnly(); _indexOfColKey = _colKeys.Select((key, idx) => new KeyValuePair <TColKey, int>(key, idx)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value).AsRestrictedAccessDictionary(); NewIndexToOldIndex = ( from newIndex in Enumerable.Range(0, ColCount) let newKey = ColKeys[newIndex] let oldKey = NewKeyToOldKey[newKey] let oldIndex = parentMatrix.IndexOfColKey[oldKey] select oldIndex ).ToList().AsReadOnly(); }
internal void InitializeIndexMaps() { var rowKeys = new Dictionary <TRowKey, int>(_rowKeys.Count); var colKeys = new Dictionary <TColKey, int>(_colKeys.Count); int rowIdx = 0; foreach (TRowKey rowKey in RowKeys) { rowKeys.Add(rowKey, rowIdx); rowIdx++; } int colIdx = 0; foreach (TColKey colKey in ColKeys) { colKeys.Add(colKey, colIdx); colIdx++; } _indexOfRowKey = rowKeys.AsRestrictedAccessDictionary(); _indexOfColKey = colKeys.AsRestrictedAccessDictionary(); }