예제 #1
0
        private void ResizeFirstDimension(int[] newShape)
        {
            var valuesToAddCount = MultiDimensionalArrayHelper.GetTotalLength(newShape) - MultiDimensionalArrayHelper.GetTotalLength(shape);

            if (valuesToAddCount > 0)
            {
                /*
                 * bool generateUniqueValueForDefaultValue = false;
                 * if (null != Owner)
                 * {
                 *  generateUniqueValueForDefaultValue = Owner.GenerateUniqueValueForDefaultValue;
                 *  // newly added function should be unique
                 *  Owner.GenerateUniqueValueForDefaultValue = true;
                 * }s*/
                AddValuesToFirstDimension(newShape, valuesToAddCount);

                /*if (null != Owner)
                 * {
                 *  Owner.GenerateUniqueValueForDefaultValue = generateUniqueValueForDefaultValue;
                 * }*/
            }
            else if (valuesToAddCount < 0)// remove values at the end.
            {
                RemoveValuesFromFirstDimension(newShape, valuesToAddCount);
            }
            else
            {
                Shape = newShape;
            }
        }
예제 #2
0
        //TODO: rewrite this to use RemoveAt(index,dimension,length)
        public virtual void RemoveAt(int index)
        {
            VerifyIsNotReadOnly();
            if (rank == 1)
            {
                var valueToRemove = values[index];

                if (FireEvents)
                {
                    var args = FireCollectionChanging(NotifyCollectionChangeAction.Remove, valueToRemove, index);

                    if (args != null && args.Cancel)
                    {
                        return;
                    }
                }

                RemoveAt1D(index);



                shape[0]--;
                count = MultiDimensionalArrayHelper.GetTotalLength(shape);

                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangeAction.Remove, valueToRemove, index, -1);
                }
            }
            else
            {
                throw new NotSupportedException("Use Resize");
            }
        }
예제 #3
0
        public void Insert(int index, object value)
        {
            if (rank != 1)
            {
                throw new NotSupportedException("Use SetValue to set values");
            }

            var newValue = value;

            if (FireEvents)
            {
                var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, newValue, index, singleValueLength);
                if (args != null)
                {
                    if (args.Cancel)
                    {
                        return;
                    }
                    newValue = args.Item;
                }
            }

            values.Insert(index, newValue);

            shape[0]++;
            count = MultiDimensionalArrayHelper.GetTotalLength(shape);

            if (FireEvents)
            {
                FireCollectionChanged(NotifyCollectionChangedAction.Add, newValue, index, -1, singleValueLength);
            }
        }
예제 #4
0
        public virtual void Insert(int index, object value)
        {
            VerifyIsNotReadOnly();
            if (rank != 1)
            {
                throw new NotSupportedException("Use SetValue to set values");
            }

            var newValue = value;

            if (FireEvents)
            {
                var args = FireCollectionChanging(NotifyCollectionChangeAction.Add, newValue, index);
                if (args != null)
                {
                    if (args.Cancel)
                    {
                        return;
                    }
                    newValue = args.Items[0];
                }
            }
            //InsertValues1D(index, newValue);
            InsertValues1D(newValue, index);

            shape[0]++;
            count = MultiDimensionalArrayHelper.GetTotalLength(shape);
            dirty = true;//update min/max after insert..maybe check if the value we inserted is > max or < min

            if (FireEvents)
            {
                FireCollectionChanged(NotifyCollectionChangeAction.Add, newValue, index, -1);
            }
        }
        public bool MoveNext()
        {
            //instead of using count this should be faster.
            foreach (var i in array.Shape)
            {
                if (i == 0)
                {
                    return(false);
                }
            }

            return(MultiDimensionalArrayHelper.IncrementIndex(index, array.Shape, array.Rank - 1));
        }
예제 #6
0
        /// <summary>
        /// Creates a new multidimensional array using provided values as 1D array.
        /// Values in the provided list will used in a row-major order.
        /// </summary>
        /// <param name="isReadOnly"></param>
        /// <param name="isFixedSize"></param>
        /// <param name="defaultValue"></param>
        /// <param name="values"></param>
        /// <param name="shape"></param>
        public MultiDimensionalArray(bool isReadOnly, bool isFixedSize, object defaultValue, IList values, int[] shape)
        {
            if (values.Count != MultiDimensionalArrayHelper.GetTotalLength(shape))
            {
                throw new ArgumentException("Copy constructor shape does not match values");
            }
            IsReadOnly  = isReadOnly;
            IsFixedSize = isFixedSize;

            DefaultValue = defaultValue;

            Shape = (int[])shape.Clone();

            SetValues(CreateClone(values));
        }
예제 #7
0
        private object[] GetDefaultValuesToAdd(int dimension, int length)
        {
            var valuesToAddShape = (int[])shape.Clone();

            valuesToAddShape[dimension] = length;
            var newValuesCount = MultiDimensionalArrayHelper.GetTotalLength(valuesToAddShape);

            var valuesToAdd = new object[newValuesCount];

            for (var i = 0; i < newValuesCount; i++)
            {
                valuesToAdd[i] = defaultValue;
            }
            return(valuesToAdd);
        }
        private void SetDependendVariabeleValues <T>(IVariable variable, IVariableFilter[] filters, IEnumerable <T> values)
        {
            IMultiDimensionalArray componentArrayView = CreateComponentArrayFromFilters(variable, filters);

            //iterate every value of the view set values for all components.
            IEnumerator enumerator = values.GetEnumerator();
            int         size       = componentArrayView.Count;

            //this check is to prevent code like f[1] = new[]{1,2,3} where the 2,3 are silently ignored.
            //if performance penalty is high here the check should go
            int count = values.Count();

            if (count > size)
            {
                throw new ArgumentException(string.Format("Number of values to be written to dependent variable '{0}' exceeds argument values range. Got {1} values expected at most {2}.", variable.Name, count, size));
            }

            int[] stride = MultiDimensionalArrayHelper.GetStride(componentArrayView.Shape);


            var valuesList = values as IList <T>;

            if (valuesList == null)
            {
                valuesList = values.ToList();
            }

            if (!valuesList.Any())
            {
                return;
            }

            var valuesListCount = valuesList.Count; //retrieve count once!

            for (int i = 0, j = 0; i < size; i++, j++)
            {
                int[] indexes = MultiDimensionalArrayHelper.GetIndex(i, stride);

                if (j == valuesListCount)
                {
                    j = 0;                     // reset index, repeat from start
                }
                componentArrayView[indexes] = valuesList[j];
            }
        }
예제 #9
0
        /// <summary>
        /// Compute index in filtered multi-dimensional array based on index in parent multi-dimensional array
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private int GetComponentValueIndexInChildComponent(int[] index, int[] stride)
        {
            var childIndex = new int[index.Length];

            for (var i = 0; i < index.Length; i++)
            {
                var argument       = Arguments[i];
                var argumentParent = (IVariable)Arguments[i].Parent;

                childIndex[i] = argument.Values.IndexOf(argumentParent.Values[index[i]]);
                if (childIndex[i] == -1)
                {
                    return(-1); // argument value is filtered
                }
            }

            return(MultiDimensionalArrayHelper.GetIndex1d(childIndex, stride));
        }
예제 #10
0
        public virtual void RemoveAt(int dimension, int index, int length)
        {
            VerifyIsNotReadOnly();
            if (rank == 1)
            {
                var elementsToRemove = length;
                while (elementsToRemove != 0)
                {
                    RemoveAt(index);
                    elementsToRemove--;
                }
            }
            else
            {
                //move items
                if (dimension > 0 || index != shape[dimension] - 1) // don't copy when 1st dimension and delete at the end (note: performance)
                {
                    for (var i = 0; i < count; i++)                 // TODO: optimize this, probably it is better to iterate in nD array instead of 1d
                    {
                        var currentIndex = MultiDimensionalArrayHelper.GetIndex(i, stride);

                        if ((currentIndex[dimension] < index) ||
                            (currentIndex[dimension] >= (shape[dimension] - length)))
                        {
                            continue;
                        }

                        // value is to be moved to a new spot in the array
                        var oldIndexes = (int[])currentIndex.Clone();
                        oldIndexes[dimension] += length;
                        values[i]              = values[MultiDimensionalArrayHelper.GetIndex1d(oldIndexes, stride)];
                    }
                }

                //trim the array
                var newShape = (int[])shape.Clone();
                if (newShape[dimension] > 0)
                {
                    newShape[dimension] -= length;
                }

                Resize(newShape);
            }
        }
예제 #11
0
        public virtual int Add(object value)
        {
            if (rank == 1)
            {
                var index    = count;
                var newValue = value;
                if (FireEvents)
                {
                    var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, newValue, index, singleValueLength);
                    if (args != null)
                    {
                        if (args.Cancel)
                        {
                            return(-1);
                        }

                        newValue = args.Item;
                        index    = args.Index; //index might be changed by changing listeners forcing a sort.
                    }
                }
                values.Insert(index, newValue);

                if (newValue is INotifyPropertyChanged)
                {
                    ((INotifyPropertyChanged)newValue).PropertyChanged += Item_PropertyChanged;
                }

                shape[0]++;
                count = MultiDimensionalArrayHelper.GetTotalLength(shape);

                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangedAction.Add, newValue, index, -1, singleValueLength);
                }

                return(index);
            }

            throw new NotSupportedException("Use Resize() and this[] to work with array where number of dimensions > 1");
        }
예제 #12
0
        private void SetDependendVariabeleValues <T>(IVariable variable, IVariableFilter[] filters, IEnumerable <T> values)
        {
            IMultiDimensionalArray componentArrayView = CreateComponentArrayFromFilters(variable, filters);

            //iterate every value of the view set values for all components.
            IEnumerator enumerator = values.GetEnumerator();
            int         size       = componentArrayView.Count;

            int[] stride = MultiDimensionalArrayHelper.GetStride(componentArrayView.Shape);

            for (int i = 0; i < size; i++)
            {
                int[] indexes = MultiDimensionalArrayHelper.GetIndex(i, stride);
                //travese our values. Reset if we run out of values
                if (!enumerator.MoveNext())
                {
                    enumerator.Reset();
                    enumerator.MoveNext();
                }
                componentArrayView[indexes] = enumerator.Current;
            }
        }
예제 #13
0
        public override object this[params int[] index]
        {
            get
            {
                if (index.Length == 1 && Rank != 1) // use 1D access
                {
                    int[] stride = MultiDimensionalArrayHelper.GetStride(Shape);
                    return(parent[GetIndexInParent(MultiDimensionalArrayHelper.GetIndex(index[0], stride))]);
                }

                return(parent[GetIndexInParent(index)]);
            }
            set
            {
                if (index.Length == 1 && Rank != 1) // use 1D access
                {
                    int[] stride = MultiDimensionalArrayHelper.GetStride(Shape);
                    parent[GetIndexInParent(MultiDimensionalArrayHelper.GetIndex(index[0], stride))] = value;
                    return;
                }

                parent[GetIndexInParent(index)] = value;
            }
        }
예제 #14
0
        public virtual void RemoveAt(int index)
        {
            if (rank == 1)
            {
                var valueToRemove = values[index];

                if (FireEvents)
                {
                    var args = FireCollectionChanging(NotifyCollectionChangedAction.Remove, valueToRemove, index, singleValueLength);

                    if (args != null && args.Cancel)
                    {
                        return;
                    }
                }

                if (values[index] is INotifyPropertyChanged)
                {
                    ((INotifyPropertyChanged)values[index]).PropertyChanged -= Item_PropertyChanged;
                }

                values.RemoveAt(index);

                shape[0]--;
                count = MultiDimensionalArrayHelper.GetTotalLength(shape);

                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangedAction.Remove, valueToRemove, index, -1, singleValueLength);
                }
            }
            else
            {
                throw new NotSupportedException("Use Resize");
            }
        }
예제 #15
0
        /// <summary>
        /// Resizes array using new lengths of dimensions.
        /// </summary>
        /// <param name="newShape"></param>
        public virtual void Resize(params int[] newShape)
        {
            VerifyIsNotReadOnly();
            //speed using inserts and remove at the bounds of dimensions...

            /*if (newShape.Length == Rank)
             * {
             *  for (int i =0;i<Rank;i++)
             *  {
             *      var delta = newShape[i] - shape[i];
             *      if (delta > 0)
             *      {
             *          InsertAt(i, shape[i], delta);
             *      }
             *      else if (delta < 0)
             *      {
             *          RemoveAt(i,shape[i]+delta);
             *      }
             *  }
             * }
             */
            // special case when only the first dimension is altered
            if (MultiDimensionalArrayHelper.ShapesAreEqualExceptFirstDimension(shape, newShape))
            {
                // just in case, check if we really resizing
                if (shape[0] == newShape[0])
                {
                    return;
                }
                ResizeFirstDimension(newShape);
                return;
            }

            var oldShape  = shape;
            var oldStride = stride;

            // TODO: optimize copy, currently it is very slow and unscalable
            // create a new defaultValue filled arrayList
            var newTotalLength = MultiDimensionalArrayHelper.GetTotalLength(newShape);
            var newValues      = CreateValuesList();

            for (int i = 0; i < newTotalLength; i++)
            {
                newValues.Add(defaultValue);
            }
            //var newValues = Enumerable.Repeat(defaultValue, newTotalLength).ToList();
            var newStride = MultiDimensionalArrayHelper.GetStride(newShape);

            // copy old values to newValues if they are within a new shape, otherwise send Changing event for all *removed* values
            for (var i = 0; i < values.Count; i++)
            {
                var oldIndex = MultiDimensionalArrayHelper.GetIndex(i, stride);

                var isOldIndexWithinNewShape = MultiDimensionalArrayHelper.IsIndexWithinShape(oldIndex, newShape);
                if (!isOldIndexWithinNewShape)
                {
                    if (FireEvents)
                    {
                        var args = FireCollectionChanging(NotifyCollectionChangeAction.Remove, values[i], i);
                        if (args != null && args.Cancel)
                        {
                            return;
                        }
                    }

                    continue;
                }

                var newValueIndex = MultiDimensionalArrayHelper.GetIndex1d(oldIndex, newStride);
                newValues[newValueIndex] = values[i];
            }

            // set a new value and send Changing event for all *newly added* values
            for (var i = 0; i < newValues.Count; i++)
            {
                var newIndex = MultiDimensionalArrayHelper.GetIndex(i, newStride);
                var isNewIndexWithinOldShape = MultiDimensionalArrayHelper.IsIndexWithinShape(newIndex, shape);

                if (isNewIndexWithinOldShape)
                {
                    continue;
                }

                var newValue = defaultValue;
                if (FireEvents)
                {
                    var args = FireCollectionChanging(NotifyCollectionChangeAction.Add, newValue, i);
                    if (args != null)
                    {
                        if (args.Cancel)
                        {
                            return;
                        }
                        newValue = args.Items[0];
                    }
                }

                newValues[i] = newValue;
            }

            var oldValues = values;

            // replace old values by new values
            SetValues(newValues);

            Shape = newShape;

            if (FireEvents)
            {
                // send Changed even for all *removed* values
                for (var i = 0; i < oldValues.Count; i++)
                {
                    var oldIndex = MultiDimensionalArrayHelper.GetIndex(i, oldStride);
                    var isIndexWithinNewShape = MultiDimensionalArrayHelper.IsIndexWithinShape(oldIndex, newShape);
                    if (!isIndexWithinNewShape)
                    {
                        FireCollectionChanged(NotifyCollectionChangeAction.Remove, oldValues[i], i, -1);
                    }
                }

                // send Changing event for all *newly added* values
                for (var i = 0; i < newValues.Count; i++)
                {
                    var newIndex = MultiDimensionalArrayHelper.GetIndex(i, oldStride);
                    var isNewIndexWithinOldShape = MultiDimensionalArrayHelper.IsIndexWithinShape(newIndex, oldShape);

                    if (isNewIndexWithinOldShape)
                    {
                        continue;
                    }

                    FireCollectionChanged(NotifyCollectionChangeAction.Add, newValues[i], i, -1);
                }
            }
        }
예제 #16
0
        public virtual void InsertAt(int dimension, int index, int length)
        {
            if (rank == 1 && index == count && length == 1)
            {
                bool generateUniqueValueForDefaultValue = Owner.GenerateUniqueValueForDefaultValue;
                Owner.GenerateUniqueValueForDefaultValue = true;
                Add(defaultValue);
                Owner.GenerateUniqueValueForDefaultValue = generateUniqueValueForDefaultValue;
                return;
            }

            //resize the array. This can cause a change of stride
            //copy values etc. Refactor resize and copy data operation?
            //increment the correct dimensions
            var newShape = (int[])shape.Clone();

            newShape[dimension] += length;

            // THE REST IS VERY SLOW BECAUSE ALL VALUES ARE COPIED!

            // compute number of values to be added
            var valuesToAddShape = (int[])shape.Clone();

            valuesToAddShape[dimension] = length;
            var newValuesCount = MultiDimensionalArrayHelper.GetTotalLength(valuesToAddShape);

            var valuesToAdd = new ArrayList();

            for (var i = 0; i < newValuesCount; i++)
            {
                valuesToAdd.Add(defaultValue);
            }

            // send Changing events
            if (FireEvents && valuesToAdd.Count > 0)
            {
                var newStride       = MultiDimensionalArrayHelper.GetStride(newShape);
                var valueToAddIndex = new int[rank];
                valueToAddIndex[dimension] = index;

                var i = 0;
                do
                {
                    int newIndex1d = MultiDimensionalArrayHelper.GetIndex1d(valueToAddIndex, newStride);
                    var args       = FireCollectionChanging(NotifyCollectionChangedAction.Add, defaultValue, newIndex1d, singleValueLength);
                    if (args != null)
                    {
                        if (args.Cancel)
                        {
                            return;
                        }
                        valuesToAdd[i] = args.Item;
                    }
                    i++;
                } while (MultiDimensionalArrayHelper.IncrementIndex(valueToAddIndex, valuesToAddShape, rank - 1));
            }

            var eventsAreFired = fireEvents;

            fireEvents = false;

            Resize(newShape); // TODO: dangerous, Shape and Stride will already change here

            fireEvents = eventsAreFired;

            //walk down the values in the underlying array
            //copy the values to a new spot if the value is to be moved
            int addedValueIndex = 0;

            for (var i = count - 1; i >= 0; i--)
            {
                var newIndex = MultiDimensionalArrayHelper.GetIndex(i, stride);

                // getting index one more time is faster than Clone()
                var oldIndex = MultiDimensionalArrayHelper.GetIndex(i, stride);
                oldIndex[dimension] -= length;

                // value is to be moved
                if (newIndex[dimension] >= index + length)
                {
                    values[MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride)] = values[MultiDimensionalArrayHelper.GetIndex1d(oldIndex, stride)];
                }

                // new value added, send Changed event
                if ((newIndex[dimension] >= index) && (newIndex[dimension] < index + length))
                {
                    var index1d = MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride);
                    values[index1d] = valuesToAdd[addedValueIndex];

                    if (FireEvents)
                    {
                        FireCollectionChanged(NotifyCollectionChangedAction.Add, valuesToAdd[addedValueIndex], index1d, -1, singleValueLength);
                    }

                    addedValueIndex++;
                }
            }
        }
예제 #17
0
        private void AddValuesToFirstDimension(int[] newShape, int valuesToAddCount)
        {
            var valuesToAdd = new object[valuesToAddCount];

            // send Changing events
            var index1d = values.Count - 1;

            for (var i = 0; i < valuesToAddCount; i++)
            {
                var newValue = defaultValue;

                if (FireEvents)
                {
                    index1d++;
                    var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, newValue, index1d, singleValueLength);
                    if (args != null)
                    {
                        if (args.Cancel)
                        {
                            return;
                        }
                        newValue = args.Item;
                    }
                }

                valuesToAdd[i] = newValue;

                // specific case, for 1d we have to generate events one by one!
                if (rank == 1)
                {
                    values.Add(newValue);
                    shape[0]++;
                    count = MultiDimensionalArrayHelper.GetTotalLength(shape);
                    if (FireEvents)
                    {
                        FireCollectionChanged(NotifyCollectionChangedAction.Add, newValue, index1d, -1, singleValueLength);
                    }
                }
            }

            if (rank > 1)
            {
                // add new values
                foreach (var o in valuesToAdd)
                {
                    values.Add(o);
                }

                Shape = newShape;

                if (FireEvents)
                {
                    // send Changed events
                    index1d = values.Count - valuesToAddCount - 1;
                    for (var i = 0; i < valuesToAddCount; i++)
                    {
                        index1d++;
                        var valueToAdd = valuesToAdd[i];
                        FireCollectionChanged(NotifyCollectionChangedAction.Add, valueToAdd, index1d, -1, singleValueLength);
                    }
                }
            }
        }
예제 #18
0
        //TODO: change this signature of values object[] this will cause boxing and bad performance probably..
        //push the functionality down to the generic subclass.
        /// <summary>
        /// Insert a slices of value(s) for a given dimension
        /// </summary>
        /// <param name="dimension">Dimensen at which to insert</param>
        /// <param name="index">Index of insert for dimension</param>
        /// <param name="length">Length (in the dimensions). In 1D this is ValuesToInsert.Count but not in n-D</param>
        /// <param name="valuesToInsert">Total values</param>
        /// <returns></returns>
        public virtual int InsertAt(int dimension, int index, int length, IList valuesToInsert)
        {
            if (length == 0)
            {
                return(-1);
            }


            //resize the array. This can cause a change of stride
            //copy values etc. Refactor resize and copy data operation?
            //increment the correct dimensions
            var newShape = (int[])shape.Clone();

            newShape[dimension] += length;

            // THE REST IS VERY SLOW BECAUSE ALL VALUES ARE COPIED!

            // compute number of values to be added
            var valuesToInsertShape = (int[])shape.Clone();

            valuesToInsertShape[dimension] = length;


            MultiDimensionalArrayHelper.VerifyValuesCountMatchesShape(valuesToInsertShape, valuesToInsert);

            var newStride       = MultiDimensionalArrayHelper.GetStride(newShape);
            var valueToAddIndex = new int[rank];

            valueToAddIndex[dimension] = index;
            int insertionStartIndex = MultiDimensionalArrayHelper.GetIndex1d(valueToAddIndex, newStride);

            // send Changing events
            if (FireEvents)
            {
                var args = FireCollectionChanging(NotifyCollectionChangeAction.Add, valuesToInsert, insertionStartIndex,
                                                  valuesToInsertShape);

                //TODO: handle changes from changing event..allows for sorting (a little bit)
                if (args != null)
                {
                    if (args.Cancel)
                    {
                        return(-1);
                    }
                    if (args.Index != insertionStartIndex && IsAutoSorted)
                    {
                        throw new InvalidOperationException("Sorted array does not allow update of Indexes in CollectionChanging");
                    }
                }
            }
            if (IsAutoSorted)
            {
                //values values to insert have values smaller than MaxValue throw
                var comparables = valuesToInsert.Cast <IComparable>();
                var monotonous  = comparables.IsMonotonousAscending();
                // first is the smallest value since comparables is monotonous ascending :)
                var allBiggerThanMaxValue = ((MaxValue == null) || ((MaxValue as IComparable).IsSmaller(comparables.First())));
                if (comparables.Count() > 1 &&
                    (!allBiggerThanMaxValue ||
                     !monotonous))
                {
                    throw new InvalidOperationException(
                              "Adding range of values for sorted array is only possible if these values are all bigger than the current max and sorted");
                }

                //get the 'real' insertion indexes..first for 1 value
                //omg this must be slow...get this faster by
                //A : using the knowledge that the array was sorted (binarysort)
                //B : using the type of T by moving this into a virtual method and push it down to a subclass

                insertionStartIndex = GetInsertionStartIndex(valuesToInsert);


                index = insertionStartIndex;//review and fix all these indexes..it is getting unclear..work in MDA style..
            }

            //performance increase when adding to the first dimension...no stuff will be moved so not need to go throught the whole array later on
            bool insertIsAtBoundsOfFirstDimension = dimension == 0 && index == shape[0];

            var eventsAreFired = fireEvents;

            fireEvents = false;

            Resize(newShape); // TODO: dangerous, Shape and Stride will already change here


            fireEvents = eventsAreFired;
            dirty      = true;//make sure min/max are set dirty


            //simple insert...at bounds of first index
            if (insertIsAtBoundsOfFirstDimension)
            {
                var addedValueIndex = 0;
                do
                {
                    int newIndex1d = MultiDimensionalArrayHelper.GetIndex1d(valueToAddIndex, newStride);
                    var newValue   = valuesToInsert[addedValueIndex];

                    SetValue1D(newValue, newIndex1d);

                    addedValueIndex++;
                } while (MultiDimensionalArrayHelper.IncrementIndex(valueToAddIndex, newShape, rank - 1));

                //fill it up until the whole new shape is filled..because we are are at the bounds of the first dimension
                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangeAction.Add, valuesToInsert, insertionStartIndex, -1, valuesToInsertShape);
                }
            }
            else  //complex...insert could be everywhere and might have to move stuff in the underlying array..
            {
                //walk down the values in the underlying array
                //copy the values to a new spot if the value is to be moved
                int addedValueIndex = valuesToInsert.Count - 1;

                var newIndex = MultiDimensionalArrayHelper.GetIndex(count - 1, stride); //start at end

                for (var i = count - 1; i >= 0; i--)
                {
                    // value is to be moved
                    if (newIndex[dimension] >= index + length)
                    {
                        var oldIndex = (int[])newIndex.Clone();
                        oldIndex[dimension] -= length;

                        values[MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride)] =
                            values[MultiDimensionalArrayHelper.GetIndex1d(oldIndex, stride)];
                        //set the 'old' copy to 'null' to prevent unsubscribtion when we replace it by the new value
                        values[MultiDimensionalArrayHelper.GetIndex1d(oldIndex, stride)] = defaultValue;
                    }

                    // new value added
                    if ((newIndex[dimension] >= index) && (newIndex[dimension] < index + length))
                    {
                        var index1d  = MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride);
                        var newValue = valuesToInsert[addedValueIndex];

                        SetValue1D(newValue, index1d);

                        addedValueIndex--;//walk down because we start at the end
                    }

                    if (i > 0) //decrementing last time won't work
                    {
                        MultiDimensionalArrayHelper.DecrementIndexForShape(newIndex, newShape);
                    }
                }
                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangeAction.Add, valuesToInsert, insertionStartIndex, -1, valuesToInsertShape);
                }
            }
            return(index);//this might be wrong..the index might have changed
        }
예제 #19
0
 protected virtual int GetInsertionStartIndex(IList valuesToInsert)
 {
     return(MultiDimensionalArrayHelper.GetInsertionIndex((IComparable)valuesToInsert[0], values.Cast <IComparable>().ToList()));
 }
예제 #20
0
 public override string ToString()
 {
     return(MultiDimensionalArrayHelper.ToString(this));
 }
예제 #21
0
        public virtual object this[params int[] index]
        {
            get
            {
                if (index.Length != rank)
                {
                    if (index.Length == 1) // use 1D
                    {
                        return(values[index[0]]);
                    }

                    throw new ArgumentException("Invalid number of indexes");
                }

                if (index.Length == 1) // performance improvement
                {
                    return(values[index[0]]);
                }

                return(values[MultiDimensionalArrayHelper.GetIndex1d(index, stride)]);
            }
            set
            {
                VerifyIsNotReadOnly();
                //exception single dimensional access to More dimensional array used 1d array
                if (index.Length != rank)
                {
                    /*
                     *                  if (index.Length == 1) // use 1D
                     *                  {
                     *                      ((IList)this)[index[0]] = value;
                     *                      dirty = true;
                     *
                     *                      //todo: collectionchanged etc
                     *                      return;
                     *                  }
                     */

                    throw new ArgumentException("Invalid number of indexes");
                }

                var index1d  = MultiDimensionalArrayHelper.GetIndex1d(index, stride);
                var newValue = value;
                var newIndex = index1d;

                if (values[index1d] == value)
                {
                    return; // do nothing, value is the same as old value
                }

                // log.DebugFormat("Value before Replace: {0}", this);

                if (FireEvents)
                {
                    var args = FireCollectionChanging(NotifyCollectionChangeAction.Replace, value, index1d);
                    if (args != null)
                    {
                        if (args.Cancel)
                        {
                            return;
                        }
                        newValue = args.Items[0];
                        newIndex = args.Index;
                    }
                }


                if (IsAutoSorted)
                {
                    if (newIndex != index1d)
                    {
                        throw new InvalidOperationException("Updating indexes in collectionChanging is not supported for AutoSortedArrays");
                    }

                    //value or newValue (possible changed by changingEvent...)
                    var oldIndex = index1d;
                    newIndex = MultiDimensionalArrayHelper.GetInsertionIndex((IComparable)value, values.Cast <IComparable>().ToList());
                    if (newIndex > oldIndex)
                    {
                        newIndex--; //if value is currently left of the new index so our insert should be on index one less..
                    }
                }

                //actual set values...
                SetValue1D(newValue, index1d);

                //move values to correct location if necessary
                if (newIndex != index1d)
                {
                    Move(0, index1d, 1, newIndex, false);
                }


                dirty = true;

                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangeAction.Replace, value, newIndex, index1d);
                }

                // log.DebugFormat("Value after Replace: {0}", this);
            }
        }
        /// <summary>
        /// Prepares the Multidimensional array of function. Expands dimensions where needed.
        /// TODO: this and above methods seem to be redundant
        ///
        /// TODO: shouldn't it happen in Function?
        /// </summary>
        /// <param name="function"></param>
        /// <param name="filters"></param>
        /// <returns></returns>
        private IMultiDimensionalArray CreateComponentArrayFromFilters(IFunction function,
                                                                       IList <IVariableFilter> filters)
        {
            if (filters.Count == 0)
            {
                return(FunctionValues[Functions.IndexOf(function)]);
            }

            var variable = (IVariable)function;

            // HACK: will create generic view. based on maxInt
            IMultiDimensionalArrayView view = FunctionValues[Functions.IndexOf(variable)].Select(0, int.MinValue,
                                                                                                 int.MaxValue);

            // check if we have aggregation filters, if yes - return a new array, otherwise return a view based on existing array
            // probably it should be always a view based on existing array, even when aggregation is used
            if (filters.Any(f => f is VariableAggregationFilter))
            {
                var filterVariableIndex = new Dictionary <VariableAggregationFilter, int>();
                foreach (VariableAggregationFilter filter in filters.OfType <VariableAggregationFilter>())
                {
                    filterVariableIndex[filter] = variable.Arguments.IndexOf(filter.Variable);
                }

                // calculate shape of the resulting array
                var shape = (int[])view.Shape.Clone();
                foreach (VariableAggregationFilter filter in filters.OfType <VariableAggregationFilter>())
                {
                    shape[filterVariableIndex[filter]] = filter.Count;
                }

                // now fill in values into the resulting array
                IMultiDimensionalArray result = variable.CreateStorageArray();
                result.Resize(shape);

                int totalLength = MultiDimensionalArrayHelper.GetTotalLength(shape);
                for (int i = 0; i < totalLength; i++)
                {
                    int[] targetIndex = MultiDimensionalArrayHelper.GetIndex(i, result.Stride);

                    // calculate index in the source array
                    var sourceIndex = (int[])targetIndex.Clone();
                    foreach (VariableAggregationFilter filter in filters.OfType <VariableAggregationFilter>())
                    {
                        int filterArgumentIndex = filterVariableIndex[filter];
                        sourceIndex[filterArgumentIndex] = GetSourceIndex(filter, targetIndex[filterArgumentIndex]);
                    }

                    result[targetIndex] = view[sourceIndex]; // copy value (only required)
                }

                view = result.Select(0, int.MinValue, int.MaxValue);
            }

            //use variable filters that are relevant to make a selection
            IEnumerable <IVariableFilter> relevantArgumentFilters =
                filters.OfType <IVariableFilter>().Where(
                    f =>
                    (f is IVariableValueFilter || f is VariableIndexRangesFilter || f is VariableIndexRangeFilter) &&
                    (f.Variable == function || function.Arguments.Contains(f.Variable)));

            foreach (IVariableFilter variableFilter in relevantArgumentFilters)
            {
                //determine indexes for this variable..get in a base class?
                int[] indexes = GetArgumentIndexes(variableFilter);

                if (function.IsIndependent && variableFilter.Variable == function)
                {
                    view.SelectedIndexes[0] = indexes; // indepedent variable always dim 0
                }
                else if (function.Arguments.Contains(variableFilter.Variable))
                {
                    int dimensionIndex = function.Arguments.IndexOf(variableFilter.Variable);
                    view.SelectedIndexes[dimensionIndex] = indexes;
                }
            }

            //reduce the view for reduce filters.
            foreach (VariableReduceFilter filter in filters.OfType <VariableReduceFilter>())
            {
                int index = function.Arguments.IndexOf(filter.Variable);
                if (index != -1)
                {
                    view.Reduce[index] = true;
                }
            }

            return(view);
        }
예제 #23
0
        public virtual object this[params int[] index]
        {
            get
            {
                if (index.Length != rank)
                {
                    if (index.Length == 1) // use 1D
                    {
                        return(values[index[0]]);
                    }

                    throw new ArgumentException("Invalid number of indexes");
                }

                if (index.Length == 1) // performance improvement
                {
                    return(values[index[0]]);
                }

                return(values[MultiDimensionalArrayHelper.GetIndex1d(index, stride)]);
            }
            set
            {
                //exception single dimensional access to More dimensional array used 1d array
                if (index.Length != rank)
                {
                    /*
                     *                  if (index.Length == 1) // use 1D
                     *                  {
                     *                      ((IList)this)[index[0]] = value;
                     *                      dirty = true;
                     *
                     *                      //todo: collectionchanged etc
                     *                      return;
                     *                  }
                     */

                    throw new ArgumentException("Invalid number of indexes");
                }

                var index1d  = MultiDimensionalArrayHelper.GetIndex1d(index, stride);
                var newValue = value;
                var newIndex = index1d;
                var oldValue = values[index1d];

                if (values[index1d] == value)
                {
                    return; // do nothing, value is the same as old value
                }

                // log.DebugFormat("Value before Replace: {0}", this);

                if (FireEvents)
                {
                    var args = FireCollectionChanging(NotifyCollectionChangedAction.Replace, value, index1d, singleValueLength);
                    if (args != null)
                    {
                        if (args.Cancel)
                        {
                            return;
                        }
                        newValue = args.Item;
                        newIndex = args.Index;
                    }
                }

                values[index1d] = newValue;

                if (newIndex != index1d)
                {
                    if (Rank > 1)
                    {
                        throw new NotSupportedException("Replacing index in CollectionChanging event works only for 1D arrays for now.");
                    }

                    if (newIndex != index1d)
                    {
                        Move(0, index1d, 1, newIndex);
                    }
                }

                dirty = true;

                if (FireEvents)
                {
                    FireCollectionChanged(NotifyCollectionChangedAction.Replace, oldValue, index1d, newIndex, singleValueLength);
                }

                // log.DebugFormat("Value after Replace: {0}", this);
            }
        }