Esempio n. 1
0
        public IVariable Subtract(IVariable x, GekkoTime t)
        {
            switch (x.Type())
            {
            case EVariableType.Val:
            {
                return(Operators.DateVal.Subtract(this, (ScalarVal)x));
            }
            break;

            case EVariableType.Date:
            {
                int obs = GekkoTime.Observations(((ScalarDate)x).date, this.date) - 1;
                if (obs < 0)
                {
                    G.Writeln();
                    G.Writeln("*** ERROR: Subtraction of two dates gave negative number of observations: " + obs);
                    throw new GekkoException();
                }
                return(new ScalarVal(obs));
            }
            break;

            default:
            {
                G.Writeln2("*** ERROR: Type error regarding subtract");
                throw new GekkoException();
            }
            break;
            }
        }
Esempio n. 2
0
        public IVariable Indexer(IVariablesFilterRange indexRange, GekkoTime t)
        {
            IVariable iv1 = indexRange.first;
            IVariable iv2 = indexRange.last;

            if (iv1.Type() == EVariableType.String && iv2.Type() == EVariableType.String)
            {
                string        s1   = O.GetString(iv1);
                string        s2   = O.GetString(iv2);
                List <string> temp = Program.MatchRange(s1, s2, this.list, null);
                return(new MetaList(temp));
            }
            else
            {
                int i1 = O.GetInt(iv1);
                int i2 = O.GetInt(iv2);
                if (i1 < 1)
                {
                    G.Writeln2("*** ERROR: Starting index (" + i1 + ") cannot be < 1");
                    throw new GekkoException();
                }
                if (i1 > this.list.Count)
                {
                    G.Writeln2("*** ERROR: Ending index (" + i2 + ") cannot be > length (" + this.list.Count + ")");
                    throw new GekkoException();
                }
                if (i1 > i2)
                {
                    G.Writeln2("*** ERROR: Starting index (" + i1 + ") cannot be > than ending index (" + i2 + ")");
                    throw new GekkoException();
                }
                return(new MetaList(this.list.GetRange(i1 - 1, i2 - i1 + 1))); //GetRange() is a shallow copy, but that is okay since it contains immutable strings
            }
        }
Esempio n. 3
0
        public IVariable Multiply(IVariable x, GekkoTime t)
        {
            switch (x.Type())
            {
            case EVariableType.Val:
            {
                return(new ScalarVal(this.val * ((ScalarVal)x).val));
            }

            case EVariableType.TimeSeries:
            {
                return(new ScalarVal(this.val * O.GetVal(x, t)));
            }

            case EVariableType.Matrix:
            {
                //This is allowed in AREMOS, too
                double[,] a = O.GetMatrix(x).data;
                double b = O.GetVal(this, t);
                int    m = a.GetLength(0);
                int    k = a.GetLength(1);
                double[,] c = O.MultiplyMatrixScalar(a, b, m, k);
                Matrix z = new Matrix();
                z.data = c;
                return(z);
            }

            default:
            {
                G.Writeln2("*** ERROR: Memory variable conversion error.");
                throw new GekkoException();
            }
            }
        }
Esempio n. 4
0
 public IVariable Indexer(GekkoTime t, bool isLhs, params IVariable[] indexes)
 {
     if (indexes.Length == 1)
     {
         IVariable index1 = indexes[0];
         int       i1     = O.GetInt(index1);
         int       d1     = this.data.GetLength(0);
         int       d2     = this.data.GetLength(1);
         if (d2 == 1)
         {
             //1 col: column vector
             IVariable   one      = new ScalarVal(1d);
             IVariable[] newIndex = new IVariable[2];
             newIndex[0] = index1;
             newIndex[1] = one;
             return(Handle2dIndexer(newIndex));  //we implicitly understand #a[3] as #a[3,1] here. But we cannot do the inverse on a row vector.
         }
         G.Writeln("*** ERROR: You are trying to use [" + i1 + "] on a " + d1 + "x" + d2 + " matrix");
         G.Writeln("           This notation can only be used regarding nx1 matrices (column vectors)");
         throw new GekkoException();
     }
     else if (indexes.Length == 2)
     {
         return(Handle2dIndexer(indexes));
     }
     else
     {
         G.Writeln2("*** ERROR: Cannot use " + indexes.Length + "-dimensional indexer on MATRIX");
         throw new GekkoException();
     }
 }
Esempio n. 5
0
        public IVariable Subtract(IVariable x, GekkoTime t)
        {
            //clone this Add() method and do with O.SubtractMatrixScalar, also for Matrix and matrix
            EVariableType type = x.Type();

            if (type == EVariableType.Matrix)
            {
                double[,] a = this.data;
                double[,] b = ((Matrix)x).data;
                int m = a.GetLength(0);
                int k = a.GetLength(1);
                if (b.GetLength(0) != m || b.GetLength(1) != k)
                {
                    G.Writeln2("*** ERROR: The two matrices are not compatible for subtraction");
                    G.Writeln2("           " + m + "x" + k + " and " + b.GetLength(0) + "x" + b.GetLength(1) + " do not match");
                    throw new GekkoException();
                }
                double[,] c = O.SubtractMatrixMatrix(a, b, m, k);
                Matrix z = new Matrix();
                z.data = c;
                return(z);
            }
            else
            {
                //subtraction of a scalar is not legal, this is like AREMOS
                G.Writeln2("*** ERROR: You are trying to add a MATRIX and a " + type.ToString().ToUpper());
                throw new GekkoException();
            }
        }
Esempio n. 6
0
 private int GetArrayIndex(GekkoTime gt)
 {
     //this.anchorSubPeriod is always 1 at the moment, and will always be 1 for Annual.
     //but we cannot count on anchorSubPeriod being 1 forever (for instance for daily obs)
     if (this.freqEnum == EFreq.Annual)
     {
         //Special treatment in order to make it fast.
         //undated freq could return fast in the same way as this??
         return(this.anchorPeriodPositionInArray + gt.super - this.anchorSuperPeriod);
     }
     else
     {
         //Non-annual
         int subPeriods = 1;
         if (this.freqEnum == EFreq.Quarterly)
         {
             subPeriods = 4;
         }
         else if (this.freqEnum == EFreq.Monthly)
         {
             subPeriods = 12;
         }
         else if (this.freqEnum == EFreq.Undated)
         {
             subPeriods = 1;
         }
         //For quarterly data for instance, each super period amounts to 4 observations. Therefore the multiplication.
         int offset = subPeriods * (gt.super - this.anchorSuperPeriod) + (gt.sub - this.anchorSubPeriod);
         int index  = this.anchorPeriodPositionInArray + offset;
         return(index);
     }
 }
Esempio n. 7
0
        public static void CodeLines(P p)
        {
            GekkoTime t = Globals.tNull;

            C0(p);

            C1(p);
        }
Esempio n. 8
0
            public static IVariable Add(ScalarDate t, ScalarVal d)
            {
                int        i  = O.GetInt(d);
                GekkoTime  t2 = t.date.Add(i);
                ScalarDate z  = new ScalarDate(t2);

                return(z);
            }
Esempio n. 9
0
 private void CheckSameFreq(GekkoTime gt2)
 {
     if (this.freq != gt2.freq)
     {
         G.Writeln2("*** ERROR: Comparing two different frequencies");
         throw new GekkoException();
     }
 }
Esempio n. 10
0
 public IVariable Indexer(GekkoTime t, bool isLhs, params IVariable[] indexes)
 {
     if (indexes.Length > 0 && indexes[0].Type() == EVariableType.String)
     {
         string hash = TimeSeries.GetHashCodeFromIvariables(indexes);
         O.ECreatePossibilities canCreate = O.ECreatePossibilities.None;
         if (isLhs)
         {
             canCreate = O.ECreatePossibilities.Can;
         }
         string     varHash = this.ts.variableName + Globals.symbolTurtle + hash;
         TimeSeries ts      = this.ts.parentDatabank.GetVariable(this.ts.freqEnum, varHash);
         if (ts == null)
         {
             if (canCreate == O.ECreatePossibilities.None)
             {
                 G.Writeln2("*** ERROR: Cannot find " + this.ts.parentDatabank.aliasName + ":" + this.ts.variableName + "[" + G.PrettifyTimeseriesHash(hash, false, false) + "]");
                 throw new GekkoException();
             }
             ts = new TimeSeries(this.ts.freqEnum, varHash);
             this.ts.parentDatabank.AddVariable(ts);
         }
         return(new MetaTimeSeries(ts));
     }
     else
     {
         //y[2010] or y[-1]
         IVariable index = indexes[0];
         if (index.Type() == EVariableType.Val)
         {
             int ival = O.GetInt(index);
             if (ival >= 1900)
             {
                 return(new ScalarVal(this.ts.GetData(new GekkoTime(EFreq.Annual, ival + this.offset, 1))));
             }
             else
             {
                 //typically ival numerically < 10 here
                 //return new MetaTimeSeries(this.ts, ival, this.bank, this.variable);
                 return(new MetaTimeSeries(this.ts, ival + this.offset));
                 //10% faster, but maybe more error prone...
                 //this.offset = ival;
                 //return this;
             }
         }
         else if (index.Type() == EVariableType.Date)
         {
             return(new ScalarVal(this.ts.GetData(((ScalarDate)index).date.Add(this.offset))));
         }
         else
         {
             //should not be possible
             G.Writeln2("*** ERROR: SERIES uses []-indexer with wrong variable type");
             throw new GekkoException();
         }
     }
 }
Esempio n. 11
0
            public static IVariable Subtract(ScalarDate t, ScalarVal d)
            {
                //HMMM, what about rounding up and down here??
                int        i  = O.GetInt(d);
                GekkoTime  t2 = t.date.Add(-i);
                ScalarDate z  = new ScalarDate(t2);

                return(z);
            }
Esempio n. 12
0
 /// <summary>
 /// Overload with setStartEndPeriods = false.
 /// </summary>
 /// <param name="index1">The array index corresponding to the start of the period</param>
 /// <param name="index2">The array index corresponding to the end of the period</param>
 /// <param name="per1">The start of the period.</param>
 /// <param name="per2">The end of the period.</param>
 /// <returns></returns>
 public double[] GetDataSequence(out int index1, out int index2, GekkoTime per1, GekkoTime per2)
 {
     if (this.isTimeless)
     {
         G.Writeln2("*** ERROR: Timeless variable error #2");
         throw new GekkoException();
     }
     return(GetDataSequence(out index1, out index2, per1, per2, false));
 }
Esempio n. 13
0
        public TimeSeriesLight(TimeSeries ts, GekkoTime gt1, GekkoTime gt2)
        {
            int i1 = -12345;
            int i2 = -12345;

            double[] dataPointer = ts.GetDataSequence(out i1, out i2, gt1, gt2);
            storage = new double[i2 - i1 + 1];
            Array.Copy(dataPointer, i1, storage, 0, (i2 - i1 + 1));
        }
Esempio n. 14
0
 public double GetVal(GekkoTime t)
 {
     //Asking a general timeless GetVal() from a timeseries (and not getting a val with a particular GekkoTime) is used in GENR, PRT etc. in an internal GekkoTime loop. Hence the use of Globals.globalGekkoTimeIterator_DO_NOT_ALTER.
     if (t.IsNull())
     {
         G.Writeln2("*** ERROR: You are trying to extract a single value from timeseries: " + this.ts.variableName + ".");
         G.Writeln("           Did you forget []-brackets to pick out an observation, for instance x[2020]?");
         throw new GekkoException();
     }
     return(this.ts.GetData(t.Add(this.offset)));
 }
Esempio n. 15
0
 public bool IsSamePeriod(GekkoTime gt2)
 {
     CheckSameFreq(gt2);
     if (this.super == gt2.super)
     {
         if (this.sub == gt2.sub)
         {
             return(true);
         }
     }
     return(false);
 }
Esempio n. 16
0
        public GekkoTime GetDate(O.GetDateChoices c)
        {
            GekkoTime gt       = Globals.tNull;
            int       intValue = O.GetInt(this);       //will issue error if the VAL is not an integer
            int       year     = G.findYear(intValue); //error is the year is crazy

            if (c == O.GetDateChoices.Strict || (c != O.GetDateChoices.Strict && (Program.options.freq == EFreq.Annual || Program.options.freq == EFreq.Undated)))
            {
                if (Program.options.freq == EFreq.Undated)
                {
                    gt = new GekkoTime(EFreq.Undated, year, 1); //here, the context matters!
                }
                else
                {
                    gt = new GekkoTime(EFreq.Annual, year, 1);  //for a, q, m
                    //so date d = 2000 in freq=m will not turn this into 2000m1 or 2000m12
                }
            }
            else
            {
                //that is, FlexibleStart or FlexibleEnd
                //For Annual and Undated, this has been handled above
                //typically for TIME 2000 2010 or SERIES<2000 2010> which are turned into
                //for instance 2000m1 to 2000m12.
                if (Program.options.freq == EFreq.Quarterly)
                {
                    int sub = 1;
                    if (c == O.GetDateChoices.FlexibleStart)
                    {
                        sub = 1;
                    }
                    else if (c == O.GetDateChoices.FlexibleEnd)
                    {
                        sub = 4;
                    }
                    gt = new GekkoTime(EFreq.Quarterly, year, sub);
                }
                else if (Program.options.freq == EFreq.Monthly)
                {
                    int sub = 1;
                    if (c == O.GetDateChoices.FlexibleStart)
                    {
                        sub = 1;
                    }
                    else if (c == O.GetDateChoices.FlexibleEnd)
                    {
                        sub = 12;
                    }
                    gt = new GekkoTime(EFreq.Monthly, year, sub);
                }
            }
            return(gt);
        }
Esempio n. 17
0
        public IVariable Indexer(GekkoTime t, bool isLhs, params IVariable[] indexes)
        {
            if (indexes.Length == 1)
            {
                IVariable index = indexes[0];
                //Indices run from 1, 2, 3, ... n. Element 0 is length of list.
                if (index.Type() == EVariableType.Val)
                {
                    int ival = O.GetInt(index);
                    if (ival < 0)
                    {
                        G.Writeln2("*** ERROR: Illegal element access [" + ival + "]: negative number not allowed");
                        throw new GekkoException();
                    }
                    else if (ival == 0)
                    {
                        ScalarVal a = new ScalarVal(this.list.Count);
                        return(a);
                    }
                    else if (ival > this.list.Count)
                    {
                        G.Writeln2("*** ERROR: Illegal element access [" + ival + "]: larger than length of list (" + this.list.Count + ")");
                        throw new GekkoException();
                    }
                    string s = this.list[ival - 1];

                    IVariable ss = null;
                    ss = new ScalarString(s, isNameList);
                    if (Globals.fixIndexerMaybeTransform)
                    {
                        bool didTransform = false;
                        ss = O.MaybeTransform(ref didTransform, ss, true);
                    }
                    return(ss);
                }
                else if (index.Type() == EVariableType.String)
                {
                    string        s5    = ((ScalarString)index)._string2;
                    List <string> found = Program.MatchWildcard(s5, this.list, null);
                    return(new MetaList(found));
                }
                else
                {
                    G.Writeln2("*** ERROR: Type mismatch regarding []-index");
                    throw new GekkoException();
                }
            }
            else
            {
                G.Writeln2("*** ERROR: Cannot use " + indexes.Length + "-dimensional indexer on LIST");
                throw new GekkoException();
            }
        }
Esempio n. 18
0
        public IVariable Indexer(IVariablesFilterRange indexRange, GekkoTime t)
        {
            int d1 = this.data.GetLength(0);
            int d2 = this.data.GetLength(1);

            if (d2 == 1)
            {
                return(Indexer(indexRange, new ScalarVal(1d), t));
            }
            G.Writeln("*** ERROR: You are trying to use [ .. ] on a " + d1 + "x" + d2 + " matrix");
            G.Writeln("           This notation can only be used regarding nx1 matrices (column vectors)");
            throw new GekkoException();
        }
Esempio n. 19
0
            public static IVariable Add(ScalarVal x, MetaTimeSeries ats, GekkoTime t)
            {
                //no need to implement swap
                if (t.IsNull())
                {
                    throw new GekkoException();
                }
                TimeSeries ts   = ats.ts;
                double     val1 = x.val;
                double     val2 = ts.GetData(t.Add(ats.offset));

                return(new ScalarVal(val1 + val2));
            }
Esempio n. 20
0
 public bool SmallerThanOrEqual(GekkoTime gt2)
 {
     CheckSameFreq(gt2);
     if (this.super == gt2.super && this.sub == gt2.sub)
     {
         return(true);
     }
     if (StrictlySmallerThan(gt2))
     {
         return(true);
     }
     return(false);
 }
Esempio n. 21
0
 public double GetVal(GekkoTime t)
 {
     if (this.data.GetLength(0) == 1 && this.data.GetLength(1) == 1)
     {
         return(this.data[0, 0]);
     }
     else
     {
         G.Writeln2("*** ERROR: Type mismatch: you are trying to extract a VAL from a matrix.");
         G.Writeln("           Maybe you need an [x, y]-indexer on the matrix, for instance #a[2, 3]?");
     }
     throw new GekkoException();
 }
Esempio n. 22
0
        /// <summary>
        /// Truncates the TimeSeries object, so that the starting period
        /// and ending period are as given. Beware: this will usually mean that data is deleted. Used to truncate
        /// a databank to a particular time period. Note: You may wish to use Trim() after a Truncate(). Note: only works for annual timeseries.
        /// </summary>
        /// <param name="start">The start period.</param>
        /// <param name="end">The end period.</param>
        /// <exception cref="GekkoException">
        /// </exception>
        public void Truncate(GekkoTime start, GekkoTime end)
        {
            //DimensionCheck();
            if (this.parentDatabank != null && this.parentDatabank.protect)
            {
                Program.ProtectError("You cannot truncate a timeseries residing in a non-editable databank, see OPEN<edit> or UNLOCK");
            }
            int indexStart = this.GetArrayIndex(start);
            int indexEnd   = this.GetArrayIndex(end);

            int newFirst = Math.Max(this.firstPeriodPositionInArray, indexStart);
            int newLast  = Math.Min(this.lastPeriodPositionInArray, indexEnd);

            if (newFirst > newLast)
            {
                //the truncate window is completely before or after the data window
                //wipe all the data, and set the sample to 1 length
                for (int i = 0; i < this.dataArray.Length; i++)
                {
                    this.dataArray[i] = double.NaN;
                }

                SetNullPeriod();
            }
            else
            {
                //the following two must be inside existing timeseries array
                this.firstPeriodPositionInArray = newFirst;
                this.lastPeriodPositionInArray  = newLast;

                //NOTE: after this, the anchor position may be outside first/lastPeriodPositionInArray.
                //But this should not be a problem: it is only a hook
                //that translates a date into an index and vice versa.

                //When Truncate() is used for writing databanks, the timeseries
                //will be Trim()'ed anyway, so these missings will disappear. But since the method
                //could be used for other purposes later on, we set the values to missings explicitly
                //The time loss is very small, and usually WRITE is not time-truncated anyway.

                for (int i = 0; i < this.firstPeriodPositionInArray; i++)
                {
                    this.dataArray[i] = double.NaN;
                }
                for (int i = this.lastPeriodPositionInArray + 1; i < this.dataArray.Length; i++)
                {
                    this.dataArray[i] = double.NaN;
                }
            }
            this.SetDirty(true);
        }
Esempio n. 23
0
        public IVariable Negate(GekkoTime t)
        {
            int    ni = this.data.GetLength(0);
            int    nj = this.data.GetLength(1);
            Matrix m  = new Matrix(ni, nj);

            for (int i = 0; i < ni; i++)
            {
                for (int j = 0; j < nj; j++)
                {
                    m.data[i, j] = -this.data[i, j];
                }
            }
            return(m);
        }
Esempio n. 24
0
            public static IVariable Add(ScalarString s, ScalarDate d, bool invert)
            {
                GekkoTime gt = O.GetDate(d);
                string    z  = null;

                if (invert)
                {
                    z = G.FromDateToString(gt) + s._string2;
                }
                else
                {
                    z = s._string2 + G.FromDateToString(gt);
                }
                return(new ScalarString(z));
            }
Esempio n. 25
0
        public IVariable Divide(IVariable x, GekkoTime t)
        {
            switch (x.Type())
            {
            case EVariableType.Matrix:
            {
                double[,] a = this.data;
                double[,] b = ((Matrix)x).data;
                // m x k  *  p x n
                int m = a.GetLength(0);
                int k = a.GetLength(1);
                int p = b.GetLength(0);
                int n = b.GetLength(1);

                if (p == 1 && n == 1)
                {
                    //Special case
                    double[,] c = O.MultiplyMatrixScalar(a, 1d / b[0, 0], m, k);
                    Matrix z = new Matrix();
                    z.data = c;
                    return(z);
                }
                else
                {
                    G.Writeln2("*** ERROR: You can only divide a matrix with a scalar or 1x1 matrix.");
                    throw new GekkoException();
                }
            }

            case EVariableType.Val:
            {
                double[,] a = this.data;
                double b = O.GetVal(x, t);
                int    m = a.GetLength(0);
                int    k = a.GetLength(1);
                double[,] c = O.MultiplyMatrixScalar(a, 1d / b, m, k);
                Matrix z = new Matrix();
                z.data = c;
                return(z);
            }

            default:
            {
                G.Writeln2("*** ERROR: You can only divide a matrix with a scalar or 1x1 matrix.");
                throw new GekkoException();
            }
            }
        }
Esempio n. 26
0
        /// <summary>
        /// This sets the observation (period) to the given value.
        /// </summary>
        /// <param name="t">The period.</param>
        /// <param name="value">The value.</param>
        /// <exception cref="GekkoException">Exception if frequency of timeseries and period do not match.</exception>
        public void SetData(GekkoTime t, double value)
        {
            if (this.isTimeless)
            {
                //Should not normally be used.
                //But this may be called from for instance DECOMP, calling it with a time period
                //Normally timeless variables should be called via the SetData(double value) method
                this.dataArray[0] = value;
            }
            if (this.parentDatabank != null && this.parentDatabank.protect)
            {
                Program.ProtectError("You cannot change an observation in a timeseries residing in a non-editable databank, see OPEN<edit> or UNLOCK");
            }

            if (this.freqEnum != t.freq)
            {
                //See comment to GetData()
                G.Writeln2("*** ERROR: Freq mismatch");
                throw new GekkoException();
            }
            if (this.dataArray == null)
            {
                InitDataArray(t);
            }

            if (this.isTimeless)
            {
                this.dataArray[0] = value;
            }
            else
            {
                //Get the array index corresponding to the period. If this index is out of array bounds, the array will
                //be resized (1.5 times larger).
                int index = ResizeDataArray(t, true);
                this.dataArray[index] = value;
                //Start and end date for observations are adjusted.
                //for the first obs put into a new timeseries, both the if's should trigger.
                if (index > this.lastPeriodPositionInArray)
                {
                    this.lastPeriodPositionInArray = index;
                }
                if (index < this.firstPeriodPositionInArray)
                {
                    this.firstPeriodPositionInArray = index;
                }
                this.SetDirtyGhost(true, false);
            }
        }
Esempio n. 27
0
 public bool StrictlySmallerThan(GekkoTime gt2)
 {
     CheckSameFreq(gt2);
     if (this.super < gt2.super)
     {
         return(true);
     }
     else if (this.super == gt2.super)
     {
         if (this.sub < gt2.sub)
         {
             return(true);
         }
     }
     return(false);
 }
Esempio n. 28
0
 public IVariable Power(IVariable x, GekkoTime t)
 {
     if (x.Type() == EVariableType.TimeSeries)
     {
         return(new ScalarVal(Math.Pow(O.GetVal(this, t), O.GetVal(x, t))));
     }
     else if (x.Type() == EVariableType.Val)
     {
         return(new ScalarVal(Math.Pow(O.GetVal(this, t), O.GetVal(x, t))));
     }
     else
     {
         G.Writeln2("*** ERROR: Type mismatch regarding power function");
         throw new GekkoException();
     }
 }
Esempio n. 29
0
 public IVariable Divide(IVariable x, GekkoTime t)
 {
     if (x.Type() == EVariableType.TimeSeries)
     {
         return(new ScalarVal(O.GetVal(this, t) / O.GetVal(x, t)));
     }
     else if (x.Type() == EVariableType.Val)
     {
         return(new ScalarVal(O.GetVal(this, t) / O.GetVal(x, t)));
     }
     else
     {
         G.Writeln2("*** ERROR: Type mismatch regarding division");
         throw new GekkoException();
     }
 }
Esempio n. 30
0
        /// <summary>
        /// For the given timeseries, this sets the data of the given period to array to the values given in the input array. An offset may be used.
        /// </summary>
        /// <param name="gt1">Start of the time period.</param>
        /// <param name="gt2">End of the time period</param>
        /// <param name="input">The input.</param>
        /// <param name="inputOffset">The input offset.</param>
        /// <exception cref="GekkoException">Exception if frequency of timeseries and periods differ.</exception>
        public void SetDataSequence(GekkoTime gt1, GekkoTime gt2, double[] input, int inputOffset)
        {
            if (this.isTimeless)
            {
                G.Writeln2("*** ERROR: Timeless variable error #3");
                throw new GekkoException();
            }
            if (this.parentDatabank != null && this.parentDatabank.protect)
            {
                Program.ProtectError("You cannot change observations in a timeseries residing in a non-editable databank, see OPEN<edit> or UNLOCK");
            }
            //Program.ErrorIfDatabanksSwapped(this);
            if (this.freqEnum != gt1.freq || gt1.freq != gt2.freq)
            {
                //This check: better safe than sorry!
                //See comment to GetData()
                G.Writeln2("*** ERROR: Freq mismatch");
                throw new GekkoException();
            }
            if (this.dataArray == null)
            {
                //slack: init could be more precise regarding size, for non-annual frequencies.
                GekkoTime gtTemp = new GekkoTime(gt1.freq, (gt1.super + gt2.super) / 2, 1);
                InitDataArray(gtTemp);  //assumes subperiod 1
            }
            int index1 = -12345;
            int index2 = -12345;

            index1 = GetArrayIndex(gt1);
            index2 = GetArrayIndex(gt2);
            if (index1 < 0 || index1 >= this.dataArray.Length || index2 < 0 || index2 >= this.dataArray.Length)
            {
                index1 = ResizeDataArray(gt1);
                index2 = ResizeDataArray(gt2); //this would never change index1, since slots are added at the end
            }
            System.Array.Copy(input, inputOffset, this.dataArray, index1, index2 - index1 + 1);
            //Adjust start and end data positions.
            if (index2 > this.lastPeriodPositionInArray)
            {
                this.lastPeriodPositionInArray = index2;
            }
            if (index1 < this.firstPeriodPositionInArray)
            {
                this.firstPeriodPositionInArray = index1;
            }
            this.SetDirtyGhost(true, false);
        }