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; } }
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 } }
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(); } } }
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(); } }
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(); } }
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); } }
public static void CodeLines(P p) { GekkoTime t = Globals.tNull; C0(p); C1(p); }
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); }
private void CheckSameFreq(GekkoTime gt2) { if (this.freq != gt2.freq) { G.Writeln2("*** ERROR: Comparing two different frequencies"); throw new GekkoException(); } }
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(); } } }
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); }
/// <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)); }
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)); }
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))); }
public bool IsSamePeriod(GekkoTime gt2) { CheckSameFreq(gt2); if (this.super == gt2.super) { if (this.sub == gt2.sub) { return(true); } } return(false); }
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); }
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(); } }
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(); }
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)); }
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); }
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(); }
/// <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); }
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); }
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)); }
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(); } } }
/// <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); } }
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); }
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(); } }
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(); } }
/// <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); }