public void Populate() { if (DefinitionType == TableDefinitionType.FREE) { return; // Nothing to do } Length = 0; if (DefinitionType == TableDefinitionType.PROJECTION) // There are import dimensions so copy data from another set (projection of another set) { List<DcColumn> inColumns = InputColumns.Where(d => d.GetData().IsAppendData).ToList(); foreach(DcColumn inColumn in inColumns) { inColumn.GetData().Translate(); inColumn.GetData().Evaluate(); // Delegate to column evaluation - it will add records from column expression } } else if (DefinitionType == TableDefinitionType.PRODUCT) // Product of local sets (no project/de-project from another set) { // Input variable for where formula DcVariable thisVariable = new Variable(this.Schema.Name, this.Name, "this"); thisVariable.TypeSchema = this.Schema; thisVariable.TypeTable = this; // Evaluator expression for where formula ExprNode outputExpr = this.WhereExpr; if(outputExpr != null) { outputExpr.OutputVariable.SchemaName = this.Schema.Name; outputExpr.OutputVariable.TypeName = "Boolean"; outputExpr.OutputVariable.TypeSchema = this.Schema; outputExpr.OutputVariable.TypeTable = this.Schema.GetPrimitiveType("Boolean"); outputExpr.Resolve(this.Space, new List<DcVariable>() { thisVariable }); outputExpr.EvaluateBegin(); } DcTableWriter tableWriter = this.GetTableWriter(); tableWriter.Open(); // // Find all local greater dimensions to be varied (including the super-dim) // DcColumn[] cols = Columns.Where(x => x.IsKey && !x.IsPrimitive).ToArray(); int colCount = cols.Length; // Dimensionality - how many free dimensions object[] vals = new object[colCount]; // A record with values for each free dimension being varied // Prepare columns foreach (DcColumn col in cols) { col.GetData().AutoIndex = true; // We need true to correctly evaluate where condition and correctly remove last element if it is wrong //col.GetData().Nullify(); } // // The current state of the search procedure // Rowid[] lengths = new Rowid[colCount]; // Size of each dimension being varied (how many offsets in each dimension) for (int i = 0; i < colCount; i++) lengths[i] = cols[i].Output.GetData().Length; Rowid[] offsets = new Rowid[colCount]; // The current point/offset for each dimensions during search for (int i = 0; i < colCount; i++) offsets[i] = -1; int top = -1; // The current level/top where we change the offset. Depth of recursion. do ++top; while (top < colCount && lengths[top] == 0); // Alternative recursive iteration: http://stackoverflow.com/questions/13655299/c-sharp-most-efficient-way-to-iterate-through-multiple-arrays-list while (top >= 0) { if (top == colCount) // New element is ready. Process it. { // Initialize a record and append it for (int i = 0; i < colCount; i++) { vals[i] = offsets[i]; } Rowid input = tableWriter.Append(cols, vals); // // Now check if this appended element satisfies the where expression and if not then remove it // if (outputExpr != null) { // Set 'this' variable to the last elements (that has been just appended) which will be read by the expression thisVariable.SetValue(this.GetData().Length - 1); // Evaluate expression outputExpr.Evaluate(); bool satisfies = (bool)outputExpr.OutputVariable.GetValue(); if (!satisfies) { Length = Length - 1; // Remove elements } } top--; while (top >= 0 && lengths[top] == 0) // Go up by skipping empty dimensions and reseting { offsets[top--] = -1; } } else { // Find the next valid offset offsets[top]++; if (offsets[top] < lengths[top]) // Offset chosen { do ++top; while (top < colCount && lengths[top] == 0); // Go up (forward) by skipping empty dimensions } else // Level is finished. Go back. { do { offsets[top--] = -1; } while (top >= 0 && lengths[top] == 0); // Go down (backward) by skipping empty dimensions and reseting } } } // Prepare columns foreach (DcColumn col in cols) { col.GetData().Reindex(); col.GetData().AutoIndex = true; } if (tableWriter != null) { tableWriter.Close(); } if (outputExpr != null) { outputExpr.EvaluateEnd(); } } else { throw new NotImplementedException("This table definition type is not implemented and cannot be populated."); } }
public virtual void Evaluate() { // Either formula is not needed or not yet provided if (formulaExpr == null || formulaExpr.DefinitionType == ColumnDefinitionType.FREE) { _evaluateError = false; ((Column)Column).NotifyPropertyChanged(""); return; // Nothing to evaluate } // // Evaluate depends on the type of definition // AutoIndex = false; //Nullify(); object thisCurrent = null; if (Column.Input is TableCsv) // Import from CSV { formulaExpr.EvaluateBegin(); DcTableReader tableReader = Column.Input.GetData().GetTableReader(); tableReader.Open(); while ((thisCurrent = tableReader.Next()) != null) { thisVariable.SetValue(thisCurrent); // Set parameters of the expression formulaExpr.Evaluate(); // Evaluate the expression // We do not store import functions (we do not need this data) object newValue = formulaExpr.OutputVariable.GetValue(); //columnData.SetValue((Rowid)thisCurrent, newValue); } tableReader.Close(); formulaExpr.EvaluateEnd(); } else if (formulaExpr.DefinitionType == ColumnDefinitionType.ARITHMETIC || formulaExpr.DefinitionType == ColumnDefinitionType.LINK) { formulaExpr.EvaluateBegin(); DcTableReader tableReader = Column.Input.GetData().GetTableReader(); tableReader.Open(); while ((thisCurrent = tableReader.Next()) != null) { thisVariable.SetValue(thisCurrent); // Set parameters of the expression formulaExpr.Evaluate(); // Evaluate the expression // Write the result value to the function // NOTE: We want to implement write operations with functions in the expression itself, particularly, because this might be done by intermediate nodes each of them having also APPEND flag // NOTE: when writing or find/append output to a table, an expression needs a TableWriter (or reader) object which is specific to the expression node (also intermediate) // NOTE: it could be meaningful to implement separately TUPLE (DOWN, NON-PRIMITIVE) nodes and CALL (UP, PRIMITIVE) expression classes since their general logic/purpose is quite different, particularly, for table writing. // NOTE: where expression (in tables) is evaluated without writing to column object newValue = formulaExpr.OutputVariable.GetValue(); this.SetValue((Rowid)thisCurrent, newValue); } tableReader.Close(); formulaExpr.EvaluateEnd(); } else if (formulaExpr.DefinitionType == ColumnDefinitionType.AGGREGATION) { // Aassert: FactTable.GroupFormula + ThisSet.ThisFunc = FactTable.MeasureFormula // Aassert: if LoopSet == ThisSet then GroupCode = null, ThisFunc = MeasureCode DcTable thisTable = Column.Input.Schema.GetSubTable(factsExpr.Name); formulaExpr.EvaluateBegin(); DcTableReader tableReader = thisTable.GetData().GetTableReader(); tableReader.Open(); while ((thisCurrent = tableReader.Next()) != null) { thisVariable.SetValue(thisCurrent); // Set parameters of the expression groupExpr.Evaluate(); Rowid groupElement = (Rowid)groupExpr.OutputVariable.GetValue(); groupVariable.SetValue(groupElement); measureExpr.Evaluate(); object measureValue = measureExpr.OutputVariable.GetValue(); measureVariable.SetValue(measureValue); outputExpr.Evaluate(); // Evaluate the expression // Write the result value to the function object newValue = outputExpr.OutputVariable.GetValue(); this.SetValue(groupElement, newValue); } tableReader.Close(); formulaExpr.EvaluateEnd(); } else { throw new NotImplementedException("This type of column definition is not implemented."); } Reindex(); AutoIndex = true; // Finally, we need to set the flag that indicates the result of the operation and status for the column _evaluateError = false; ((Column)Column).NotifyPropertyChanged(""); }