diff --git a/src/abstract-interpretation/data-frame/absint-visitor.ts b/src/abstract-interpretation/data-frame/absint-visitor.ts index 56df52d49a2..2cd7c416040 100644 --- a/src/abstract-interpretation/data-frame/absint-visitor.ts +++ b/src/abstract-interpretation/data-frame/absint-visitor.ts @@ -1,12 +1,12 @@ -import { type CfgBasicBlockVertex, type CfgSimpleVertex, type ControlFlowInformation , CfgVertexType, getVertexRootId, isMarkerVertex } from '../../control-flow/control-flow-graph'; -import { type SemanticCfgGuidedVisitorConfiguration , SemanticCfgGuidedVisitor } from '../../control-flow/semantic-cfg-guided-visitor'; +import { type CfgBasicBlockVertex, type CfgSimpleVertex, type ControlFlowInformation, CfgVertexType, getVertexRootId, isMarkerVertex } from '../../control-flow/control-flow-graph'; +import { type SemanticCfgGuidedVisitorConfiguration, SemanticCfgGuidedVisitor } from '../../control-flow/semantic-cfg-guided-visitor'; import type { DataflowGraph } from '../../dataflow/graph/graph'; import type { DataflowGraphVertexFunctionCall, DataflowGraphVertexVariableDefinition } from '../../dataflow/graph/vertex'; import type { NoInfo, RNode } from '../../r-bridge/lang-4.x/ast/model/model'; import type { NormalizedAst, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate'; import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id'; import { isNotUndefined } from '../../util/assert'; -import { DataFrameInfoMarker, hasDataFrameAssignmentInfo, hasDataFrameExpressionInfo, hasDataFrameInfoMarker, type AbstractInterpretationInfo } from './absint-info'; +import { type AbstractInterpretationInfo, DataFrameInfoMarker, hasDataFrameAssignmentInfo, hasDataFrameExpressionInfo, hasDataFrameInfoMarker } from './absint-info'; import { DataFrameDomain, DataFrameStateDomain } from './dataframe-domain'; import { mapDataFrameAccess } from './mappers/access-mapper'; import { isAssignmentTarget, mapDataFrameVariableAssignment } from './mappers/assignment-mapper'; diff --git a/src/abstract-interpretation/data-frame/dataframe-domain.ts b/src/abstract-interpretation/data-frame/dataframe-domain.ts index 611d5751b62..efe27bf238e 100644 --- a/src/abstract-interpretation/data-frame/dataframe-domain.ts +++ b/src/abstract-interpretation/data-frame/dataframe-domain.ts @@ -2,12 +2,13 @@ import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-i import type { AbstractDomainValue } from '../domains/abstract-domain'; import { PosIntervalDomain } from '../domains/positive-interval-domain'; import { ProductDomain } from '../domains/product-domain'; -import { SetUpperBoundDomain } from '../domains/set-upper-bound-domain'; +import type { SetRangeLimit } from '../domains/set-range-domain'; +import { SetRangeDomain } from '../domains/set-range-domain'; import { StateAbstractDomain } from '../domains/state-abstract-domain'; /** The type of the abstract product representing the shape of data frames */ export type AbstractDataFrameShape = { - colnames: SetUpperBoundDomain; + colnames: SetRangeDomain; cols: PosIntervalDomain; rows: PosIntervalDomain; } @@ -19,9 +20,9 @@ export type DataFrameShapeProperty { - constructor(value: AbstractDataFrameShape, maxColNames?: number) { + constructor(value: AbstractDataFrameShape, maxColNames?: SetRangeLimit | number) { super({ - colnames: new SetUpperBoundDomain(value.colnames.value, maxColNames ?? value.colnames.limit), + colnames: new SetRangeDomain(value.colnames.value, maxColNames ?? value.colnames.limit), cols: new PosIntervalDomain(value.cols.value), rows: new PosIntervalDomain(value.rows.value) }); @@ -29,7 +30,7 @@ export class DataFrameDomain extends ProductDomain { public create(value: AbstractDataFrameShape): this; public create(value: AbstractDataFrameShape): DataFrameDomain { - return new DataFrameDomain(value, this.maxColNames); + return new DataFrameDomain(value, this.colnames.limit); } /** @@ -53,16 +54,9 @@ export class DataFrameDomain extends ProductDomain { return this.value.rows; } - /** - * The maximum number of inferred column names of the column names domain. - */ - public get maxColNames(): number { - return this.value.colnames.limit; - } - public static bottom(maxColNames?: number): DataFrameDomain { return new DataFrameDomain({ - colnames: SetUpperBoundDomain.bottom(maxColNames), + colnames: SetRangeDomain.bottom(maxColNames), cols: PosIntervalDomain.bottom(), rows: PosIntervalDomain.bottom() }); @@ -70,7 +64,7 @@ export class DataFrameDomain extends ProductDomain { public static top(maxColNames?: number): DataFrameDomain { return new DataFrameDomain({ - colnames: SetUpperBoundDomain.top(maxColNames), + colnames: SetRangeDomain.top(maxColNames), cols: PosIntervalDomain.top(), rows: PosIntervalDomain.top() }); diff --git a/src/abstract-interpretation/data-frame/mappers/access-mapper.ts b/src/abstract-interpretation/data-frame/mappers/access-mapper.ts index 6fcb5aefc84..740ae9a32ef 100644 --- a/src/abstract-interpretation/data-frame/mappers/access-mapper.ts +++ b/src/abstract-interpretation/data-frame/mappers/access-mapper.ts @@ -3,7 +3,7 @@ import type { ResolveInfo } from '../../../dataflow/eval/resolve/alias-tracking' import type { DataflowGraph } from '../../../dataflow/graph/graph'; import type { RNode } from '../../../r-bridge/lang-4.x/ast/model/model'; import type { RAccess, RIndexAccess, RNamedAccess } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-access'; -import { type RFunctionArgument , EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; +import { type RFunctionArgument, EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate'; import { RType } from '../../../r-bridge/lang-4.x/ast/model/type'; import type { DataFrameExpressionInfo, DataFrameOperation } from '../absint-info'; diff --git a/src/abstract-interpretation/data-frame/mappers/arguments.ts b/src/abstract-interpretation/data-frame/mappers/arguments.ts index ecaafa23884..925c3624e9c 100644 --- a/src/abstract-interpretation/data-frame/mappers/arguments.ts +++ b/src/abstract-interpretation/data-frame/mappers/arguments.ts @@ -4,15 +4,15 @@ import { isUseVertex, VertexType } from '../../../dataflow/graph/vertex'; import { toUnnamedArgument } from '../../../dataflow/internal/process/functions/call/argument/make-argument'; import type { RNode } from '../../../r-bridge/lang-4.x/ast/model/model'; import type { RArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-argument'; -import { type RFunctionArgument, type RFunctionCall , EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; +import { type RFunctionArgument, type RFunctionCall, EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; import type { RSymbol } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol'; import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate'; +import { visitAst } from '../../../r-bridge/lang-4.x/ast/model/processing/visitor'; import { RType } from '../../../r-bridge/lang-4.x/ast/model/type'; import { RNull } from '../../../r-bridge/lang-4.x/convert-values'; import type { AbstractInterpretationInfo } from '../absint-info'; -import { resolveIdToDataFrameShape } from '../shape-inference'; import { resolveIdToArgName, resolveIdToArgValue, unquoteArgument } from '../resolve-args'; -import { visitAst } from '../../../r-bridge/lang-4.x/ast/model/processing/visitor'; +import { resolveIdToDataFrameShape } from '../shape-inference'; /** Regular expression representing valid columns names, e.g. for `data.frame` */ const ColNamesRegex = /^[A-Za-z.][A-Za-z0-9_.]*$/; diff --git a/src/abstract-interpretation/data-frame/mappers/function-mapper.ts b/src/abstract-interpretation/data-frame/mappers/function-mapper.ts index 924bd2c6224..495c6667b1a 100644 --- a/src/abstract-interpretation/data-frame/mappers/function-mapper.ts +++ b/src/abstract-interpretation/data-frame/mappers/function-mapper.ts @@ -1,13 +1,14 @@ -import { VariableResolve } from '../../../config'; +import { VariableResolve } from '../../../config'; import { type ResolveInfo } from '../../../dataflow/eval/resolve/alias-tracking'; import type { DataflowGraph } from '../../../dataflow/graph/graph'; import { toUnnamedArgument } from '../../../dataflow/internal/process/functions/call/argument/make-argument'; import { findSource } from '../../../dataflow/internal/process/functions/call/built-in/built-in-source'; +import type { ReadOnlyFlowrAnalyzerContext } from '../../../project/context/flowr-analyzer-context'; import type { RNode } from '../../../r-bridge/lang-4.x/ast/model/model'; -import { type RFunctionArgument , EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; +import { type RFunctionArgument, EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate'; import { RType } from '../../../r-bridge/lang-4.x/ast/model/type'; -import { type RParseRequest , requestFromInput } from '../../../r-bridge/retriever'; +import { type RParseRequest, requestFromInput } from '../../../r-bridge/retriever'; import { assertUnreachable, isNotUndefined, isUndefined } from '../../../util/assert'; import { readLineByLineSync } from '../../../util/files'; import type { DataFrameExpressionInfo, DataFrameOperation } from '../absint-info'; @@ -15,8 +16,7 @@ import { DataFrameDomain } from '../dataframe-domain'; import { resolveIdToArgName, resolveIdToArgValue, resolveIdToArgValueSymbolName, resolveIdToArgVectorLength, unescapeSpecialChars } from '../resolve-args'; import type { ConstraintType } from '../semantics'; import { resolveIdToDataFrameShape } from '../shape-inference'; -import { type FunctionParameterLocation , escapeRegExp, filterValidNames, getArgumentValue, getEffectiveArgs, getFunctionArgument, getFunctionArguments, getUnresolvedSymbolsInExpression, hasCriticalArgument, isDataFrameArgument, isNamedArgument, isRNull } from './arguments'; -import type { ReadOnlyFlowrAnalyzerContext } from '../../../project/context/flowr-analyzer-context'; +import { type FunctionParameterLocation, escapeRegExp, filterValidNames, getArgumentValue, getEffectiveArgs, getFunctionArgument, getFunctionArguments, getUnresolvedSymbolsInExpression, hasCriticalArgument, isDataFrameArgument, isNamedArgument, isRNull } from './arguments'; /** * Represents the different types of data frames in R @@ -564,7 +564,7 @@ type OtherDataFrameFunctionMapping = OtherDataFrameEntryPoint | OtherDataFrameTr * - `args` contains the function call arguments * - `params` contains the expected argument location for each parameter of the function * - `info` contains the resolve information - * - `ctx` access to the current flowR analyzer context + * - `ctx` contains the current flowR analyzer context */ type DataFrameFunctionMapping = ( args: readonly RFunctionArgument[], @@ -1127,20 +1127,20 @@ function mapDataFrameMutate( }); } - if(deletedCols === undefined || deletedCols.length > 0) { + if(mutatedCols === undefined || mutatedCols.length > 0 || deletedCols?.length === 0) { result.push({ - operation: 'removeCols', + operation: 'mutateCols', operand: operand?.info.id, - colnames: deletedCols, - options: { maybe: true } + colnames: mutatedCols }); operand = undefined; } - if(mutatedCols === undefined || mutatedCols.length > 0 || deletedCols?.length === 0) { + if(deletedCols === undefined || deletedCols.length > 0) { result.push({ - operation: 'mutateCols', + operation: 'removeCols', operand: operand?.info.id, - colnames: mutatedCols + colnames: deletedCols, + options: { maybe: true } }); operand = undefined; } @@ -1381,6 +1381,7 @@ function getRequestFromRead( } } request = request ? ctx.files.resolveRequest(request).r : undefined; + return { source, request }; } diff --git a/src/abstract-interpretation/data-frame/resolve-args.ts b/src/abstract-interpretation/data-frame/resolve-args.ts index f50ede90077..68b9f086fb3 100644 --- a/src/abstract-interpretation/data-frame/resolve-args.ts +++ b/src/abstract-interpretation/data-frame/resolve-args.ts @@ -1,4 +1,4 @@ -import { type ResolveInfo , resolveIdToValue } from '../../dataflow/eval/resolve/alias-tracking'; +import { type ResolveInfo, resolveIdToValue } from '../../dataflow/eval/resolve/alias-tracking'; import type { RArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-argument'; import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate'; import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id'; diff --git a/src/abstract-interpretation/data-frame/semantics.ts b/src/abstract-interpretation/data-frame/semantics.ts index 2112c15fb3c..1616c9a03c5 100644 --- a/src/abstract-interpretation/data-frame/semantics.ts +++ b/src/abstract-interpretation/data-frame/semantics.ts @@ -1,6 +1,7 @@ import { assertUnreachable, isNotUndefined } from '../../util/assert'; import { Bottom, Top } from '../domains/lattice'; import { PosIntervalDomain, PosIntervalTop } from '../domains/positive-interval-domain'; +import type { ArrayRangeValue } from '../domains/set-range-domain'; import { DataFrameDomain } from './dataframe-domain'; /** @@ -105,7 +106,7 @@ function applyCreateSemantics( value: DataFrameDomain, { colnames, rows }: { colnames: (string | undefined)[] | undefined, rows: number | [number, number] | undefined } ): DataFrameDomain { - const colnamesValue = colnames?.every(isNotUndefined) ? colnames : Top; + const colnamesValue = setRange(colnames); const colsValue = colnames !== undefined ? [colnames.length, colnames.length] as const : PosIntervalTop; const rowsValue = Array.isArray(rows) ? rows : typeof rows === 'number' ? [rows, rows] as const : PosIntervalTop; @@ -129,14 +130,14 @@ function applyAccessColsSemantics( ): DataFrameDomain { if(columns?.every(col => typeof col === 'string')) { return new DataFrameDomain({ - colnames: value.colnames.join(columns), + colnames: value.colnames.union(setRange(columns)), cols: value.cols, rows: value.rows }); } else if(columns?.every(col => typeof col === 'number')) { return new DataFrameDomain({ colnames: value.colnames, - cols: columns?.reduce((current, col) => current.max([col, col]), value.cols), + cols: columns.reduce((current, col) => current.max([col, col]), value.cols), rows: value.rows }); } @@ -165,20 +166,20 @@ function applyAssignColsSemantics( const cols = columns.length; return new DataFrameDomain({ - colnames: value.colnames.join(columns), + colnames: value.colnames.union(setRange(columns)), cols: value.cols.add([0, cols]).max([cols, cols]), rows: value.rows }); } else if(columns?.every(col => typeof col === 'number')) { return new DataFrameDomain({ - colnames: value.colnames.top(), + colnames: value.colnames.widenUp(), cols: columns.reduce((current, col) => current.max([col, col]), value.cols), rows: value.rows }); } return new DataFrameDomain({ - colnames: value.colnames.top(), - cols: value.cols.extendUp(), + colnames: value.colnames.widenUp(), + cols: value.cols.widenUp(), rows: value.rows }); } @@ -197,7 +198,7 @@ function applyAssignRowsSemantics( return new DataFrameDomain({ colnames: value.colnames, cols: value.cols, - rows: value.rows.extendUp() + rows: value.rows.widenUp() }); } @@ -208,7 +209,7 @@ function applySetColNamesSemantics( ): DataFrameDomain { if(options?.partial) { return new DataFrameDomain({ - colnames: colnames?.every(isNotUndefined) ? value.colnames.join(colnames) : value.colnames.top(), + colnames: value.colnames.widenDown().union(setRange(colnames)), cols: value.cols, rows: value.rows }); @@ -216,7 +217,7 @@ function applySetColNamesSemantics( const allColNames = colnames?.every(isNotUndefined) && value.cols.value !== Bottom && colnames.length >= value.cols.value[1]; return new DataFrameDomain({ - colnames: allColNames ? value.colnames.create(colnames) : value.colnames.top(), + colnames: allColNames ? value.colnames.create(setRange(colnames)) : value.colnames.widenDown().union(setRange(colnames)).widenUp(), cols: value.cols, rows: value.rows }); @@ -227,8 +228,8 @@ function applyAddColsSemantics( { colnames }: { colnames: (string | undefined)[] | undefined } ): DataFrameDomain { return new DataFrameDomain({ - colnames: colnames?.every(isNotUndefined) ? value.colnames.join(colnames) : value.colnames.top(), - cols: colnames !== undefined ? value.cols.add([colnames.length, colnames.length]) : value.cols.extendUp(), + colnames: colnames !== undefined ? value.colnames.union(setRange(colnames)) : value.colnames.widenUp(), + cols: colnames !== undefined ? value.cols.add([colnames.length, colnames.length]) : value.cols.widenUp(), rows: value.rows }); } @@ -242,13 +243,13 @@ function applyAddRowsSemantics( ...value, colnames: value.colnames.top(), cols: rows !== undefined ? value.cols.add([1, 1]) : value.cols.top(), - rows: rows !== undefined ? value.rows.add([rows, rows]) : value.rows.extendUp() + rows: rows !== undefined ? value.rows.add([rows, rows]) : value.rows.widenUp() }); } return new DataFrameDomain({ colnames: value.colnames, cols: value.cols, - rows: rows !== undefined ? value.rows.add([rows, rows]) : value.rows.extendUp() + rows: rows !== undefined ? value.rows.add([rows, rows]) : value.rows.widenUp() }); } @@ -259,14 +260,14 @@ function applyRemoveColsSemantics( ): DataFrameDomain { if(options?.maybe) { return new DataFrameDomain({ - colnames: colnames !== undefined ? value.colnames.subtract(colnames.filter(isNotUndefined)) : value.colnames, - cols: colnames !== undefined ? value.cols.subtract([colnames.length, 0]) : value.cols.extendDown(), + colnames: colnames !== undefined ? value.colnames.subtract(setRange(colnames)) : value.colnames.widenDown(), + cols: colnames !== undefined ? value.cols.subtract([colnames.length, 0]) : value.cols.widenDown(), rows: value.rows }); } return new DataFrameDomain({ - colnames: colnames !== undefined ? value.colnames.subtract(colnames.filter(isNotUndefined)) : value.colnames, - cols: colnames !== undefined ? value.cols.subtract([colnames.length, colnames.length]) : value.cols.extendDown(), + colnames: colnames !== undefined ? value.colnames.subtract(setRange(colnames)) : value.colnames.widenDown(), + cols: colnames !== undefined ? value.cols.subtract([colnames.length, colnames.length]) : value.cols.widenDown(), rows: value.rows }); } @@ -280,13 +281,13 @@ function applyRemoveRowsSemantics( return new DataFrameDomain({ colnames: value.colnames, cols: value.cols, - rows: rows !== undefined ? value.rows.subtract([rows, 0]) : value.rows.extendDown() + rows: rows !== undefined ? value.rows.subtract([rows, 0]) : value.rows.widenDown() }); } return new DataFrameDomain({ colnames: value.colnames, cols: value.cols, - rows: rows !== undefined ? value.rows.subtract([rows, rows]) : value.rows.extendDown() + rows: rows !== undefined ? value.rows.subtract([rows, rows]) : value.rows.widenDown() }); } @@ -295,7 +296,7 @@ function applyConcatColsSemantics( { other }: { other: DataFrameDomain } ): DataFrameDomain { return new DataFrameDomain({ - colnames: value.colnames.join(other.colnames), + colnames: value.colnames.union(other.colnames), cols: value.cols.add(other.cols), rows: value.rows }); @@ -334,13 +335,13 @@ function applySubsetColsSemantics( } else if(options?.renamedCols) { return new DataFrameDomain({ colnames: value.colnames.top(), - cols: colnames !== undefined ? value.cols.min([colnames.length, colnames.length]) : value.cols.extendDown(), + cols: colnames !== undefined ? value.cols.min([colnames.length, colnames.length]) : value.cols.widenDown(), rows: value.rows }); } return new DataFrameDomain({ - colnames: colnames?.every(isNotUndefined) ? value.colnames.meet(colnames) : value.colnames, - cols: colnames !== undefined ? value.cols.min([colnames.length, colnames.length]) : value.cols.extendDown(), + colnames: colnames !== undefined ? value.colnames.intersect(setRange(colnames)) : value.colnames.widenDown(), + cols: colnames !== undefined ? value.cols.min([colnames.length, colnames.length]) : value.cols.widenDown(), rows: value.rows }); } @@ -360,7 +361,7 @@ function applySubsetRowsSemantics( return new DataFrameDomain({ colnames: value.colnames, cols: value.cols, - rows: rows !== undefined ? value.rows.min([rows, rows]) : value.rows.extendDown() + rows: rows !== undefined ? value.rows.min([rows, rows]) : value.rows.widenDown() }); } @@ -371,7 +372,7 @@ function applyFilterRowsSemantics( return new DataFrameDomain({ colnames: value.colnames, cols: value.cols, - rows: condition ? value.rows : condition === false ? value.rows.create([0, 0]) : value.rows.extendDown() + rows: condition ? value.rows : condition === false ? value.rows.create([0, 0]) : value.rows.widenDown() }); } @@ -380,8 +381,8 @@ function applyMutateColsSemantics( { colnames }: { colnames: (string | undefined)[] | undefined } ): DataFrameDomain { return new DataFrameDomain({ - colnames: colnames?.every(isNotUndefined) ? value.colnames.join(colnames) : value.colnames.top(), - cols: colnames !== undefined ? value.cols.add([0, colnames.length]).max([colnames.length, colnames.length]) : value.cols.extendUp(), + colnames: colnames !== undefined ? value.colnames.union(setRange(colnames)) : value.colnames.widenUp(), + cols: colnames !== undefined ? value.cols.add([0, colnames.length]).max([colnames.length, colnames.length]) : value.cols.widenUp(), rows: value.rows }); } @@ -393,7 +394,7 @@ function applyGroupBySemantics( ): DataFrameDomain { if(options?.mutatedCols) { return new DataFrameDomain({ - colnames: by.every(isNotUndefined) ? value.colnames.join(by) : value.colnames.top(), + colnames: value.colnames.union(setRange(by)), cols: value.cols.add([0, by.length]), rows: value.rows }); @@ -407,8 +408,8 @@ function applySummarizeSemantics( { colnames }: { colnames: (string | undefined)[] | undefined } ): DataFrameDomain { return new DataFrameDomain({ - colnames: colnames?.every(isNotUndefined) ? value.colnames.join(colnames) : value.colnames.top(), - cols: colnames !== undefined ? value.cols.add([0, colnames.length]).min([colnames.length, +Infinity]) : value.cols.extendUp(), + colnames: colnames !== undefined ? value.colnames.join(setRange([])).union(setRange(colnames)) : value.colnames.widenUp(), + cols: colnames !== undefined ? value.cols.add([0, colnames.length]).min([colnames.length, +Infinity]) : value.cols.widenUp(), rows: value.rows.min([1, +Infinity]).max([0, 1]) }); } @@ -434,25 +435,26 @@ function applyJoinSemantics( return new PosIntervalDomain([lower.value[0], interval1.value[1] * interval2.value[1]]); } }; - const commonCols = value.colnames.meet(other.colnames); - let duplicateCols: boolean; // whether columns may be renamed due to occurrence in both data frames + let duplicateCols: string[] | undefined; // columns that may be renamed due to occurring in both data frames let productRows: boolean; // whether the resulting rows may be a Cartesian product of the rows of the data frames if(options?.natural) { - duplicateCols = false; - productRows = commonCols.isValue() && commonCols.value.size === 0; + const commonCols = value.colnames.intersect(other.colnames).upper(); + duplicateCols = []; + productRows = commonCols !== Bottom && commonCols !== Top && commonCols.size === 0; } else if(by === undefined) { - duplicateCols = true; + duplicateCols = undefined; productRows = true; } else if(by.length === 0) { - duplicateCols = commonCols.isTop() || (commonCols.isValue() && commonCols.value.size > 0); + const commonCols = value.colnames.intersect(other.colnames).upper(); + duplicateCols = commonCols !== Bottom ? commonCols !== Top ? [...commonCols] : undefined : []; productRows = true; } else if(by.every(isNotUndefined)) { - const remainingCols = commonCols.subtract(by); - duplicateCols = remainingCols.isTop() || (remainingCols.isValue() && remainingCols.value.size > 0); + const remainingCols = value.colnames.intersect(other.colnames).subtract(setRange(by)).upper(); + duplicateCols = remainingCols !== Bottom ? remainingCols !== Top ? [...remainingCols] : undefined : []; productRows = false; } else { - duplicateCols = true; + duplicateCols = undefined; productRows = false; } const joinType = options?.join ?? 'inner'; @@ -460,7 +462,7 @@ function applyJoinSemantics( switch(joinType) { case 'inner': - rows = value.rows.min(other.rows).extendDown(); + rows = value.rows.min(other.rows).widenDown(); break; case 'left': rows = value.rows; @@ -476,7 +478,7 @@ function applyJoinSemantics( } return new DataFrameDomain({ ...value, - colnames: duplicateCols ? value.colnames.top() : value.colnames.join(other.colnames), + colnames: duplicateCols === undefined ? value.colnames.top() : duplicateCols.length > 0 ? value.colnames.union(other.colnames).subtract(setRange(duplicateCols)).widenUp() : value.colnames.union(other.colnames), cols: by !== undefined ? value.cols.add(other.cols).subtract([by.length, by.length]) : mergeInterval(value.cols, other.cols), rows: productRows ? productInterval(rows, value.rows, other.rows) : rows }); @@ -497,3 +499,9 @@ function applyUnknownSemantics( ): DataFrameDomain { return value.top(); } + +function setRange(colnames: (string | undefined)[] | undefined): ArrayRangeValue { + const names = colnames?.filter(isNotUndefined) ?? []; + + return { min: names, range: names.length === colnames?.length ? [] : Top }; +} diff --git a/src/abstract-interpretation/data-frame/shape-inference.ts b/src/abstract-interpretation/data-frame/shape-inference.ts index b7e6cbe6eec..184f7410437 100644 --- a/src/abstract-interpretation/data-frame/shape-inference.ts +++ b/src/abstract-interpretation/data-frame/shape-inference.ts @@ -2,6 +2,7 @@ import { type ControlFlowInformation, getVertexRootId } from '../../control-flow import type { DataflowGraph } from '../../dataflow/graph/graph'; import { VertexType } from '../../dataflow/graph/vertex'; import { getOriginInDfg, OriginType } from '../../dataflow/origin/dfg-get-origin'; +import type { ReadOnlyFlowrAnalyzerContext } from '../../project/context/flowr-analyzer-context'; import type { RNode } from '../../r-bridge/lang-4.x/ast/model/model'; import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call'; import type { NormalizedAst, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate'; @@ -12,7 +13,6 @@ import { AbstractDomain } from '../domains/abstract-domain'; import { type AbstractInterpretationInfo, DataFrameInfoMarker, hasDataFrameInfoMarker } from './absint-info'; import { DataFrameShapeInferenceVisitor } from './absint-visitor'; import { type DataFrameDomain, DataFrameStateDomain } from './dataframe-domain'; -import type { ReadOnlyFlowrAnalyzerContext } from '../../project/context/flowr-analyzer-context'; /** * Infers the shape of data frames by performing abstract interpretation using the control flow graph of a program. diff --git a/src/abstract-interpretation/domains/abstract-domain.ts b/src/abstract-interpretation/domains/abstract-domain.ts index c1f59724526..0d8afd73c4f 100644 --- a/src/abstract-interpretation/domains/abstract-domain.ts +++ b/src/abstract-interpretation/domains/abstract-domain.ts @@ -1,5 +1,5 @@ import { guard } from '../../util/assert'; -import { type Lattice , Bottom, Top } from './lattice'; +import { type Lattice, Bottom, BottomSymbol, Top, TopSymbol } from './lattice'; /** * The default limit of inferred constraints in {@link AbstractDomain|AbstractDomains}. @@ -8,6 +8,7 @@ export const DEFAULT_INFERENCE_LIMIT = 50; /** * An abstract domain as complete lattice with a widening operator, narrowing operator, concretization function, and abstraction function. + * All operations of value abstract domains should not modify the domain in-place but return new values using {@link create}. * @template Concrete - Type of an concrete element of the concrete domain for the abstract domain * @template Abstract - Type of an abstract element of the abstract domain representing possible elements (excludes `Top` and `Bot`) * @template Top - Type of the Top element of the abstract domain representing all possible elements @@ -155,9 +156,9 @@ export function domainElementToString(value: AnyAbstractDomain | unknown): strin // eslint-disable-next-line @typescript-eslint/no-base-to-string return value.toString(); } else if(value === Top) { - return '⊤'; + return TopSymbol; } else if(value === Bottom) { - return '⊥'; + return BottomSymbol; } return JSON.stringify(value); } diff --git a/src/abstract-interpretation/domains/bounded-set-domain.ts b/src/abstract-interpretation/domains/bounded-set-domain.ts index ddd1cd0f702..3d4ca10c25f 100644 --- a/src/abstract-interpretation/domains/bounded-set-domain.ts +++ b/src/abstract-interpretation/domains/bounded-set-domain.ts @@ -1,7 +1,7 @@ import { setEquals } from '../../util/collections/set'; import { Ternary } from '../../util/logic'; import { AbstractDomain, DEFAULT_INFERENCE_LIMIT, domainElementToString } from './abstract-domain'; -import { Top } from './lattice'; +import { Top, TopSymbol } from './lattice'; import type { SatisfiableDomain } from './satisfiable-domain'; /* eslint-disable @typescript-eslint/unified-signatures */ @@ -159,7 +159,7 @@ export class BoundedSetDomain = BoundedSetLif public toString(): string { if(this.value === Top) { - return '⊤'; + return TopSymbol; } const string = this.value.values().map(domainElementToString).toArray().join(', '); diff --git a/src/abstract-interpretation/domains/interval-domain.ts b/src/abstract-interpretation/domains/interval-domain.ts index d245b9ae64d..ba2ebfdfca6 100644 --- a/src/abstract-interpretation/domains/interval-domain.ts +++ b/src/abstract-interpretation/domains/interval-domain.ts @@ -1,8 +1,8 @@ import { assertUnreachable } from '../../util/assert'; import { Ternary } from '../../util/logic'; import { AbstractDomain } from './abstract-domain'; -import { Bottom, Top } from './lattice'; -import { type SatisfiableDomain , NumericalComparator } from './satisfiable-domain'; +import { Bottom, BottomSymbol, Top } from './lattice'; +import { type SatisfiableDomain, NumericalComparator } from './satisfiable-domain'; /* eslint-disable @typescript-eslint/unified-signatures */ /** The Top element of the interval domain as interval [-∞, +∞] */ @@ -99,8 +99,6 @@ export class IntervalDomain if(this.value === Bottom || otherValue === Bottom) { return this.bottom(); - } else if(Math.max(this.value[0], otherValue[0]) > Math.min(this.value[1], otherValue[1])) { - return this.bottom(); } else { return this.create([Math.max(this.value[0], otherValue[0]), Math.min(this.value[1], otherValue[1])]); } @@ -248,7 +246,7 @@ export class IntervalDomain /** * Extends the lower bound of the current abstract value down to -∞. */ - public extendDown(): this { + public widenDown(): this { if(this.value === Bottom) { return this.bottom(); } else { @@ -259,7 +257,7 @@ export class IntervalDomain /** * Extends the upper bound of the current abstract value up to +∞. */ - public extendUp(): this { + public widenUp(): this { if(this.value === Bottom) { return this.bottom(); } else { @@ -276,7 +274,7 @@ export class IntervalDomain public toString(): string { if(this.value === Bottom) { - return '⊥'; + return BottomSymbol; } return `[${isFinite(this.value[0]) ? this.value[0] : '-∞'}, ${isFinite(this.value[1]) ? this.value[1] : '+∞'}]`; } diff --git a/src/abstract-interpretation/domains/lattice.ts b/src/abstract-interpretation/domains/lattice.ts index 69ee9946334..973c62df989 100644 --- a/src/abstract-interpretation/domains/lattice.ts +++ b/src/abstract-interpretation/domains/lattice.ts @@ -2,11 +2,13 @@ * The Top symbol to represent the Top element of complete lattices (e.g. of abstract domains). */ export const Top = Symbol('top'); +export const TopSymbol = '⊤'; /** * The Bottom symbol to represent the Bottom element of complete lattices (e.g. of abstract domains). */ export const Bottom = Symbol('bottom'); +export const BottomSymbol = '⊥'; /** * A complete lattice with a partially ordered set, join operator (LUB), meet operator (GLB), top element, and bottom element (e.g. for abstract domains). diff --git a/src/abstract-interpretation/domains/positive-interval-domain.ts b/src/abstract-interpretation/domains/positive-interval-domain.ts index 407ce289dd4..e1d834aac22 100644 --- a/src/abstract-interpretation/domains/positive-interval-domain.ts +++ b/src/abstract-interpretation/domains/positive-interval-domain.ts @@ -104,7 +104,7 @@ export class PosIntervalDomain /** * Extends the lower bound of the current abstract value down to 0. */ - public extendDown(): this { + public widenDown(): this { if(this.value === Bottom) { return this.bottom(); } else { diff --git a/src/abstract-interpretation/domains/satisfiable-domain.ts b/src/abstract-interpretation/domains/satisfiable-domain.ts index 797db614820..3549f5b73f3 100644 --- a/src/abstract-interpretation/domains/satisfiable-domain.ts +++ b/src/abstract-interpretation/domains/satisfiable-domain.ts @@ -3,7 +3,6 @@ import type { Ternary } from '../../util/logic'; /** * An abstract domain with satisfiability checks for concrete values. */ - export interface SatisfiableDomain { /** * Checks whether the current abstract value satisfies a concrete value (i.e. includes a concrete value). @@ -13,9 +12,8 @@ export interface SatisfiableDomain { } /** - * Represents the different types of numerical comparators for satifiability checks for an abstract domain. + * Represents the different types of numerical comparators for satisfiability checks for an abstract domain. */ - export enum NumericalComparator { Equal, Less, @@ -25,9 +23,8 @@ export enum NumericalComparator { } /** - * Represents the different types of set comparators for satifiability checks for an abstract domain. + * Represents the different types of set comparators for satisfiability checks for an abstract domain. */ - export enum SetComparator { Equal, Subset, diff --git a/src/abstract-interpretation/domains/set-range-domain.ts b/src/abstract-interpretation/domains/set-range-domain.ts new file mode 100644 index 00000000000..cb412dd2c0e --- /dev/null +++ b/src/abstract-interpretation/domains/set-range-domain.ts @@ -0,0 +1,453 @@ +import { assertUnreachable } from '../../util/assert'; +import { setEquals } from '../../util/collections/set'; +import { Ternary } from '../../util/logic'; +import { AbstractDomain, DEFAULT_INFERENCE_LIMIT, domainElementToString } from './abstract-domain'; +import { Bottom, BottomSymbol, Top, TopSymbol } from './lattice'; +import type { SatisfiableDomain } from './satisfiable-domain'; +import { SetComparator } from './satisfiable-domain'; +/* eslint-disable @typescript-eslint/unified-signatures */ + +/** The Top element of the set range domain with an empty set as minimum set and {@link Top} as range set */ +export const SetRangeTop = { min: new Set(), range: Top } as const satisfies SetRangeValue; + +/** The type of the actual values of the set range domain as tuple with a minimum set and range set of additional possible values (i.e. `[{"id","name"}, ∅]`, or `[{"id"}, {"score"}]`) */ +type SetRangeValue = { readonly min: ReadonlySet, readonly range: ReadonlySet | typeof Top }; +/** The type of the Top element of the set range domain as tuple with the empty set as minimum set and {@link Top} as range set (i.e. `[∅, Top]`) */ +type SetRangeTop = typeof SetRangeTop; +/** The type of the Bottom element of the set range domain as {@link Bottom} */ +type SetRangeBottom = typeof Bottom; +/** The type of the abstract values of the set range domain that are Top, Bottom, or actual values */ +type SetRangeLift = SetRangeValue | SetRangeTop | SetRangeBottom; + +/** The type of the actual values of the set range domain as array tuple with a minimum array and range array for better readability (e.g. `[["id","name"], []]`, or `[["id"], ["score"]]`) */ +export type ArrayRangeValue = { readonly min: T[], readonly range: T[] | typeof Top }; + +/** The type for the maximum number of elements in the minimum set and maximum set of the set range domain before over-approximation */ +export type SetRangeLimit = { readonly min: number, readonly range: number }; +const DefaultLimit = { min: DEFAULT_INFERENCE_LIMIT, range: DEFAULT_INFERENCE_LIMIT } as const satisfies SetRangeLimit; + +/** + * The set range abstract domain as range of possible value sets with a minimum set of values and a range of possible additional values + * (similar to an interval like structure with a lower bound and a difference to the upper bound). + * The Bottom element is defined as {@link Bottom} symbol and the Top element is defined as the range `[∅, Top]` where the minimum set is the empty set and the range is {@link Top}. + * @template T - Type of the values in the sets in the abstract domain + * @template Value - Type of the constraint in the abstract domain (Top, Bottom, or an actual value) + */ +export class SetRangeDomain = SetRangeLift> + extends AbstractDomain, SetRangeValue, SetRangeTop, SetRangeBottom, Value> + implements SatisfiableDomain> { + + public readonly limit: SetRangeLimit; + private readonly setType: typeof Set; + + /** + * @param limit - A limit for the maximum number of elements to store in the minimum set and maximum set before over-approximation + * @param newSet - An optional set constructor for the domain elements if the type `T` is not storable in a HashSet + */ + constructor(value: Value | ArrayRangeValue, limit: SetRangeLimit | number = DefaultLimit, setType: typeof Set = Set) { + limit = typeof limit === 'number' ? { min: limit, range: limit } : limit; + + if(value !== Bottom) { + const minSet = new setType(value.min); + const rangeSet = value.range === Top ? Top : new setType(value.range); + const minExceeds = minSet.size > limit.min; + const rangeExceeds = rangeSet === Top || rangeSet.size > limit.range || minSet.size + rangeSet.size > limit.min + limit.range; + + const min = minExceeds ? new setType(minSet.values().take(limit.min)) : minSet; + const range = rangeExceeds ? Top : minSet.union(rangeSet).difference(min); + super({ min, range } as SetRangeValue as Value); + } else { + super(value); + } + this.limit = limit; + this.setType = setType; + } + + public create(value: SetRangeLift | ArrayRangeValue): this; + public create(value: SetRangeLift | ArrayRangeValue): SetRangeDomain { + return new SetRangeDomain(value, this.limit, this.setType); + } + + /** + * The minimum set (lower bound) of the set range representing all values that must exist (subset of {@link upper}). + */ + public lower(): SetRangeValue['min'] | typeof Bottom { + if(this.value === Bottom) { + return Bottom; + } + return this.value.min; + } + + /** + * The maximum set (upper bound) of the set range representing all values that can possibly exist (union of {@link lower} and range). + */ + public upper(): SetRangeValue['range'] | typeof Bottom { + if(this.value === Bottom) { + return Bottom; + } + return this.value.range === Top ? Top : this.value.min.union(this.value.range); + } + + public static top(limit?: SetRangeLimit | number, setType?: typeof Set): SetRangeDomain { + return new SetRangeDomain(SetRangeTop, limit, setType); + } + + public static bottom(limit?: SetRangeLimit | number, setType?: typeof Set): SetRangeDomain { + return new SetRangeDomain(Bottom, limit, setType); + } + + public static abstract(concrete: ReadonlySet> | typeof Top, limit?: SetRangeLimit | number, setType?: typeof Set): SetRangeDomain { + if(concrete === Top) { + return SetRangeDomain.top(limit, setType); + } else if(concrete.size === 0) { + return SetRangeDomain.bottom(limit, setType); + } + const lower = concrete.values().reduce((result, set) => result.intersection(set)); + const upper = concrete.values().reduce((result, set) => result.union(set)); + + return new SetRangeDomain({ min: lower, range: upper.difference(lower) }, limit, setType); + } + + public top(): this & SetRangeDomain; + public top(): SetRangeDomain { + return SetRangeDomain.top(this.limit, this.setType); + } + + public bottom(): this & SetRangeDomain; + public bottom(): SetRangeDomain { + return SetRangeDomain.bottom(this.limit, this.setType); + } + + public equals(other: this): boolean { + if(this.value === other.value) { + return true; + } else if(this.value === Bottom || other.value === Bottom || !setEquals(this.value.min, other.value.min)) { + return false; + } else if(this.value.range === other.value.range) { + return true; + } + return this.value.range !== Top && other.value.range !== Top && setEquals(this.value.range, other.value.range); + } + + public leq(other: this): boolean { + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom) { + return true; + } else if(otherLower === Bottom || otherUpper === Bottom || !otherLower.isSubsetOf(thisLower)) { + return false; + } else if(otherUpper === Top) { + return true; + } + return thisUpper !== Top && thisUpper.isSubsetOf(otherUpper); + } + + public join(other: this): this; + public join(other: SetRangeLift | ArrayRangeValue): this; + public join(other: this | SetRangeLift | ArrayRangeValue): this { + other = other instanceof SetRangeDomain ? other : this.create(other); + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom) { + return this.create(other.value); + } else if(otherLower === Bottom || otherUpper === Bottom) { + return this.create(this.value); + } + const joinLower = thisLower.intersection(otherLower); + let joinUpper; + + if(thisUpper === Top || otherUpper === Top) { + joinUpper = Top; + } else { + joinUpper = thisUpper.union(otherUpper); + } + return this.create({ min: joinLower, range: joinUpper === Top ? Top : joinUpper.difference(joinLower) }); + } + + public meet(other: this): this; + public meet(other: SetRangeLift | ArrayRangeValue): this; + public meet(other: this | SetRangeLift | ArrayRangeValue): this { + other = other instanceof SetRangeDomain ? other : this.create(other); + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom || otherLower === Bottom || otherUpper === Bottom) { + return this.bottom(); + } + const meetLower = thisLower.union(otherLower); + let meetUpper; + + if(thisUpper === Top) { + meetUpper = otherUpper; + } else if(otherUpper === Top) { + meetUpper = thisUpper; + } else { + meetUpper = thisUpper.intersection(otherUpper); + } + if(meetUpper !== Top && !meetLower.isSubsetOf(meetUpper)) { + return this.bottom(); + } + return this.create({ min: meetLower, range: meetUpper === Top ? Top : meetUpper.difference(meetLower) }); + } + + /** + * Creates the union of this abstract value and another abstract value by creating the union of the minimum and maximum set, respectively. + */ + public union(other: this | SetRangeLift | ArrayRangeValue): this { + other = other instanceof SetRangeDomain ? other : this.create(other); + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom) { + return this.create(other.value); + } else if(otherLower === Bottom || otherUpper === Bottom) { + return this.create(this.value); + } + const unionLower = thisLower.union(otherLower); + let unionUpper; + + if(thisUpper === Top || otherUpper === Top) { + unionUpper = Top; + } else { + unionUpper = thisUpper.union(otherUpper); + } + return this.create({ min: unionLower, range: unionUpper === Top ? Top : unionUpper.difference(unionLower) }); + } + + /** + * Creates the intersection of this abstract value and another abstract value by creating the intersection of the minimum and maximum set, respectively. + */ + public intersect(other: this | SetRangeLift | ArrayRangeValue): this { + other = other instanceof SetRangeDomain ? other : this.create(other); + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom || otherLower === Bottom || otherUpper === Bottom) { + return this.bottom(); + } + const intersectLower = thisLower.intersection(otherLower); + let intersectUpper; + + if(thisUpper === Top) { + intersectUpper = otherUpper; + } else if(otherUpper === Top) { + intersectUpper = thisUpper; + } else { + intersectUpper = thisUpper.intersection(otherUpper); + } + return this.create({ min: intersectLower, range: intersectUpper === Top ? Top : intersectUpper.difference(intersectLower) }); + } + + /** + * Subtracts another abstract value from the current abstract value by removing all elements of the other abstract value from the current abstract value. + */ + public subtract(other: this | SetRangeLift | ArrayRangeValue): this { + other = other instanceof SetRangeDomain ? other : this.create(other); + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom) { + return this.bottom(); + } else if(otherLower === Bottom || otherUpper === Bottom) { + return this.create(this.value); + } + let subLower; + + if(otherUpper === Top) { + subLower = new Set(); + } else { + subLower = thisLower.difference(otherUpper); + } + let subUpper; + + if(thisUpper === Top) { + subUpper = Top; + } else if(otherUpper === Top) { + subUpper = thisUpper.difference(otherLower); + } else { + subUpper = thisUpper.difference(otherUpper); + } + return this.create({ min: subLower, range: subUpper === Top ? Top : subUpper.difference(subLower) }); + } + + public widen(other: this): this { + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom) { + return this.create(other.value); + } else if(otherLower === Bottom || otherUpper === Bottom) { + return this.create(this.value); + } + let widenLower; + + if(!thisLower.isSubsetOf(otherLower)) { + widenLower = new Set(); + } else { + widenLower = thisLower; + } + let widenUpper; + + if(thisUpper === Top || otherUpper === Top || !otherUpper.isSubsetOf(thisUpper)) { + widenUpper = Top; + } else { + widenUpper = thisUpper; + } + return this.create({ min: widenLower, range: widenUpper === Top ? Top : widenUpper.difference(widenLower) }); + } + + public narrow(other: this): this { + const thisLower = this.lower(), thisUpper = this.upper(); + const otherLower = other.lower(), otherUpper = other.upper(); + + if(thisLower === Bottom || thisUpper === Bottom || otherLower === Bottom || otherUpper === Bottom) { + return this.bottom(); + } + let meetUpper; + + if(thisUpper === Top) { + meetUpper = otherUpper; + } else if(otherUpper === Top) { + meetUpper = thisUpper; + } else { + meetUpper = thisUpper.intersection(otherUpper); + } + if(meetUpper !== Top && !thisLower.union(otherLower).isSubsetOf(meetUpper)) { + return this.bottom(); + } + let narrowLower; + + if(thisLower.size === 0) { + narrowLower = otherLower; + } else { + narrowLower = thisLower; + } + let narrowUpper; + + if(thisUpper === Top) { + narrowUpper = otherUpper; + } else { + narrowUpper = thisUpper; + } + return this.create({ min: narrowLower, range: narrowUpper === Top ? Top : narrowUpper.difference(narrowLower) }); + } + + public concretize(limit: number): ReadonlySet> | typeof Top { + if(this.value === Bottom) { + return new Set(); + } else if(this.value.range === Top || 2**(this.value.range.size) > limit) { + return Top; + } + const subsets = [new this.setType()]; + + for(const element of this.value.range) { + const newSubsets = subsets.map(subset => new this.setType([...subset, element])); + + for(const subset of newSubsets) { + subsets.push(subset); + } + } + return new Set(subsets.map(subset => this.value === Bottom ? subset : this.value.min.union(subset))); + } + + public abstract(concrete: ReadonlySet> | typeof Top): this; + public abstract(concrete: ReadonlySet> | typeof Top): SetRangeDomain { + return SetRangeDomain.abstract(concrete, this.limit); + } + + public satisfies(set: ReadonlySet | T[], comparator: SetComparator = SetComparator.Equal): Ternary { + const value = new this.setType(set); + const lower = this.lower(), upper = this.upper(); + + if(lower === Bottom || upper === Bottom) { + return Ternary.Never; + } + switch(comparator) { + case SetComparator.Equal: { + if(lower.isSubsetOf(value) && (upper === Top || value.isSubsetOf(upper))) { + return upper !== Top && lower.size === upper.size ? Ternary.Always : Ternary.Maybe; + } + return Ternary.Never; + } + case SetComparator.SubsetOrEqual: { + if(upper === Top || value.isSubsetOf(upper)) { + return value.isSubsetOf(lower) ? Ternary.Always : Ternary.Maybe; + } + return Ternary.Never; + } + case SetComparator.Subset: { + if(upper === Top || (value.isSubsetOf(upper) && !setEquals(value, upper))) { + return value.isSubsetOf(lower) && !setEquals(value, lower) ? Ternary.Always : Ternary.Maybe; + } + return Ternary.Never; + } + default: { + assertUnreachable(comparator); + } + } + } + + /** + * Extends the minimum set of the current abstract value down to the empty set. + */ + public widenDown(): this { + const upper = this.upper(); + + if(upper === Bottom) { + return this.bottom(); + } else { + return this.create({ min: new this.setType(), range: upper }); + } + } + + /** + * Extends the maximum set of the current abstract value up to {@link Top}. + */ + public widenUp(): this { + const lower = this.lower(); + + if(lower === Bottom) { + return this.bottom(); + } else { + return this.create({ min: lower, range: Top }); + } + } + + public toJson(): unknown { + if(this.value === Bottom) { + return this.value.description; + } + const min = this.value.min.values().toArray(); + const range = this.value.range === Top ? this.value.range.description : this.value.range.values().toArray(); + + return { min, range }; + } + + public toString(): string { + if(this.value === Bottom) { + return BottomSymbol; + } else if(this.value.range === Top) { + const minString = this.value.min.values().map(domainElementToString).toArray().join(', '); + + return `[{${minString}}, ${TopSymbol}]`; + } + const minString = this.value.min.values().map(domainElementToString).toArray().join(', '); + const rangeString = this.value.range.values().map(domainElementToString).toArray().join(', '); + + return `[{${minString}}, {${rangeString}}]`; + } + + public isTop(): this is SetRangeDomain { + return this.value !== Bottom && this.value.min.size === 0 && this.value.range === Top; + } + + public isBottom(): this is SetRangeDomain { + return this.value === Bottom; + } + + public isValue(): this is SetRangeDomain> { + return this.value !== Bottom; + } +} diff --git a/src/abstract-interpretation/domains/set-upper-bound-domain.ts b/src/abstract-interpretation/domains/set-upper-bound-domain.ts index 04f4fa86d15..b780884c72a 100644 --- a/src/abstract-interpretation/domains/set-upper-bound-domain.ts +++ b/src/abstract-interpretation/domains/set-upper-bound-domain.ts @@ -2,7 +2,7 @@ import { assertUnreachable } from '../../util/assert'; import { setEquals } from '../../util/collections/set'; import { Ternary } from '../../util/logic'; import { AbstractDomain, DEFAULT_INFERENCE_LIMIT, domainElementToString } from './abstract-domain'; -import { Bottom, Top } from './lattice'; +import { Bottom, BottomSymbol, Top, TopSymbol } from './lattice'; import { type SatisfiableDomain , SetComparator } from './satisfiable-domain'; /* eslint-disable @typescript-eslint/unified-signatures */ @@ -204,9 +204,9 @@ export class SetUpperBoundDomain = SetUppe public toString(): string { if(this.value === Top) { - return '⊤'; + return TopSymbol; } else if(this.value === Bottom) { - return '⊥'; + return BottomSymbol; } const string = this.value.values().map(domainElementToString).toArray().join(', '); diff --git a/src/abstract-interpretation/domains/singleton-domain.ts b/src/abstract-interpretation/domains/singleton-domain.ts index 33394b21b3c..247c407671e 100644 --- a/src/abstract-interpretation/domains/singleton-domain.ts +++ b/src/abstract-interpretation/domains/singleton-domain.ts @@ -1,6 +1,6 @@ import { Ternary } from '../../util/logic'; import { AbstractDomain, domainElementToString } from './abstract-domain'; -import { Bottom, Top } from './lattice'; +import { Bottom, BottomSymbol, Top, TopSymbol } from './lattice'; import type { SatisfiableDomain } from './satisfiable-domain'; /* eslint-disable @typescript-eslint/unified-signatures */ @@ -137,9 +137,9 @@ export class SingletonDomain = SingletonLift(value: SetRangeDomain | PosIntervalDomain): number { + if(value.isValue()) { + if(value instanceof SetRangeDomain) { + return value.value.range === Top ? Infinity : value.value.range.size; + } else { + return value.value[1] - value.value[0]; + } + } + return 0; + } + + private getInferredNumber(value: SetRangeDomain | PosIntervalDomain): number | 'bottom' | 'infinite' | 'top' { if(value.isTop()) { return 'top'; - } else if(value.isValue() && !isFinite(value.value[1])) { - return 'infinite'; } else if(value.isValue()) { - return Math.floor((value.value[0] + value.value[1]) / 2); + if(value instanceof SetRangeDomain) { + if(value.value.range === Top) { + return 'infinite'; + } + return Math.floor(value.value.min.size + (value.value.range.size / 2)); + } else { + if(!isFinite(value.value[1])) { + return 'infinite'; + } + return Math.floor((value.value[0] + value.value[1]) / 2); + } } return 'bottom'; } diff --git a/src/benchmark/stats/print.ts b/src/benchmark/stats/print.ts index 08827f81a50..1d1bd869dbf 100644 --- a/src/benchmark/stats/print.ts +++ b/src/benchmark/stats/print.ts @@ -195,15 +195,16 @@ Dataframe shape inference: Number of total top: ${pad(stats.dataFrameShape.numberOfTotalTop)} Inferred column names per node: ${pad(stats.dataFrameShape.inferredColNames.mean)} Number of column names values: ${pad(stats.dataFrameShape.numberOfColNamesValues)} - Number of column names Top: ${pad(stats.dataFrameShape.numberOfColNamesTop)} + Number of column names infinite:${pad(stats.dataFrameShape.numberOfColNamesInfinite)} + Number of column names top: ${pad(stats.dataFrameShape.numberOfColNamesTop)} Inferred column count per node: ${pad(stats.dataFrameShape.inferredColCount.mean)} Number of column count values: ${pad(stats.dataFrameShape.numberOfColCountValues)} - Number of column count Top: ${pad(stats.dataFrameShape.numberOfColCountTop)} Number of column count infinite:${pad(stats.dataFrameShape.numberOfColCountInfinite)} + Number of column count top: ${pad(stats.dataFrameShape.numberOfColCountTop)} Inferred row count per node: ${pad(stats.dataFrameShape.inferredRowCount.mean)} Number of row count values: ${pad(stats.dataFrameShape.numberOfRowCountValues)} - Number of row count Top: ${pad(stats.dataFrameShape.numberOfRowCountTop)} Number of row count infinite: ${pad(stats.dataFrameShape.numberOfRowCountInfinite)} + Number of row count top: ${pad(stats.dataFrameShape.numberOfRowCountTop)} Size of data frame shape info: ${convertNumberToNiceBytes(stats.dataFrameShape.sizeOfInfo)}`; } @@ -301,18 +302,20 @@ Dataframe shape inference: Number of total values: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfTotalValues)} Number of total top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfTotalTop)} Inferred column names per node: ${formatSummarizedMeasure(stats.dataFrameShape.inferredColNames)} + Number of column names exact: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColNamesExact)} Number of column names values: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColNamesValues)} + Number of column names infinite:${formatSummarizedMeasure(stats.dataFrameShape.numberOfColNamesInfinite)} Number of column names top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColNamesTop)} Inferred column count per node: ${formatSummarizedMeasure(stats.dataFrameShape.inferredColCount)} Number of column count exact: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColCountExact)} Number of column count values: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColCountValues)} - Number of column count top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColCountTop)} Number of column count infinite:${formatSummarizedMeasure(stats.dataFrameShape.numberOfColCountInfinite)} + Number of column count top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfColCountTop)} Inferred row count per node: ${formatSummarizedMeasure(stats.dataFrameShape.inferredRowCount)} Number of row count exact: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfRowCountExact)} Number of row count values: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfRowCountValues)} - Number of row count top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfRowCountTop)} Number of row count infinite: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfRowCountInfinite)} + Number of row count top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfRowCountTop)} Size of data frame shape info: ${formatSummarizedMeasure(stats.dataFrameShape.sizeOfInfo, convertNumberToNiceBytes)}`; } diff --git a/src/benchmark/stats/stats.ts b/src/benchmark/stats/stats.ts index facb7356491..77b24293c31 100644 --- a/src/benchmark/stats/stats.ts +++ b/src/benchmark/stats/stats.ts @@ -55,8 +55,8 @@ export interface SlicerStatsDfShape { numberOfNonDataFrameFiles: T extends number ? 0 | 1 : number, numberOfResultConstraints: T, numberOfResultingValues: T, - numberOfResultingTop: T, numberOfResultingBottom: T, + numberOfResultingTop: T, numberOfEmptyNodes: T, numberOfOperationNodes: T, numberOfValueNodes: T, @@ -67,10 +67,11 @@ export interface SlicerStatsDfShape { export interface PerNodeStatsDfShape { numberOfEntries: T, mappedOperations?: DataFrameOperationName[] - inferredColNames?: T | 'bottom' | 'top', + inferredColNames?: T | 'bottom' | 'infinite' | 'top', inferredColCount?: T | 'bottom' | 'infinite' | 'top', inferredRowCount?: T | 'bottom' | 'infinite' | 'top', /** difference between upper and lower bound of interval domain (to estimate approximation) */ + approxRangeColNames?: T, approxRangeColCount?: T, approxRangeRowCount?: T } diff --git a/src/benchmark/summarizer/data.ts b/src/benchmark/summarizer/data.ts index 1b53040d0ed..b2e7ca69f71 100644 --- a/src/benchmark/summarizer/data.ts +++ b/src/benchmark/summarizer/data.ts @@ -99,25 +99,28 @@ export interface SummarizedDfShapeStats extends Omit } diff --git a/src/benchmark/summarizer/first-phase/process.ts b/src/benchmark/summarizer/first-phase/process.ts index 6e627a277ae..66394256343 100644 --- a/src/benchmark/summarizer/first-phase/process.ts +++ b/src/benchmark/summarizer/first-phase/process.ts @@ -250,26 +250,29 @@ function summarizeDfShapeStats({ perNodeStats, ...stats }: SlicerStatsDfShape): numberOfEntriesPerNode: summarizeMeasurement(nodeStats.map(s => s.numberOfEntries)), numberOfOperations: arraySum(nodeStats.map(s => s.mappedOperations?.length).filter(isNotUndefined)), numberOfTotalValues: nodeStats.filter(s => isValue(s.inferredColNames) && isValue(s.inferredColCount) && isValue(s.inferredRowCount)).length, - numberOfTotalTop: nodeStats.filter(s => isTop(s.inferredColNames) && isTop(s.inferredColCount) && isTop(s.inferredRowCount)).length, numberOfTotalBottom: nodeStats.filter(s => s.inferredColNames === 0 && isBottom(s.inferredColCount) && isBottom(s.inferredRowCount)).length, + numberOfTotalTop: nodeStats.filter(s => isTop(s.inferredColNames) && isTop(s.inferredColCount) && isTop(s.inferredRowCount)).length, inferredColNames: summarizeMeasurement(nodeStats.map(s => s.inferredColNames).filter(isValue)), + approxRangeColNames: summarizeMeasurement(nodeStats.map(s => s.approxRangeColNames).filter(isNotUndefined).filter(isFinite)), + numberOfColNamesExact: nodeStats.map(s => s.approxRangeColNames).filter(range => range === 0).length, numberOfColNamesValues: nodeStats.map(s => s.inferredColNames).filter(isValue).length, + numberOfColNamesBottom: nodeStats.map(s => s.inferredColNames).filter(isBottom).length, + numberOfColNamesInfinite: nodeStats.map(s => s.inferredColNames).filter(isInfinite).length, numberOfColNamesTop: nodeStats.map(s => s.inferredColNames).filter(isTop).length, - numberOfColNamesBottom: nodeStats.map(s => s.inferredColNames).filter(number => number === 0).length, inferredColCount: summarizeMeasurement(nodeStats.map(s => s.inferredColCount).filter(isValue)), + approxRangeColCount: summarizeMeasurement(nodeStats.map(s => s.approxRangeColCount).filter(isNotUndefined).filter(isFinite)), numberOfColCountExact: nodeStats.map(s => s.approxRangeColCount).filter(range => range === 0).length, numberOfColCountValues: nodeStats.map(s => s.inferredColCount).filter(isValue).length, - numberOfColCountTop: nodeStats.map(s => s.inferredColCount).filter(isTop).length, - numberOfColCountInfinite: nodeStats.map(s => s.inferredColCount).filter(isInfinite).length, numberOfColCountBottom: nodeStats.map(s => s.inferredColCount).filter(isBottom).length, - approxRangeColCount: summarizeMeasurement(nodeStats.map(s => s.approxRangeColCount).filter(isNotUndefined).filter(isFinite)), + numberOfColCountInfinite: nodeStats.map(s => s.inferredColCount).filter(isInfinite).length, + numberOfColCountTop: nodeStats.map(s => s.inferredColCount).filter(isTop).length, inferredRowCount: summarizeMeasurement(nodeStats.map(s => s.inferredRowCount).filter(isValue)), + approxRangeRowCount: summarizeMeasurement(nodeStats.map(s => s.approxRangeRowCount).filter(isNotUndefined).filter(isFinite)), numberOfRowCountExact: nodeStats.map(s => s.approxRangeRowCount).filter(range => range === 0).length, numberOfRowCountValues: nodeStats.map(s => s.inferredRowCount).filter(isValue).length, - numberOfRowCountTop: nodeStats.map(s => s.inferredRowCount).filter(isTop).length, - numberOfRowCountInfinite: nodeStats.map(s => s.inferredRowCount).filter(isInfinite).length, numberOfRowCountBottom: nodeStats.map(s => s.inferredRowCount).filter(isBottom).length, - approxRangeRowCount: summarizeMeasurement(nodeStats.map(s => s.approxRangeRowCount).filter(isNotUndefined).filter(isFinite)), + numberOfRowCountInfinite: nodeStats.map(s => s.inferredRowCount).filter(isInfinite).length, + numberOfRowCountTop: nodeStats.map(s => s.inferredRowCount).filter(isTop).length, perOperationNumber: summarizePerOperationStats(nodeStats), }; } diff --git a/src/benchmark/summarizer/second-phase/process.ts b/src/benchmark/summarizer/second-phase/process.ts index 6688bd60145..a718857e10c 100644 --- a/src/benchmark/summarizer/second-phase/process.ts +++ b/src/benchmark/summarizer/second-phase/process.ts @@ -125,8 +125,8 @@ export function summarizeAllSummarizedStats(stats: SummarizedSlicerStats[]): Ult numberOfNonDataFrameFiles: arraySum(stats.map(s => s.dataFrameShape?.numberOfNonDataFrameFiles).filter(isNotUndefined)), numberOfResultConstraints: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultConstraints).filter(isNotUndefined)), numberOfResultingValues: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingValues).filter(isNotUndefined)), - numberOfResultingTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingTop).filter(isNotUndefined)), numberOfResultingBottom: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingBottom).filter(isNotUndefined)), + numberOfResultingTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingTop).filter(isNotUndefined)), numberOfEmptyNodes: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfEmptyNodes).filter(isNotUndefined)), numberOfOperationNodes: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfOperationNodes).filter(isNotUndefined)), numberOfValueNodes: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfValueNodes).filter(isNotUndefined)), @@ -134,26 +134,29 @@ export function summarizeAllSummarizedStats(stats: SummarizedSlicerStats[]): Ult numberOfEntriesPerNode: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfEntriesPerNode).filter(isNotUndefined)), numberOfOperations: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfOperations).filter(isNotUndefined)), numberOfTotalValues: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalValues).filter(isNotUndefined)), - numberOfTotalTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(isNotUndefined)), numberOfTotalBottom: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalBottom).filter(isNotUndefined)), + numberOfTotalTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(isNotUndefined)), inferredColNames: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.inferredColNames).filter(isNotUndefined)), + approxRangeColNames: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeColNames).filter(isNotUndefined)), + numberOfColNamesExact: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesExact).filter(isNotUndefined)), numberOfColNamesValues: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesValues).filter(isNotUndefined)), - numberOfColNamesTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesTop).filter(isNotUndefined)), numberOfColNamesBottom: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesBottom).filter(isNotUndefined)), + numberOfColNamesInfinite: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesInfinite).filter(isNotUndefined)), + numberOfColNamesTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesTop).filter(isNotUndefined)), inferredColCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.inferredColCount).filter(isNotUndefined)), + approxRangeColCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeColCount).filter(isNotUndefined)), numberOfColCountExact: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountExact).filter(isNotUndefined)), numberOfColCountValues: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountValues).filter(isNotUndefined)), - numberOfColCountTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountTop).filter(isNotUndefined)), - numberOfColCountInfinite: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountInfinite).filter(isNotUndefined)), numberOfColCountBottom: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountBottom).filter(isNotUndefined)), - approxRangeColCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeColCount).filter(isNotUndefined)), + numberOfColCountInfinite: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountInfinite).filter(isNotUndefined)), + numberOfColCountTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountTop).filter(isNotUndefined)), inferredRowCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.inferredRowCount).filter(isNotUndefined)), + approxRangeRowCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeRowCount).filter(isNotUndefined)), numberOfRowCountExact: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountExact).filter(isNotUndefined)), numberOfRowCountValues: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountValues).filter(isNotUndefined)), - numberOfRowCountTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountTop).filter(isNotUndefined)), - numberOfRowCountInfinite: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountInfinite).filter(isNotUndefined)), numberOfRowCountBottom: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountBottom).filter(isNotUndefined)), - approxRangeRowCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeRowCount).filter(isNotUndefined)), + numberOfRowCountInfinite: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountInfinite).filter(isNotUndefined)), + numberOfRowCountTop: summarizeMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountTop).filter(isNotUndefined)), perOperationNumber: new Map(DataFrameOperationNames.map(n => [n, summarizeMeasurement(stats.map(s => s.dataFrameShape?.perOperationNumber.get(n) ?? 0))])) } : undefined }; @@ -210,8 +213,8 @@ export function summarizeAllUltimateStats(stats: UltimateSlicerStats[]): Ultimat numberOfNonDataFrameFiles: arraySum(stats.map(s => s.dataFrameShape?.numberOfNonDataFrameFiles).filter(isNotUndefined)), numberOfResultConstraints: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultConstraints).filter(isNotUndefined)), numberOfResultingValues: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingValues).filter(isNotUndefined)), - numberOfResultingTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingTop).filter(isNotUndefined)), numberOfResultingBottom: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingBottom).filter(isNotUndefined)), + numberOfResultingTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfResultingTop).filter(isNotUndefined)), numberOfEmptyNodes: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfEmptyNodes).filter(isNotUndefined)), numberOfOperationNodes: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfOperationNodes).filter(isNotUndefined)), numberOfValueNodes: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfValueNodes).filter(isNotUndefined)), @@ -219,26 +222,29 @@ export function summarizeAllUltimateStats(stats: UltimateSlicerStats[]): Ultimat numberOfEntriesPerNode: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfEntriesPerNode).filter(isNotUndefined)), numberOfOperations: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfOperations).filter(isNotUndefined)), numberOfTotalValues: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalValues).filter(isNotUndefined)), - numberOfTotalTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(isNotUndefined)), numberOfTotalBottom: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalBottom).filter(isNotUndefined)), + numberOfTotalTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(isNotUndefined)), inferredColNames: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.inferredColNames).filter(isNotUndefined)), + approxRangeColNames: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeColNames).filter(isNotUndefined)), + numberOfColNamesExact: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesExact).filter(isNotUndefined)), numberOfColNamesValues: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesValues).filter(isNotUndefined)), - numberOfColNamesTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesTop).filter(isNotUndefined)), numberOfColNamesBottom: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesBottom).filter(isNotUndefined)), + numberOfColNamesInfinite: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesInfinite).filter(isNotUndefined)), + numberOfColNamesTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColNamesTop).filter(isNotUndefined)), inferredColCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.inferredColCount).filter(isNotUndefined)), + approxRangeColCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeColCount).filter(isNotUndefined)), numberOfColCountExact: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountExact).filter(isNotUndefined)), numberOfColCountValues: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountValues).filter(isNotUndefined)), - numberOfColCountTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountTop).filter(isNotUndefined)), - numberOfColCountInfinite: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountInfinite).filter(isNotUndefined)), numberOfColCountBottom: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountBottom).filter(isNotUndefined)), - approxRangeColCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeColCount).filter(isNotUndefined)), + numberOfColCountInfinite: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountInfinite).filter(isNotUndefined)), + numberOfColCountTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfColCountTop).filter(isNotUndefined)), inferredRowCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.inferredRowCount).filter(isNotUndefined)), + approxRangeRowCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeRowCount).filter(isNotUndefined)), numberOfRowCountExact: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountExact).filter(isNotUndefined)), numberOfRowCountValues: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountValues).filter(isNotUndefined)), - numberOfRowCountTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountTop).filter(isNotUndefined)), - numberOfRowCountInfinite: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountInfinite).filter(isNotUndefined)), numberOfRowCountBottom: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountBottom).filter(isNotUndefined)), - approxRangeRowCount: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.approxRangeRowCount).filter(isNotUndefined)), + numberOfRowCountInfinite: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountInfinite).filter(isNotUndefined)), + numberOfRowCountTop: summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.numberOfRowCountTop).filter(isNotUndefined)), perOperationNumber: new Map(DataFrameOperationNames.map(n => [n, summarizeSummarizedMeasurement(stats.map(s => s.dataFrameShape?.perOperationNumber.get(n)).filter(isNotUndefined))])) } : undefined }; diff --git a/src/queries/catalog/df-shape-query/df-shape-query-executor.ts b/src/queries/catalog/df-shape-query/df-shape-query-executor.ts index d91e5abe01a..28dd05e108e 100644 --- a/src/queries/catalog/df-shape-query/df-shape-query-executor.ts +++ b/src/queries/catalog/df-shape-query/df-shape-query-executor.ts @@ -1,12 +1,12 @@ import type { DataFrameDomain } from '../../../abstract-interpretation/data-frame/dataframe-domain'; import { inferDataFrameShapes, resolveIdToDataFrameShape } from '../../../abstract-interpretation/data-frame/shape-inference'; -import { type SingleSlicingCriterion , slicingCriterionToId } from '../../../slicing/criterion/parse'; +import { type SingleSlicingCriterion, slicingCriterionToId } from '../../../slicing/criterion/parse'; import { log } from '../../../util/log'; import type { BasicQueryData } from '../../base-query-format'; import type { DfShapeQuery, DfShapeQueryResult } from './df-shape-query-format'; /** - * Executes the given dataframe shape queries using the provided analyzer. + * Executes the given data frame shape queries using the provided analyzer. */ export async function executeDfShapeQuery({ analyzer }: BasicQueryData, queries: readonly DfShapeQuery[]): Promise { if(queries.length !== 1 && queries.some(query => query.criterion === undefined)) { diff --git a/src/queries/catalog/df-shape-query/df-shape-query-format.ts b/src/queries/catalog/df-shape-query/df-shape-query-format.ts index 9b77d304c35..fb3435cb91a 100644 --- a/src/queries/catalog/df-shape-query/df-shape-query-format.ts +++ b/src/queries/catalog/df-shape-query/df-shape-query-format.ts @@ -1,14 +1,14 @@ -import { type DataFrameDomain , DataFrameStateDomain } from '../../../abstract-interpretation/data-frame/dataframe-domain'; +import Joi from 'joi'; +import { type DataFrameDomain, DataFrameStateDomain } from '../../../abstract-interpretation/data-frame/dataframe-domain'; +import type { ReplOutput } from '../../../cli/repl/commands/repl-main'; +import { sliceCriterionParser } from '../../../cli/repl/parser/slice-query-parser'; +import type { FlowrConfigOptions } from '../../../config'; +import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse'; import { bold } from '../../../util/text/ansi'; import { printAsMs } from '../../../util/text/time'; import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format'; import type { ParsedQueryLine, QueryResults, SupportedQuery } from '../../query'; import { executeDfShapeQuery } from './df-shape-query-executor'; -import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse'; -import type { ReplOutput } from '../../../cli/repl/commands/repl-main'; -import type { FlowrConfigOptions } from '../../../config'; -import { sliceCriterionParser } from '../../../cli/repl/parser/slice-query-parser'; -import Joi from 'joi'; /** Infer the shape of data frames using abstract interpretation. */ export interface DfShapeQuery extends BaseQueryFormat { diff --git a/test/functionality/abstract-interpretation/data-frame/data-frame.ts b/test/functionality/abstract-interpretation/data-frame/data-frame.ts index 840eed2e2e7..97973e2a85a 100644 --- a/test/functionality/abstract-interpretation/data-frame/data-frame.ts +++ b/test/functionality/abstract-interpretation/data-frame/data-frame.ts @@ -1,14 +1,17 @@ import { assert, beforeAll, test } from 'vitest'; -import { hasDataFrameExpressionInfo, type AbstractInterpretationInfo, type DataFrameOperation } from '../../../../src/abstract-interpretation/data-frame/absint-info'; +import { type AbstractInterpretationInfo, type DataFrameOperation, hasDataFrameExpressionInfo } from '../../../../src/abstract-interpretation/data-frame/absint-info'; import type { AbstractDataFrameShape, DataFrameDomain, DataFrameShapeProperty } from '../../../../src/abstract-interpretation/data-frame/dataframe-domain'; import type { DataFrameOperationArgs, DataFrameOperationName } from '../../../../src/abstract-interpretation/data-frame/semantics'; import { inferDataFrameShapes, resolveIdToDataFrameShape } from '../../../../src/abstract-interpretation/data-frame/shape-inference'; import type { AnyAbstractDomain } from '../../../../src/abstract-interpretation/domains/abstract-domain'; import { Bottom, Top } from '../../../../src/abstract-interpretation/domains/lattice'; -import { type FlowrConfigOptions , defaultConfigOptions } from '../../../../src/config'; +import type { ArrayRangeValue } from '../../../../src/abstract-interpretation/domains/set-range-domain'; +import { type FlowrConfigOptions, defaultConfigOptions } from '../../../../src/config'; import { extractCfg } from '../../../../src/control-flow/extract-cfg'; -import { type DEFAULT_DATAFLOW_PIPELINE, type TREE_SITTER_DATAFLOW_PIPELINE , createDataflowPipeline } from '../../../../src/core/steps/pipeline/default-pipelines'; +import { type DEFAULT_DATAFLOW_PIPELINE, type TREE_SITTER_DATAFLOW_PIPELINE, createDataflowPipeline } from '../../../../src/core/steps/pipeline/default-pipelines'; import type { PipelineOutput } from '../../../../src/core/steps/pipeline/pipeline'; +import { type FlowrAnalyzerContext, type ReadOnlyFlowrAnalyzerContext, contextFromInput } from '../../../../src/project/context/flowr-analyzer-context'; +import type { FlowrFileProvider } from '../../../../src/project/context/flowr-file'; import type { RNode } from '../../../../src/r-bridge/lang-4.x/ast/model/model'; import type { RSymbol } from '../../../../src/r-bridge/lang-4.x/ast/model/nodes/r-symbol'; import type { ParentInformation } from '../../../../src/r-bridge/lang-4.x/ast/model/processing/decorate'; @@ -16,16 +19,11 @@ import { RoleInParent } from '../../../../src/r-bridge/lang-4.x/ast/model/proces import { RType } from '../../../../src/r-bridge/lang-4.x/ast/model/type'; import type { KnownParser } from '../../../../src/r-bridge/parser'; import type { RShell } from '../../../../src/r-bridge/shell'; -import { type SingleSlicingCriterion , slicingCriterionToId } from '../../../../src/slicing/criterion/parse'; +import { type SingleSlicingCriterion, slicingCriterionToId } from '../../../../src/slicing/criterion/parse'; import { assertUnreachable, guard, isNotUndefined } from '../../../../src/util/assert'; import { getRangeEnd } from '../../../../src/util/range'; -import { decorateLabelContext, type TestLabel } from '../../_helper/label'; -import { type TestConfiguration , skipTestBecauseConfigNotMet } from '../../_helper/shell'; -import { - type FlowrAnalyzerContext, - type ReadOnlyFlowrAnalyzerContext - , contextFromInput } from '../../../../src/project/context/flowr-analyzer-context'; -import type { FlowrFileProvider } from '../../../../src/project/context/flowr-file'; +import { type TestLabel, decorateLabelContext } from '../../_helper/label'; +import { type TestConfiguration, skipTestBecauseConfigNotMet } from '../../_helper/shell'; /** * The default flowR configuration options for performing abstract interpretation. @@ -64,18 +62,11 @@ export const DataFrameShapeOverapproximation: DataFrameShapeMatching = { rows: DomainMatchingType.Overapproximation }; -/** - * Data frame shape matching options defining that the inferred columns names should be an over-approximation of the actual value. - */ -export const ColNamesOverapproximation: Partial = { - colnames: DomainMatchingType.Overapproximation -}; - /** * The expected data frame shape for data frame shape assertion tests. */ export interface ExpectedDataFrameShape { - colnames: Exclude, ReadonlySet> | string[], + colnames: [min: string[], range: string[] | typeof Top] | typeof Bottom, cols: DataFrameShapeProperty<'cols'>, rows: DataFrameShapeProperty<'rows'> } @@ -308,7 +299,7 @@ function assertDomainMatches( assert.ok(inferred === undefined || expected !== undefined, `result is no over-approximation: expected ${inferred?.toString()} to be an over-approximation of ${JSON.stringify(expected)}`); } if(inferred !== undefined && expected !== undefined) { - assertPropertyMatches('colnames', inferred.colnames, inferred.colnames.create(expected.colnames), matching.colnames); + assertPropertyMatches('colnames', inferred.colnames, inferred.colnames.create(createSetRange(expected.colnames)), matching.colnames); assertPropertyMatches('cols', inferred.cols, inferred.cols.create(expected.cols), matching.cols); assertPropertyMatches('rows', inferred.rows, inferred.rows.create(expected.rows), matching.rows); } @@ -338,12 +329,20 @@ function createCodeForOutput( return `cat(sprintf("${marker} %s,%s,%s,%s\\n", is.data.frame(${symbol}), paste(names(${symbol}), collapse = ";"), paste(ncol(${symbol}), collapse = ""), paste(nrow(${symbol}), collapse = "")))`; } +function createSetRange(value: [string[], string[] | typeof Top] | typeof Bottom): ArrayRangeValue | typeof Bottom { + return value === Bottom ? value : { min: value[0], range: value[1] === Top ? Top : value[1] }; +} + function getDefaultMatchingType(expected: ExpectedDataFrameShape | undefined, matching?: Partial): Partial { const matchingType: Partial = { ...matching }; if(expected !== undefined) { - if(matching?.colnames === undefined && expected.colnames === Top) { - matchingType.colnames = DomainMatchingType.Overapproximation; + if(matching?.colnames === undefined) { + if(expected.colnames === Bottom || (expected.colnames[1] !== Top && expected.colnames[1].length === 0)) { + matchingType.colnames = DomainMatchingType.Exact; + } else { + matchingType.colnames = DomainMatchingType.Overapproximation; + } } if(matching?.cols === undefined) { if(expected.cols === Bottom || expected.cols[0] === expected.cols[1]) { @@ -422,7 +421,7 @@ function getRealDomainFromOutput( const cols = Number.parseInt(result[3]); const rows = Number.parseInt(result[4]); - return dataFrame ? { colnames: colnames, cols: [cols, cols], rows: [rows, rows] } : undefined; + return dataFrame ? { colnames: [colnames, []], cols: [cols, cols], rows: [rows, rows] } : undefined; } return undefined; } @@ -436,18 +435,20 @@ function guardValidCriteria( ): void { for(const [criterion, domain, matching] of criteria) { if(domain !== undefined) { - if(domain.colnames === Top) { - guard(matching?.colnames === DomainMatchingType.Overapproximation, `Domain matching type for column names of "${criterion}" must be \`Overapproximation\` if expected column names are ${domain.colnames.toString()}`); + if(domain.colnames !== Bottom && (domain.colnames[1] === Top || domain.colnames[1].length > 0)) { + guard(matching?.colnames === DomainMatchingType.Overapproximation, `Domain matching type for column names of "${criterion}" must be \`Overapproximation\` if expected column names have a non-empty range set ${JSON.stringify(domain.colnames)}`); + } else { + guard((matching?.colnames ?? DomainMatchingType.Exact) === DomainMatchingType.Exact, `Domain matching type for column names of "${criterion}" must be \`Exact\` if expected column names have an empty range set ${JSON.stringify(domain.colnames)}`); } if(domain.cols !== Bottom && domain.cols[0] !== domain.cols[1]) { - guard(matching?.cols === DomainMatchingType.Overapproximation, `Domain matching type for number of columns of "${criterion}" must be \`Overapproximation\` if expected interval has more than 1 element ${domain.cols.toString()}`); + guard(matching?.cols === DomainMatchingType.Overapproximation, `Domain matching type for number of columns of "${criterion}" must be \`Overapproximation\` if expected interval has more than 1 element ${JSON.stringify(domain.cols)}`); } else { - guard((matching?.cols ?? DomainMatchingType.Exact) === DomainMatchingType.Exact, `Domain matching type for number of columns of "${criterion}" must be \`Exact\` if expected interval has only 1 element ${domain.cols.toString()}`); + guard((matching?.cols ?? DomainMatchingType.Exact) === DomainMatchingType.Exact, `Domain matching type for number of columns of "${criterion}" must be \`Exact\` if expected interval has only 1 element ${JSON.stringify(domain.cols)}`); } if(domain.rows !== Bottom && domain.rows[0] !== domain.rows[1]) { - guard(matching?.rows === DomainMatchingType.Overapproximation, `Domain matching type for number of rows of "${criterion}" must be \`Overapproximation\` if expected interval has more than 1 element ${domain.rows.toString()}`); + guard(matching?.rows === DomainMatchingType.Overapproximation, `Domain matching type for number of rows of "${criterion}" must be \`Overapproximation\` if expected interval has more than 1 element ${JSON.stringify(domain.rows)}`); } else { - guard((matching?.rows ?? DomainMatchingType.Exact) === DomainMatchingType.Exact, `Domain matching type for number of rows of "${criterion}" must be \`Exact\` if expected interval has only 1 element ${domain.rows.toString()}`); + guard((matching?.rows ?? DomainMatchingType.Exact) === DomainMatchingType.Exact, `Domain matching type for number of rows of "${criterion}" must be \`Exact\` if expected interval has only 1 element ${JSON.stringify(domain.rows)}`); } } } diff --git a/test/functionality/abstract-interpretation/data-frame/dataframe-domain.test.ts b/test/functionality/abstract-interpretation/data-frame/dataframe-domain.test.ts index d325e5c8401..bb072cdd090 100644 --- a/test/functionality/abstract-interpretation/data-frame/dataframe-domain.test.ts +++ b/test/functionality/abstract-interpretation/data-frame/dataframe-domain.test.ts @@ -4,14 +4,14 @@ import { DEFAULT_INFERENCE_LIMIT } from '../../../../src/abstract-interpretation import { Bottom, Top } from '../../../../src/abstract-interpretation/domains/lattice'; import { PosIntervalDomain, PosIntervalTop } from '../../../../src/abstract-interpretation/domains/positive-interval-domain'; import type { ConcreteProduct } from '../../../../src/abstract-interpretation/domains/product-domain'; -import { SetUpperBoundDomain } from '../../../../src/abstract-interpretation/domains/set-upper-bound-domain'; +import { SetRangeDomain } from '../../../../src/abstract-interpretation/domains/set-range-domain'; import type { NodeId } from '../../../../src/r-bridge/lang-4.x/ast/model/processing/node-id'; import { assertAbstractDomain } from '../domains/domain'; import type { ExpectedDataFrameShape } from './data-frame'; describe('Data Frame Domains', () => { const createDomain = ({ colnames, cols, rows }: ExpectedDataFrameShape) => new DataFrameDomain({ - colnames: new SetUpperBoundDomain(colnames), + colnames: new SetRangeDomain(colnames === Bottom ? colnames : { min: colnames[0], range: colnames[1] === Top ? Top : colnames[1] }), cols: new PosIntervalDomain(cols), rows: new PosIntervalDomain(rows) }); @@ -20,18 +20,18 @@ describe('Data Frame Domains', () => { new DataFrameStateDomain(new Map(state.map(([id, value]) => [id, createDomain(value)]))); const DataFrameBottom = { colnames: Bottom, cols: Bottom, rows: Bottom } satisfies ExpectedDataFrameShape; - const DataFrameTop = { colnames: Top, cols: PosIntervalTop, rows: PosIntervalTop } satisfies ExpectedDataFrameShape; - const DataFrameEmpty = { colnames: [], cols: [0, 0], rows: [0,0] } satisfies ExpectedDataFrameShape; + const DataFrameTop = { colnames: [[], Top], cols: PosIntervalTop, rows: PosIntervalTop } satisfies ExpectedDataFrameShape; + const DataFrameEmpty = { colnames: [[], []], cols: [0, 0], rows: [0,0] } satisfies ExpectedDataFrameShape; - const domain1 = { colnames: ['id', 'name', 'age'], cols: [3, 5], rows: [5, 5] } satisfies ExpectedDataFrameShape; - const domain2 = { colnames: ['id', 'category'], cols: [2, 2], rows: [0, 6] } satisfies ExpectedDataFrameShape; + const domain1 = { colnames: [['id', 'name'], ['age']], cols: [3, 5], rows: [5, 5] } satisfies ExpectedDataFrameShape; + const domain2 = { colnames: [['id', 'category'], []], cols: [2, 2], rows: [0, 6] } satisfies ExpectedDataFrameShape; - const join = { colnames: ['id', 'name', 'age', 'category'], cols: [2, 5], rows: [0, 6] } satisfies ExpectedDataFrameShape; - const meet = { colnames: ['id'], cols: Bottom, rows: [5, 5] } satisfies ExpectedDataFrameShape; - const widen1 = { colnames: Top, cols: [0, 5], rows: PosIntervalTop } satisfies ExpectedDataFrameShape; - const narrow1 = { colnames: ['id', 'name', 'age'], cols: Bottom, rows: [5, 5] } satisfies ExpectedDataFrameShape; - const widen2 = { colnames: Top, cols: [2, +Infinity], rows: [0, 6] } satisfies ExpectedDataFrameShape; - const narrow2 = { colnames: ['id', 'category'], cols: Bottom, rows: [5, 6] } satisfies ExpectedDataFrameShape; + const join = { colnames: [['id'], ['name', 'age', 'category']], cols: [2, 5], rows: [0, 6] } satisfies ExpectedDataFrameShape; + const meet = { colnames: Bottom, cols: Bottom, rows: [5, 5] } satisfies ExpectedDataFrameShape; + const widen1 = { colnames: [[], Top], cols: [0, 5], rows: PosIntervalTop } satisfies ExpectedDataFrameShape; + const narrow1 = { colnames: Bottom, cols: Bottom, rows: [5, 5] } satisfies ExpectedDataFrameShape; + const widen2 = { colnames: [[], Top], cols: [2, +Infinity], rows: [0, 6] } satisfies ExpectedDataFrameShape; + const narrow2 = { colnames: Bottom, cols: Bottom, rows: [5, 6] } satisfies ExpectedDataFrameShape; const concrete1 = [...createDomain(domain1).concretize(DEFAULT_INFERENCE_LIMIT) as ReadonlySet>]; const concrete2 = [...createDomain(domain2).concretize(DEFAULT_INFERENCE_LIMIT) as ReadonlySet>]; @@ -65,11 +65,11 @@ describe('Data Frame Domains', () => { assertAbstractDomain(create, domain1, domain1, { equal: true, leq: true, join: domain1, meet: domain1, widen: domain1, narrow: domain1, concrete: concrete1 }); - assertAbstractDomain(create, domain1, { ...domain1, colnames: Top }, { - equal: false, leq: true, join: { ...domain1, colnames: Top }, meet: domain1, widen: { ...domain1, colnames: Top }, narrow: domain1, concrete: concrete1 + assertAbstractDomain(create, domain1, { ...domain1, colnames: [[], Top] }, { + equal: false, leq: true, join: { ...domain1, colnames: [[], Top] }, meet: domain1, widen: { ...domain1, colnames: [[], Top] }, narrow: domain1, concrete: concrete1 }); - assertAbstractDomain(create, { ...domain1, colnames: Top }, domain1, { - equal: false, leq: false, join: { ...domain1, colnames: Top }, meet: domain1, widen: { ...domain1, colnames: Top }, narrow: domain1, concrete: Top, abstract: DataFrameTop + assertAbstractDomain(create, { ...domain1, colnames: [[], Top] }, domain1, { + equal: false, leq: false, join: { ...domain1, colnames: [[], Top] }, meet: domain1, widen: { ...domain1, colnames: [[], Top] }, narrow: domain1, concrete: Top, abstract: DataFrameTop }); assertAbstractDomain(create, domain1, { ...domain1, cols: PosIntervalTop }, { equal: false, leq: true, join: { ...domain1, cols: PosIntervalTop }, meet: domain1, widen: { ...domain1, cols: PosIntervalTop }, narrow: domain1, concrete: concrete1 diff --git a/test/functionality/abstract-interpretation/data-frame/inference.test.ts b/test/functionality/abstract-interpretation/data-frame/inference.test.ts index 18722d63fb2..edc1118cd11 100644 --- a/test/functionality/abstract-interpretation/data-frame/inference.test.ts +++ b/test/functionality/abstract-interpretation/data-frame/inference.test.ts @@ -3,13 +3,13 @@ import { Top } from '../../../../src/abstract-interpretation/domains/lattice'; import { PosIntervalTop } from '../../../../src/abstract-interpretation/domains/positive-interval-domain'; import { MIN_VERSION_LAMBDA, MIN_VERSION_PIPE } from '../../../../src/r-bridge/lang-4.x/ast/model/versions'; import { withShell } from '../../_helper/shell'; -import { assertDataFrameDomain, assertDataFrameOperation, ColNamesOverapproximation, DataFrameShapeOverapproximation, testDataFrameDomain, testDataFrameDomainAgainstReal, testDataFrameDomainWithSource } from './data-frame'; +import { assertDataFrameDomain, assertDataFrameOperation, DataFrameShapeOverapproximation, testDataFrameDomain, testDataFrameDomainAgainstReal, testDataFrameDomainWithSource } from './data-frame'; import { FlowrInlineTextFile } from '../../../../src/project/context/flowr-file'; /** The minimum version required for calling `head` and `tail` with a vector argument, e.g. `head(df, c(1, 2))` */ export const MIN_VERSION_HEAD_TAIL_VECTOR = '4.0.0'; -const DataFrameTop = { colnames: Top, cols: PosIntervalTop, rows: PosIntervalTop } as const; +const DataFrameTop = { colnames: [[], Top] as [[], typeof Top], cols: PosIntervalTop, rows: PosIntervalTop } as const; describe.sequential('Data Frame Shape Inference', withShell(shell => { let librariesInstalled = false; @@ -22,17 +22,9 @@ describe.sequential('Data Frame Shape Inference', withShell(shell => { 'd.csv': '1;3,5;banana\n2;7,8;apple\n3;4,2;peach\n4;1,9;grape\n', 'e.csv': 'first last state phone\nJohn Smith WA 418-Y11-4111\nMary Hartford CA 319-Z19-4341\nEvan Nolan IL 219-532-c301\n', 'f.csv': 'name\tname\tstate\tphone\nJohn\tSmith\tWA\t418-Y11-4111\nMary\tHartford\tCA\t319-Z19-4341\nEvan\tNolan\tIL\t219-532-c301' - } as const satisfies Readonly<{[path: string]: string}>; - - const addFiles = [ - new FlowrInlineTextFile('a.csv', sources['a.csv']), - new FlowrInlineTextFile('b.csv', sources['b.csv']), - new FlowrInlineTextFile('c.csv', sources['c.csv']), - new FlowrInlineTextFile('d.csv', sources['d.csv']), - new FlowrInlineTextFile('e.csv', sources['e.csv']), - new FlowrInlineTextFile('f.csv', sources['f.csv']) - ]; + } as const satisfies Readonly<{ [path: string]: string }>; + const addFiles = Object.entries(sources).map(([path, content]) => new FlowrInlineTextFile(path, content)); function getFileContent(source: keyof typeof sources) { return sources[source].replaceAll('\n', '\\n').replaceAll('\t', ' \\t').replaceAll('"', '\\"'); @@ -47,8 +39,7 @@ describe.sequential('Data Frame Shape Inference', withShell(shell => { testDataFrameDomain( shell, 'x <- 42', - [['1@x', undefined]], - { addFiles } + [['1@x', undefined]] ); testDataFrameDomain( @@ -63,14 +54,13 @@ assign("df6", data.frame(id = 1:5)) print(df6) `.trim(), [ - ['1@df1', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df2', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['3@df3', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['4@df4', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['5@df5', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['7@df6', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }] - ], - { addFiles } + ['1@df1', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df2', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['3@df3', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['4@df4', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['5@df5', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['7@df6', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }] + ] ); testDataFrameDomain( @@ -82,11 +72,10 @@ print(df6) df <- cbind(df1, df2, df3) `.trim(), [ - ['4@df1', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['4@df2', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['4@df3', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }] - ], - { addFiles } + ['4@df1', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['4@df2', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['4@df3', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }] + ] ); testDataFrameDomain( @@ -96,11 +85,10 @@ df1 <- data.frame(id = 1:5) df2 <- df1 `.trim(), [ - ['1@df1', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df1', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df2', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }] - ], - { addFiles } + ['1@df1', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df1', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df2', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }] + ] ); testDataFrameDomain( @@ -111,11 +99,10 @@ df <- data.frame() print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'type'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: [], cols: [0, 0], rows: [0, 0] }], - ['3@df', { colnames: [], cols: [0, 0], rows: [0, 0] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'type'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }], + ['3@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }] + ] ); testDataFrameDomain( @@ -126,32 +113,29 @@ print(df <- data.frame()) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'type'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: [], cols: [0, 0], rows: [0, 0] }], - ['3@df', { colnames: [], cols: [0, 0], rows: [0, 0] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'type'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }], + ['3@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }] + ] ); testDataFrameDomain( shell, 'df <- 1:3 |> data.frame(type = c("A", "B", "C"))', - [['1@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }]], - { minRVersion: MIN_VERSION_PIPE, addFiles } + [['1@df', { colnames: [['type'], Top], cols: [2, 2], rows: [3, 3] }]], + { minRVersion: MIN_VERSION_PIPE } ); testDataFrameDomain( shell, 'df <- if (runif(1) >= 0.5) data.frame(id = 1:5)', - [['1@df', undefined, DataFrameShapeOverapproximation]], - { addFiles } + [['1@df', undefined, DataFrameShapeOverapproximation]] ); testDataFrameDomain( shell, 'df <- if (runif(1) >= 0.5) data.frame(id = 1:5) else data.frame(id = 1:10, name = "A")', - [['1@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [5, 10] }, ColNamesOverapproximation]], - { addFiles } + [['1@df', { colnames: [['id'], ['name']], cols: [1, 2], rows: [5, 10] }]] ); testDataFrameDomain( @@ -164,8 +148,7 @@ if(runif(1) >= 0.5) { } print(df) `.trim(), - [['6@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [5, 10] }, ColNamesOverapproximation]], - { addFiles } + [['6@df', { colnames: [['id'], ['name']], cols: [1, 2], rows: [5, 10] }]] ); testDataFrameDomain( @@ -183,8 +166,7 @@ df <- if (i == 0) { } print(df) `.trim(), - [['11@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 10] }]], - { addFiles } + [['11@df', { colnames: [[], ['id', 'name']], cols: [1, 2], rows: [3, 10] }]] ); testDataFrameDomain( @@ -197,8 +179,7 @@ for (i in 1:5) { df[10, ] <- c(6, 11) print(df) `.trim(), - [['6@df', { colnames: Top, cols: [1, 2], rows: [10, 10] }]], - { addFiles } + [['6@df', { colnames: [['id'], Top], cols: [1, 2], rows: [10, 10] }]] ); testDataFrameDomain( @@ -214,8 +195,7 @@ while (nrow(df) < 10) { } print(df) `.trim(), - [['9@df', { colnames: ['id', 'name'], cols: [1, Infinity], rows: [5, Infinity] }]], - { addFiles } + [['9@df', { colnames: [['id'], ['name']], cols: [1, Infinity], rows: [5, Infinity] }]] ); testDataFrameDomain( @@ -229,12 +209,12 @@ while (TRUE) { df[10, ] <- c(6, 11) print(df) `.trim(), - [['7@df', { colnames: Top, cols: [1, 2], rows: [10, 10] }]], - { addFiles } + [['7@df', { colnames: [['id'], Top], cols: [1, 2], rows: [10, 10] }]] ); assertDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:5) repeat { df[2] <- 6:10 @@ -242,47 +222,46 @@ repeat { df[10, ] <- c(6, 11) print(df) `.trim(), - [['6@df', undefined]], // unreachable - { addFiles } + [['6@df', undefined]] // unreachable ); assertDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:5, name = 6:10) load('object_file') print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], ['3@df', undefined] - ], - { addFiles } + ] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:5, name = 6:10) eval(parse(text="df <- 12")) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], ['3@df', undefined] - ], - { addFiles } + ] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:5, score = 6:10) eval(parse(text="df$level <- df$score^2")) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], ['3@df', undefined, DataFrameShapeOverapproximation] - ], - { addFiles } + ] ); }); @@ -290,22 +269,19 @@ print(df) testDataFrameDomain( shell, 'df <- data.frame(id = 1:5, age = c(25, 32, 35, 40, 45), score = c(90, 85, 88, 92, 95), check.names = FALSE)', - [['1@df', { colnames: ['id', 'age', 'score'], cols: [3, 3], rows: [5, 5] }]], - { addFiles } + [['1@df', { colnames: [['id', 'age', 'score'], []], cols: [3, 3], rows: [5, 5] }]] ); testDataFrameDomain( shell, 'df <- data.frame("id" = c(1, 2, 3, 5, 6, 7), `category` = c("A", "B", "A", "A", "B", "B"))', - [['1@df', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }]], - { addFiles } + [['1@df', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }]] ); testDataFrameDomain( shell, 'df <- data.frame(1:5, c("A", "B", "C", "D", "E"), TRUE)', - [['1@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }]], - { addFiles } + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [5, 5] }]] ); testDataFrameDomain( @@ -314,99 +290,85 @@ print(df) a = 1; b = "A" df <- data.frame(id = c(a, a), name = b) `.trim(), - [['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [2, 2] }]], - { addFiles } + [['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [2, 2] }]] ); testDataFrameDomain( shell, 'df <- data.frame(c(1, 2, 3:5, c(6, 7, c(8, 9))), c("a", "b", "c"))', - [['1@df', { colnames: Top, cols: [2, 2], rows: [9, 9] }]], - { addFiles } + [['1@df', { colnames: [[], Top], cols: [2, 2], rows: [9, 9] }]] ); testDataFrameDomain( shell, 'df <- data.frame(1)', - [['1@df', { colnames: Top, cols: [1, 1], rows: [1, 1] }]], - { addFiles } + [['1@df', { colnames: [[], Top], cols: [1, 1], rows: [1, 1] }]] ); testDataFrameDomain( shell, 'df <- data.frame()', - [['1@df', { colnames: [], cols: [0, 0], rows: [0, 0] }]], - { addFiles } + [['1@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }]] ); testDataFrameDomain( shell, 'df <- data.frame(id = c(), name = c())', - [['1@df', { colnames: [], cols: [0, 0], rows: [0, 0] }]], - { addFiles } + [['1@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }]] ); testDataFrameDomain( shell, 'df <- data.frame(id = NULL)', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- data.frame(data.frame(1:3))', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- data.frame(list(id = 1:3))', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- data.frame(id = list(num = 1:3, name = 3:1))', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- data.frame(`:D` = 1:3)', - [['1@df', { colnames: Top, cols: [1, 1], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [[], Top], cols: [1, 1], rows: [3, 3] }]] ); testDataFrameDomain( shell, - 'df <- data.frame(id = 1:3, id = 4:6)', - [['1@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }]], - { addFiles } + 'df <- data.frame(id = 1:3, id = 4:6, name = c("A", "B", "C"))', + [['1@df', { colnames: [['name'], Top], cols: [3, 3], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- data.frame(id = 1:3, name = 6:8, row.names = "id")', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- data.frame(`:D` = 1:3, check.names = FALSE)', - [['1@df', { colnames: [':D'], cols: [1, 1], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [[':D'], []], cols: [1, 1], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- data.frame(1:3, fix.empty.names = FALSE)', - [['1@df', { colnames: Top, cols: [1, 1], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [[], Top], cols: [1, 1], rows: [3, 3] }]] ); }); @@ -414,29 +376,25 @@ df <- data.frame(id = c(a, a), name = b) testDataFrameDomain( shell, 'df <- as.data.frame(data.frame(1:3))', - [['1@df', { colnames: Top, cols: [1, 1], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [[], Top], cols: [1, 1], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- as.data.frame(list(id = 1:3))', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- as.data.frame(c(1, 2, 3))', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( shell, 'df <- as.data.frame(1)', - [['1@df', DataFrameTop]], - { addFiles } + [['1@df', DataFrameTop]] ); testDataFrameDomain( @@ -446,45 +404,39 @@ df1 <- data.frame(id = 1:3, label = c("A", "B", "C")) df2 <- as.data.frame(df1) `.trim(), [ - ['1@df1', { colnames: ['id', 'label'], cols: [2, 2], rows: [3, 3] }], - ['2@df2', { colnames: ['id', 'label'], cols: [2, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df1', { colnames: [['id', 'label'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df2', { colnames: [['id', 'label'], []], cols: [2, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( shell, 'df <- as.data.frame(data.frame(id = 1:3, name = 4:6), optional = TRUE)', - [['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- as.data.frame(data.frame(id = 1:3, name = 4:6), cut.names = 3)', - [['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- as.data.frame(data.frame(id = 1:3, name = 4:6), col.names = c("col1", "col2"))', - [['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- as.data.frame(data.frame(id = 1:3, name = 4:6), fix.empty.names = FALSE)', - [['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'df <- as.data.frame(optional = TRUE, fix.empty.names = FALSE, x = data.frame(id = 1:3, name = 4:6))', - [['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }]] ); }); @@ -493,7 +445,7 @@ df2 <- as.data.frame(df1) shell, '"a.csv"', `text = "${getFileContent('a.csv')}"`, source => `df <- read.csv(${source})`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { addFiles } ); @@ -509,7 +461,7 @@ df2 <- as.data.frame(df1) shell, '"a.csv"', `text = "${getFileContent('a.csv')}"`, source => `df <- read.csv(${source}, nrows = -1)`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { addFiles } ); @@ -517,7 +469,7 @@ df2 <- as.data.frame(df1) shell, '"a.csv"', `text = "${getFileContent('a.csv')}"`, source => `df <- read.table(${source}, header = TRUE, sep = ",")`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { addFiles } ); @@ -525,7 +477,7 @@ df2 <- as.data.frame(df1) shell, '"b.csv"', `text = "${getFileContent('b.csv')}"`, source => `df <- read.csv(${source}, quote = "'")`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { addFiles } ); @@ -533,7 +485,7 @@ df2 <- as.data.frame(df1) shell, '"b.csv"', `text = "${getFileContent('b.csv')}"`, source => `df <- read.table(${source}, header = TRUE, sep = ",")`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { addFiles } ); @@ -541,7 +493,7 @@ df2 <- as.data.frame(df1) shell, '"c.csv"', `text = "${getFileContent('c.csv')}"`, source => `df <- read.csv(${source}, comment.char = "#", check.names = FALSE)`, - [['1@df', { colnames: ['', 'id,number', '"unique" name'], cols: [3, 3], rows: [5, 5] }]], + [['1@df', { colnames: [['', 'id,number', '"unique" name'], []], cols: [3, 3], rows: [5, 5] }]], { addFiles } ); @@ -549,7 +501,7 @@ df2 <- as.data.frame(df1) shell, '"c.csv"', `text = "${getFileContent('c.csv')}"`, source => `df <- read.csv(${source}, header = FALSE, skip = 4)`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }]], + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [5, 5] }]], { addFiles } ); @@ -557,7 +509,7 @@ df2 <- as.data.frame(df1) shell, '"d.csv"', `text = "${getFileContent('d.csv')}"`, source => `df <- read.csv2(${source}, header = FALSE)`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [4, 4] }]], + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [4, 4] }]], { addFiles } ); @@ -565,7 +517,7 @@ df2 <- as.data.frame(df1) shell, '"d.csv"', `text = "${getFileContent('d.csv')}"`, source => `df <- read.delim(${source}, header = FALSE, sep = ",")`, - [['1@df', { colnames: Top, cols: [2, 2], rows: [4, 4] }]], + [['1@df', { colnames: [[], Top], cols: [2, 2], rows: [4, 4] }]], { addFiles } ); @@ -573,7 +525,7 @@ df2 <- as.data.frame(df1) shell, '"d.csv"', `text = "${getFileContent('d.csv')}"`, source => `df <- read.delim2(${source}, header = FALSE, sep = ";")`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [4, 4] }]], + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [4, 4] }]], { addFiles } ); @@ -581,7 +533,7 @@ df2 <- as.data.frame(df1) shell, '"e.csv"', `text = "${getFileContent('e.csv')}"`, source => `df <- read.table(${source}, header = TRUE)`, - [['1@df', { colnames: ['first', 'last', 'state', 'phone'], cols: [4, 4], rows: [3, 3] }]], + [['1@df', { colnames: [['first', 'last', 'state', 'phone'], []], cols: [4, 4], rows: [3, 3] }]], { addFiles } ); @@ -589,7 +541,7 @@ df2 <- as.data.frame(df1) shell, '"f.csv"', `text = "${getFileContent('f.csv')}"`, source => `df <- read.delim(${source})`, - [['1@df', { colnames: Top, cols: [4, 4], rows: [3, 3] }]], + [['1@df', { colnames: [['state', 'phone'], Top], cols: [4, 4], rows: [3, 3] }]], { addFiles } ); @@ -597,7 +549,7 @@ df2 <- as.data.frame(df1) shell, '"a.csv"', `"${getFileContent('a.csv')}"`, source => `df <- readr::read_csv(${source})`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { skipRun: skipLibraries, addFiles } ); @@ -605,7 +557,7 @@ df2 <- as.data.frame(df1) shell, '"b.csv"', `"${getFileContent('b.csv')}"`, source => `df <- readr::read_csv(${source}, quote = "'")`, - [['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }]], + [['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }]], { skipRun: skipLibraries, addFiles } ); @@ -613,7 +565,7 @@ df2 <- as.data.frame(df1) shell, '"c.csv"', `"${getFileContent('c.csv')}"`, source => `df <- readr::read_csv(${source}, comment = "#")`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }]], + [['1@df', { colnames: [['id,number','"unique" name'], Top], cols: [3, 3], rows: [5, 5] }]], { skipRun: skipLibraries, addFiles } ); @@ -621,7 +573,7 @@ df2 <- as.data.frame(df1) shell, '"c.csv"', `"${getFileContent('c.csv')}"`, source => `df <- readr::read_csv(${source}, col_names = FALSE, skip = 4)`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }]], + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [5, 5] }]], { skipRun: skipLibraries, addFiles } ); @@ -629,7 +581,7 @@ df2 <- as.data.frame(df1) shell, '"d.csv"', `"${getFileContent('d.csv')}"`, source => `df <- readr::read_csv2(${source}, col_names = FALSE)`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [4, 4] }]], + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [4, 4] }]], { skipRun: skipLibraries, addFiles } ); @@ -637,7 +589,7 @@ df2 <- as.data.frame(df1) shell, '"d.csv"', `"${getFileContent('d.csv')}"`, source => `df <- readr::read_delim(${source}, delim = ",", col_names = FALSE)`, - [['1@df', { colnames: Top, cols: [2, 2], rows: [4, 4] }]], + [['1@df', { colnames: [[], Top], cols: [2, 2], rows: [4, 4] }]], { skipRun: skipLibraries, addFiles } ); @@ -645,7 +597,7 @@ df2 <- as.data.frame(df1) shell, '"d.csv"', `"${getFileContent('d.csv')}"`, source => `df <- readr::read_delim(${source}, delim = ";", col_names = FALSE)`, - [['1@df', { colnames: Top, cols: [3, 3], rows: [4, 4] }]], + [['1@df', { colnames: [[], Top], cols: [3, 3], rows: [4, 4] }]], { skipRun: skipLibraries, addFiles } ); @@ -653,7 +605,7 @@ df2 <- as.data.frame(df1) shell, '"e.csv"', `"${getFileContent('e.csv')}"`, source => `df <- readr::read_table(${source})`, - [['1@df', { colnames: ['first', 'last', 'state', 'phone'], cols: [4, 4], rows: [3, 3] }]], + [['1@df', { colnames: [['first', 'last', 'state', 'phone'], []], cols: [4, 4], rows: [3, 3] }]], { skipRun: skipLibraries, addFiles } ); @@ -661,7 +613,7 @@ df2 <- as.data.frame(df1) shell, '"f.csv"', `"${getFileContent('f.csv')}"`, source => `df <- readr::read_tsv(${source})`, - [['1@df', { colnames: Top, cols: [4, 4], rows: [3, 3] }]], + [['1@df', { colnames: [['state', 'phone'], Top], cols: [4, 4], rows: [3, 3] }]], { skipRun: skipLibraries, addFiles } ); }); @@ -681,8 +633,7 @@ df$'id' ['3@$', [{ operation: 'accessCols', columns: ['id'] }]], ['4@$', [{ operation: 'accessCols', columns: ['id'] }]], ['5@$', [{ operation: 'accessCols', columns: ['id'] }]] - ], - { addFiles } + ] ); assertDataFrameOperation( @@ -705,8 +656,7 @@ df[1, ] ['6@[', [{ operation: 'accessCols', columns: [1] }]], ['7@[[', [{ operation: 'accessCols', columns: [1] }]], ['8@[', [{ operation: 'accessRows', rows: [1] }, { operation: 'subsetRows', rows: 1 }]] - ], - { addFiles } + ] ); assertDataFrameOperation( @@ -723,8 +673,7 @@ df[[1, 1]] ['3@[[', [{ operation: 'accessRows', rows: [1] }, { operation: 'accessCols', columns: ['id'] }]], ['4@[', [{ operation: 'accessRows', rows: [1] }, { operation: 'accessCols', columns: [1] }]], ['5@[[', [{ operation: 'accessRows', rows: [1] }, { operation: 'accessCols', columns: [1] }]] - ], - { addFiles } + ] ); assertDataFrameOperation( @@ -755,8 +704,7 @@ df[c(1, 3), 1:2] ['10@[', [{ operation: 'accessRows', rows: [1, 2] }, { operation: 'accessCols', columns: [1] }]], ['11@[', [{ operation: 'accessRows', rows: [1, 2] }, { operation: 'accessCols', columns: ['id', 'name'] }, { operation: 'subsetRows', rows: 2 }, { operation: 'subsetCols', colnames: ['id', 'name'] }]], ['12@[', [{ operation: 'accessRows', rows: [1, 3] }, { operation: 'accessCols', columns: [1, 2] }, { operation: 'subsetRows', rows: 2 }, { operation: 'subsetCols', colnames: [undefined, undefined] }]] - ], - { addFiles } + ] ); testDataFrameDomain( @@ -765,8 +713,7 @@ df[c(1, 3), 1:2] df <- data.frame(id = 1:3, name = 4:6) result <- df["id"] `.trim(), - [['2@result', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }]] ); testDataFrameDomain( @@ -775,26 +722,25 @@ result <- df["id"] df <- data.frame(id = 1:3, name = 4:6) result <- df[1] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [1, 1], rows: [3, 3] }, ColNamesOverapproximation]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [3, 3] }]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[1, 1] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[, 1] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( @@ -803,8 +749,7 @@ result <- df[, 1] df <- data.frame(id = 1:3, name = 4:6) result <- df[1, ] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [1, 1] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [1, 1] }]] ); testDataFrameDomain( @@ -813,8 +758,7 @@ result <- df[1, ] df <- data.frame(id = 1:3, name = 4:6) result <- df[1, c("id", "name")] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [1, 1] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [1, 1] }]] ); testDataFrameDomain( @@ -823,8 +767,7 @@ result <- df[1, c("id", "name")] df <- data.frame(id = 1:3, name = 4:6) result <- df[1, c(1, 2)] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [1, 1] }]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name']], cols: [2, 2], rows: [1, 1] }]] ); testDataFrameDomain( @@ -833,8 +776,7 @@ result <- df[1, c(1, 2)] df <- data.frame(id = 1:3, name = 4:6) result <- df[1:2, c(1, 2)] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [2, 2] }]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name']], cols: [2, 2], rows: [2, 2] }]] ); testDataFrameDomain( @@ -843,8 +785,7 @@ result <- df[1:2, c(1, 2)] df <- data.frame(id = 1:3, name = 4:6) result <- df[, 1:2] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name']], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -853,71 +794,70 @@ result <- df[, 1:2] df <- data.frame(id = 1:3, name = 4:6) result <- df[1:2, ] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [2, 2] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [2, 2] }]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[c(1, 2), 1] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[["id"]] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[[1]] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[[1, "id"]] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[[1, 1]] `.trim(), - [['2@result', undefined]], - { addFiles } + [['2@result', undefined]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df["id", drop = TRUE] `.trim(), - [['2@result', { colnames: ['id'], cols: [1,1], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [['id'], []], cols: [1,1], rows: [3, 3] }]] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) result <- df[, "id", drop = FALSE] `.trim(), - [['2@result', { colnames: ['id'], cols: [1,1], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [['id'], []], cols: [1,1], rows: [3, 3] }]] ); testDataFrameDomain( @@ -926,8 +866,7 @@ result <- df[, "id", drop = FALSE] df <- data.frame(id = 1:3, name = 4:6) result <- df[-1, "id", drop = FALSE] `.trim(), - [['2@result', { colnames: ['id'], cols: [1, 1], rows: [2, 2] }]], - { addFiles } + [['2@result', { colnames: [['id'], []], cols: [1, 1], rows: [2, 2] }]] ); testDataFrameDomain( @@ -936,8 +875,7 @@ result <- df[-1, "id", drop = FALSE] df <- data.frame(id = 1:3, name = 4:6) result <- df[c(-1, -2), -1, drop = FALSE] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [1, 1], rows: [1, 1] }, ColNamesOverapproximation]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [1, 1] }]] ); testDataFrameDomain( @@ -946,8 +884,7 @@ result <- df[c(-1, -2), -1, drop = FALSE] df <- data.frame(id = 1:3, name = 4:6, score = 7:9) result <- df[, -1] `.trim(), - [['2@result', { colnames: ['id', 'name', 'score'], cols: [2, 2], rows: [3, 3] }, ColNamesOverapproximation]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name', 'score']], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -956,8 +893,7 @@ result <- df[, -1] df <- data.frame(id = 1:3, name = 4:6, score = 7:9) result <- df[sample(1:3, 1)] `.trim(), - [['2@result', { colnames: ['id', 'name', 'score'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name', 'score']], cols: [0, 3], rows: [3, 3] }]] ); testDataFrameDomain( @@ -966,8 +902,7 @@ result <- df[sample(1:3, 1)] df <- data.frame(id = 1:3, name = 4:6, score = 7:9) result <- df[sample(1:3, 1), , drop = FALSE] `.trim(), - [['2@result', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [0, 3] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [0, 3] }]] ); testDataFrameDomain( @@ -976,8 +911,7 @@ result <- df[sample(1:3, 1), , drop = FALSE] df <- data.frame(id = 1:3, name = 4:6) result <- df[] `.trim(), - [['2@result', { colnames: ['id','name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [['id','name'], []], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -986,8 +920,7 @@ result <- df[] df <- data.frame(id = 1:3, name = 4:6) result <- df[,] `.trim(), - [['2@result', { colnames: ['id','name'], cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [['id','name'], []], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -996,8 +929,7 @@ result <- df[,] df <- data.frame(id = 1:3, name = 4:6) result <- df[0] `.trim(), - [['2@result', { colnames: [], cols: [0, 0], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [[], []], cols: [0, 0], rows: [3, 3] }]] ); testDataFrameDomain( @@ -1006,7 +938,7 @@ result <- df[0] df <- data.frame(id = 1:3, name = 4:6) result <- df[0, 1, drop = FALSE] `.trim(), - [['2@result', { colnames: ['id','name'], cols: [1, 1], rows: [0, 0] }, ColNamesOverapproximation]] + [['2@result', { colnames: [[], ['id','name']], cols: [1, 1], rows: [0, 0] }]] ); testDataFrameDomain( @@ -1015,8 +947,7 @@ result <- df[0, 1, drop = FALSE] df <- data.frame(id = 1:3, name = 4:6) result <- df[0, 0] `.trim(), - [['2@result', { colnames: [], cols: [0, 0], rows: [0, 0] }]], - { addFiles } + [['2@result', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }]] ); testDataFrameDomain( @@ -1025,7 +956,7 @@ result <- df[0, 0] df <- data.frame(id = 1:3, name = 4:6) result <- df[c(TRUE, FALSE)] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [0, 2], rows: [3, 3] }, ColNamesOverapproximation]] + [['2@result', { colnames: [[], ['id', 'name']], cols: [0, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -1034,8 +965,7 @@ result <- df[c(TRUE, FALSE)] df <- data.frame(id = 1:3, name = 4:6) result <- df[TRUE] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [0, 2], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [[], ['id', 'name']], cols: [0, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -1044,8 +974,7 @@ result <- df[TRUE] df <- data.frame(id = 1:3, name = 4:6) result <- df[c(TRUE, FALSE), ] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 3] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 3] }]] ); testDataFrameDomain( @@ -1054,8 +983,7 @@ result <- df[c(TRUE, FALSE), ] df <- data.frame(id = 1:3, name = 4:6) result <- df[df$id == 2, ] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 3] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 3] }]] ); testDataFrameDomain( @@ -1064,8 +992,7 @@ result <- df[df$id == 2, ] df <- data.frame(id = 1:3, name = 4:6) result <- df[df$id == 2, "name", drop = FALSE] `.trim(), - [['2@result', { colnames: ['name'], cols: [1, 1], rows: [0, 3] }]], - { addFiles } + [['2@result', { colnames: [['name'], []], cols: [1, 1], rows: [0, 3] }]] ); assertDataFrameOperation( @@ -1074,8 +1001,7 @@ result <- df[df$id == 2, "name", drop = FALSE] df <- data.frame(id = 1:3, name = 4:6) df[["nam", exact = FALSE]] `.trim(), - [['2@[[', [{ operation: 'accessCols', columns: undefined }]]], - { addFiles } + [['2@[[', [{ operation: 'accessCols', columns: undefined }]]] ); testDataFrameDomain( @@ -1084,8 +1010,7 @@ df[["nam", exact = FALSE]] df <- data.frame(id = 1:3, name = 4:6) result <- df[c("id", "id")] `.trim(), - [['2@result', { colnames: Top, cols: [2, 2], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }]] ); testDataFrameDomain( @@ -1094,8 +1019,7 @@ result <- df[c("id", "id")] df <- data.frame(id = 1:3, name = 4:6) result <- df[c(1, 1, 1)] `.trim(), - [['2@result', { colnames: Top, cols: [3, 3], rows: [3, 3] }]], - { addFiles } + [['2@result', { colnames: [[], Top], cols: [3, 3], rows: [3, 3] }]] ); testDataFrameDomain( @@ -1104,8 +1028,7 @@ result <- df[c(1, 1, 1)] df <- data.frame(id = 1:3, name = 4:6) result <- df[c(1, 1), ] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [2, 2] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [2, 2] }]] ); testDataFrameDomain( @@ -1114,22 +1037,19 @@ result <- df[c(1, 1), ] df <- data.frame(id = 1:3, name = 4:6) result <- df[c(1, 1, 1, 1, 1), ] `.trim(), - [['2@result', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }]], - { addFiles } + [['2@result', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }]] ); testDataFrameDomain( shell, 'result <- data.frame(id = 1:3, name = 4:6)["id"]', - [['1@result', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }]], - { addFiles } + [['1@result', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }]] ); testDataFrameDomain( shell, 'result <- cbind(data.frame(id = 1:3), name = 4:6)[2]', - [['1@result', { colnames: ['id', 'name'], cols: [1, 1], rows: [3, 3] }, ColNamesOverapproximation]], - { addFiles } + [['1@result', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [3, 3] }]] ); describe('Unsupported', { fails: true }, () => { @@ -1139,8 +1059,7 @@ result <- df[c(1, 1, 1, 1, 1), ] df <- data.frame(id = 1:3, name = 4:6, score = 7:9) result <- df[sample(1:3, 1), sample(1:3, 1)] `.trim(), - [['2@result', DataFrameShapeOverapproximation]], - { addFiles } + [['2@result', DataFrameShapeOverapproximation]] ); testDataFrameDomainAgainstReal( @@ -1149,8 +1068,7 @@ result <- df[sample(1:3, 1), sample(1:3, 1)] df <- data.frame(id = 1:3, name = 4:6, score = 7:9) result <- df[rep("id", times = 12)] `.trim(), - [['2@result', DataFrameShapeOverapproximation]], - { addFiles } + [['2@result', DataFrameShapeOverapproximation]] ); testDataFrameDomainAgainstReal( @@ -1159,8 +1077,7 @@ result <- df[rep("id", times = 12)] df <- data.frame(id = 1:3, name = 4:6, score = 7:9) result <- df[rep(1, times = 12), ] `.trim(), - [['2@result', DataFrameShapeOverapproximation]], - { addFiles } + [['2@result', DataFrameShapeOverapproximation]] ); }); }); @@ -1174,11 +1091,9 @@ df$id <- 4:6 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1189,10 +1104,9 @@ df$\`name\` <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1203,10 +1117,9 @@ df$"name" <- letters[1:3] print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1217,10 +1130,9 @@ df$name <- NULL print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1231,10 +1143,9 @@ df$name[3] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1245,10 +1156,9 @@ df$name[[3]] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1259,10 +1169,9 @@ df["id"] <- 4:6 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1273,10 +1182,9 @@ df[["name"]] <- letters[1:3] print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1287,10 +1195,9 @@ df[1] <- c("A", "B", "C") print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [1, 1], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], Top], cols: [1, 1], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1301,10 +1208,9 @@ df[[2]] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], Top], cols: [2, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1315,10 +1221,9 @@ df[, "name"] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1329,10 +1234,9 @@ df[4, ] <- 4 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 1], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 1], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1343,10 +1247,9 @@ df[4, "id"] <- 4 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 2], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 2], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1357,10 +1260,9 @@ df[[4, "id"]] <- 4 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 2], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 2], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1371,10 +1273,9 @@ df[4, 1] <- 4 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [1, 1], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], Top], cols: [1, 1], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1385,10 +1286,9 @@ df[[4, 1]] <- 4 print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [1, 1], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], Top], cols: [1, 1], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1399,10 +1299,9 @@ df[1, c("id", "name")] <- c(42, "A") print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 4], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 4], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1413,10 +1312,9 @@ df[, c("score", "level")] <- 100 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name', 'score', 'level'], cols: [2, 4], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name', 'score', 'level'], []], cols: [2, 4], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1427,10 +1325,9 @@ df[4, c(1, 2)] <- 100 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, 2], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1441,10 +1338,9 @@ df[1:2, c(1, 3)] <- 1 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [3, 3], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [3, 3], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1455,10 +1351,9 @@ df[3:5, 1:3] <- 1 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [3, 3], rows: [5, 5] }] + ] ); testDataFrameDomain( @@ -1469,10 +1364,9 @@ df[, 1:3] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [3, 3], rows: [3, 3] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [3, 3], rows: [3, 3] }] + ] ); testDataFrameDomain( @@ -1483,23 +1377,22 @@ df[1:8, ] <- 0 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [8, 8] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [8, 8] }] + ] ); testDataFrameDomain( - shell, ` + shell, + ` df <- data.frame(id = 1:3, name = 4:6) df[c(1, 4), 1] <- 42 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [4, 4] }] - ], - { addFiles } + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, 2], rows: [4, 4] }] + ] ); testDataFrameDomain( @@ -1510,8 +1403,8 @@ df[-1, "id"] <- 8:9 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 3], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 3], rows: [3, 3] }] ] ); @@ -1523,8 +1416,8 @@ df[c(-1, -2), -1] <- 1 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1536,8 +1429,8 @@ df[, -5] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1549,8 +1442,8 @@ df[sample(1:10)] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, Infinity], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, Infinity], rows: [3, 3] }] ] ); @@ -1562,8 +1455,8 @@ df[sample(1:10), ] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, Infinity] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, Infinity] }] ] ); @@ -1575,8 +1468,8 @@ df[] <- NULL print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: [], cols: [0, 0], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], []], cols: [0, 0], rows: [3, 3] }] ] ); @@ -1588,8 +1481,8 @@ df[,] <- 0 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1601,8 +1494,8 @@ df["name"] <- NULL print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id'], cols: [1, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id'], []], cols: [1, 2], rows: [3, 3] }] ] ); @@ -1614,8 +1507,8 @@ df[2] <- NULL print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], ['id', 'name']], cols: [1, 2], rows: [3, 3] }] ] ); @@ -1627,8 +1520,8 @@ df[c(TRUE, FALSE)] <- 3:1 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, Infinity], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, Infinity], rows: [3, 3] }] ] ); @@ -1640,8 +1533,8 @@ df[TRUE] <- 42 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, Infinity], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], Top], cols: [2, Infinity], rows: [3, 3] }] ] ); @@ -1653,8 +1546,8 @@ df[c(TRUE, FALSE), ] <- 1 print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, Infinity] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, Infinity] }] ] ); @@ -1666,8 +1559,8 @@ df[df$id == 2, ] <- c(5, "A") print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, Infinity] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, Infinity] }] ] ); @@ -1679,8 +1572,8 @@ df[["name"]][3] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [3, 3] }] ] ); @@ -1692,8 +1585,8 @@ df[[1]][3] <- "A" print(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['3@df', { colnames: [['id'], Top], cols: [1, 1], rows: [3, 3] }] ] ); @@ -1745,8 +1638,8 @@ colnames(df) <- c("id", "name") print(df) `.trim(), [ - ['1@df', { colnames: Top, cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [[], Top], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1758,8 +1651,8 @@ names(df) <- c("id", "name") print(df) `.trim(), [ - ['1@df', { colnames: Top, cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [[], Top], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1771,8 +1664,8 @@ colnames(df) <- runif(2) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1784,8 +1677,8 @@ colnames(df) <- NULL print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1797,8 +1690,8 @@ colnames(df) <- "col" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [['col'], Top], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1810,8 +1703,8 @@ colnames(df) <- c("col1", "col2") print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }], - ['3@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['3@df', { colnames: [['col1', 'col2'], Top], cols: [3, 3], rows: [5, 5] }] ] ); @@ -1823,8 +1716,8 @@ colnames(df)[1] <- "test" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: ['id', 'name', 'test'], cols: [2, 2], rows: [5, 5] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [['test'], ['id', 'name']], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1836,8 +1729,8 @@ colnames(df)[1:2] <- "test" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }], - ['3@df', { colnames: ['id', 'name', 'score', 'test'], cols: [3, 3], rows: [5, 5] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['3@df', { colnames: [['test'], ['id', 'name', 'score']], cols: [3, 3], rows: [5, 5] }] ] ); @@ -1849,8 +1742,8 @@ colnames(df)[-1] <- "test" print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['3@df', { colnames: ['id', 'name', 'test'], cols: [2, 2], rows: [5, 5] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['3@df', { colnames: [['test'], ['id', 'name']], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1862,8 +1755,8 @@ rownames(df) <- c("row1", "row2", "row3") print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1875,8 +1768,8 @@ rownames(df) <- runif(3) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1888,8 +1781,8 @@ dimnames(df) <- list(c("row1", "row2", "row3"), c("col1", "col2")) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1901,8 +1794,8 @@ dimnames(df)[[1]] <- c("row1", "row2", "row3") print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1914,8 +1807,8 @@ dimnames(df)[[2]] <- c("col1", "col2") print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1927,8 +1820,8 @@ dimnames(df)[1:2] <- list(c("row1", "row2", "row3"), c("col1", "col2")) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -1940,8 +1833,8 @@ dimnames(df)[-1] <- list(c("col1", "col2")) print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['3@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['3@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); }); @@ -1954,8 +1847,8 @@ df <- data.frame(id = 1:5) df <- cbind(df, name = 6:10, label = c("A", "B", "C", "D", "E")) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [5, 5] }] ] ); @@ -1966,8 +1859,8 @@ df <- data.frame(id = 1:5) df <- cbind(df, 6:10, c("A", "B", "C", "D", "E")) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], Top], cols: [3, 3], rows: [5, 5] }] ] ); @@ -1978,8 +1871,8 @@ df <- data.frame(id = 1:5) df <- cbind(df, name = "A") `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -1990,8 +1883,8 @@ df <- data.frame(id = 1:5) df <- cbind(df, runif(5)) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [1, Infinity], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], Top], cols: [1, Infinity], rows: [5, 5] }] ] ); @@ -2004,10 +1897,10 @@ df3 <- data.frame(label = c("A", "B", "C", "D", "E")) df <- cbind(df1, df2, df3) `.trim(), [ - ['1@df1', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df2', { colnames: ['name'], cols: [1, 1], rows: [5, 5] }], - ['3@df3', { colnames: ['label'], cols: [1, 1], rows: [5, 5] }], - ['4@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [5, 5] }] + ['1@df1', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df2', { colnames: [['name'], []], cols: [1, 1], rows: [5, 5] }], + ['3@df3', { colnames: [['label'], []], cols: [1, 1], rows: [5, 5] }], + ['4@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [5, 5] }] ] ); @@ -2019,9 +1912,9 @@ df2 <- data.frame(name = 6:10) df <- cbind(df1, df2, label = c("A", "B", "C", "D", "E")) `.trim(), [ - ['1@df1', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df2', { colnames: ['name'], cols: [1, 1], rows: [5, 5] }], - ['3@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [5, 5] }] + ['1@df1', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df2', { colnames: [['name'], []], cols: [1, 1], rows: [5, 5] }], + ['3@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [5, 5] }] ] ); @@ -2032,8 +1925,8 @@ df <- data.frame(id = 1:5) df <- cbind(df, label = list(name = 6:10)) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [1, Infinity], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], Top], cols: [1, Infinity], rows: [5, 5] }] ] ); @@ -2044,8 +1937,8 @@ df <- data.frame(id = 1:5) df <- cbind(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }] ] ); @@ -2056,16 +1949,15 @@ df <- data.frame(id = 1:5) df <- cbind(6:10, df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], Top], cols: [2, 2], rows: [5, 5] }] ] ); testDataFrameDomain( shell, 'df <- cbind(name = c("A", "B", "C"), value = "X", data.frame(id = 1:3, score = c(90, 75, 80)))', - [['1@df', { colnames: ['name', 'value', 'id', 'score'], cols: [4, 4], rows: [3, 3] }]], - { addFiles } + [['1@df', { colnames: [['name', 'value', 'id', 'score'], []], cols: [4, 4], rows: [3, 3] }]] ); testDataFrameDomain( @@ -2081,8 +1973,8 @@ df <- data.frame(id = 1, name = "A", score = 20) df <- rbind(df, c(2, "B", 30), c(4, "C", 25)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [1, 1] }], - ['2@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [1, 1] }], + ['2@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }] ] ); @@ -2093,8 +1985,8 @@ df <- data.frame(id = 1:3, name = 6:8) df <- rbind(df, row4 = c(4, 9), row5 = c(5, 10)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -2105,8 +1997,8 @@ df <- data.frame(id = 1:5) df <- rbind(df, 6, 7, 8, 9, 10) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [10, 10] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [10, 10] }] ] ); @@ -2117,8 +2009,8 @@ df <- data.frame(id = 1:5) df <- rbind(df, runif(5)) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [5, Infinity] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, Infinity] }] ] ); @@ -2131,10 +2023,10 @@ df3 <- data.frame(id = 5, name = "E", score = 40) df <- rbind(df1, df2, df3) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }], - ['2@df2', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [1, 1] }], - ['3@df3', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [1, 1] }], - ['4@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df2', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [1, 1] }], + ['3@df3', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [1, 1] }], + ['4@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }] ] ); @@ -2146,9 +2038,9 @@ df2 <- data.frame(id = 4, name = "D", score = 20) df <- rbind(df1, df2, label = c(5, "E", 40)) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [3, 3] }], - ['2@df2', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [1, 1] }], - ['3@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df2', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [1, 1] }], + ['3@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }] ] ); @@ -2159,8 +2051,8 @@ df <- data.frame(id = 1:5) df <- rbind(df, list(id = 6:10)) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [5, Infinity] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, Infinity] }] ] ); @@ -2171,8 +2063,8 @@ df <- data.frame(id = 1:5) df <- rbind(df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }] ] ); @@ -2183,27 +2075,38 @@ df <- data.frame(id = 1:5) df <- rbind(6, df) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [6, 6] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [6, 6] }] ] ); testDataFrameDomain( shell, 'df <- rbind(1:2, "X", data.frame(id = 1:3, score = c(90, 75, 80)), c("A", "B"))', - [['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [6, 6] }]], - { addFiles } + [['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [6, 6] }]] ); testDataFrameDomain( shell, ` -df <- data.frame(id = c(), name = c()) +df <- data.frame() df <- rbind(df, data.frame(id = 1:5, name = "A")) `.trim(), [ - ['1@df', { colnames: [], cols: [0, 0], rows: [0, 0] }], - ['2@df', { colnames: ['id', 'name'], cols: [0, 2], rows: [5, 5] }] + ['1@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [0, 2], rows: [5, 5] }] + ] + ); + + testDataFrameDomain( + shell, + ` +df <- data.frame(id = c(), name = c()) +df <- rbind(df, data.frame(score = 1:5, age = "A")) + `.trim(), + [ + ['1@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }], + ['2@df', { colnames: [[], ['score', 'age']], cols: [0, 2], rows: [5, 5] }] ] ); @@ -2214,8 +2117,8 @@ df <- data.frame() df <- rbind(df, 12) `.trim(), [ - ['1@df', { colnames: [], cols: [0, 0], rows: [0, 0] }], - ['2@df', { colnames: Top, cols: [1, 1], rows: [1, 1] }] + ['1@df', { colnames: [[], []], cols: [0, 0], rows: [0, 0] }], + ['2@df', { colnames: [[], Top], cols: [1, 1], rows: [1, 1] }] ] ); @@ -2234,8 +2137,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(df, n = 12) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [12, 12] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [12, 12] }] ] ); @@ -2246,8 +2149,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- head(df, n = 12) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -2258,8 +2161,8 @@ df <- if (runif(1) >= 0.5) data.frame(id = 1:3) else data.frame(id = 1:5, name = df <- head(df, n = 3) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 5] }, ColNamesOverapproximation], - ['2@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id'], ['name']], cols: [1, 2], rows: [3, 5] }], + ['2@df', { colnames: [['id'], ['name']], cols: [1, 2], rows: [3, 3] }] ] ); @@ -2270,8 +2173,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [6, 6] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [6, 6] }] ] ); @@ -2282,8 +2185,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(df, c(2, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 1], rows: [2, 2] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [2, 2] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2295,8 +2198,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(n = -2, x = df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [48, 48] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [48, 48] }] ] ); @@ -2307,8 +2210,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(df, n = -c(2, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 1], rows: [48, 48] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [48, 48] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2320,8 +2223,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(df, n = c(-2, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 1], rows: [48, 48] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [48, 48] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2333,8 +2236,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- head(df, sample(1:50, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 50] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 50] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2346,8 +2249,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(df, n = 12) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [12, 12] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [12, 12] }] ] ); @@ -2358,8 +2261,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- tail(df, n = 12) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -2370,8 +2273,8 @@ df <- if (runif(1) >= 0.5) data.frame(id = 1:3) else data.frame(id = 1:5, name = df <- tail(df, n = 3) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 5] }, ColNamesOverapproximation], - ['2@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id'], ['name']], cols: [1, 2], rows: [3, 5] }], + ['2@df', { colnames: [['id'], ['name']], cols: [1, 2], rows: [3, 3] }] ] ); @@ -2382,8 +2285,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [6, 6] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [6, 6] }] ] ); @@ -2394,8 +2297,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(df, c(2, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 1], rows: [2, 2] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [2, 2] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2407,8 +2310,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(n = -2, x = df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [48, 48] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [48, 48] }] ] ); @@ -2419,8 +2322,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(df, n = -c(2, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 1], rows: [48, 48] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [48, 48] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2432,8 +2335,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(df, n = c(-2, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 1], rows: [48, 48] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [[], ['id', 'name']], cols: [1, 1], rows: [48, 48] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2445,8 +2348,8 @@ df <- data.frame(id = 1:50, name = 51:100) df <- tail(df, sample(1:50, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [50, 50] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 50] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [50, 50] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 50] }] ], { minRVersion: MIN_VERSION_HEAD_TAIL_VECTOR } ); @@ -2460,8 +2363,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }] ] ); @@ -2472,8 +2375,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, FALSE) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [0, 0] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [0, 0] }] ] ); @@ -2484,8 +2387,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, id > 1) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [0, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [0, 3] }] ] ); @@ -2496,8 +2399,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, c(TRUE, FALSE)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [0, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [0, 3] }] ] ); @@ -2508,8 +2411,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }] ] ); @@ -2520,8 +2423,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = id) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }] ] ); @@ -2532,8 +2435,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = "id") `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }] ] ); @@ -2544,8 +2447,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = 1) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [1, 1], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [1, 1], rows: [3, 3] }] ] ); @@ -2556,8 +2459,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c(id, label)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'label'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'label'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2568,8 +2471,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c("id", "name")) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2580,8 +2483,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = 1:2) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [2, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2592,8 +2495,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c(id, 2)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2604,8 +2507,8 @@ df <- data.frame(id = 1:3) df <- subset(df, select = c(id, 1)) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }], - ['2@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }], + ['2@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2616,8 +2519,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = id:name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ] ); @@ -2628,8 +2531,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = sample(1:3, 2)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ] ); @@ -2640,8 +2543,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, TRUE, select = c(id, name)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2652,8 +2555,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, FALSE, id) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [0, 0] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [0, 0] }] ] ); @@ -2664,8 +2567,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, id == 2, -label) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 3] }] ] ); @@ -2676,8 +2579,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, id > 1, select = c(-name, -label)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [0, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [0, 3] }] ] ); @@ -2688,8 +2591,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = -c(id, name)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['label'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['label'], []], cols: [1, 1], rows: [3, 3] }] ] ); @@ -2700,8 +2603,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = -c(1, 2)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [1, 1], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [1, 1], rows: [3, 3] }] ] ); @@ -2712,8 +2615,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = -1) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [2, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2724,8 +2627,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c(TRUE, FALSE)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ] ); @@ -2736,8 +2639,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, TRUE, TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ] ); @@ -2748,8 +2651,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c(id, id)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: Top, cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], Top], cols: [2, 2], rows: [3, 3] }] ] ); testDataFrameDomain( @@ -2759,8 +2662,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c(1, 1, 1)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: Top, cols: [3, 3], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], Top], cols: [3, 3], rows: [3, 3] }] ] ); @@ -2771,7 +2674,7 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = id, drop = TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], ['2@df', undefined] ] ); @@ -2783,8 +2686,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- subset(df, select = c(id, name), drop = TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ] ); @@ -2815,6 +2718,33 @@ result <- subset(df, select = 1:2) [['2@subset', [{ operation: 'accessCols', columns: [1, 2] }]]] ); + assertDataFrameOperation( + shell, + ` +df <- data.frame(id = 1:3, name = 4:6, label = "A") +result <- subset(df, id > 1, c("name", "label")) + `.trim(), + [['2@subset', [{ operation: 'accessCols', columns: ['id', 'name', 'label'] }]]] + ); + + assertDataFrameOperation( + shell, + ` +df <- data.frame(id = 1:3, name = 4:6, label = "A") +result <- subset(df, label != "A", -id) + `.trim(), + [['2@subset', [{ operation: 'accessCols', columns: ['id', 'label'] }]]] + ); + + assertDataFrameOperation( + shell, + ` +df <- data.frame(id = 1:3, name = 4:6, label = "A") +result <- subset(df, select = 1:2) + `.trim(), + [['2@subset', [{ operation: 'accessCols', columns: [1, 2] }]]] + ); + describe('Unsupported', { fails: true }, () => { testDataFrameDomainAgainstReal( shell, @@ -2844,8 +2774,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df, TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2857,8 +2787,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df, FALSE) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 0] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 0] }] ], { skipRun: skipLibraries } ); @@ -2870,8 +2800,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df, id == 2) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 3] }] ], { skipRun: skipLibraries } ); @@ -2883,8 +2813,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df, TRUE, TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2896,8 +2826,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df, TRUE, FALSE, TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 0] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 0] }] ], { skipRun: skipLibraries } ); @@ -2909,8 +2839,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2922,8 +2852,8 @@ df <- data.frame(id = 1:3, name = 4:6) df <- dplyr::filter(df, FALSE, .preserve = TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [0, 0] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [0, 0] }] ], { skipRun: skipLibraries } ); @@ -2946,8 +2876,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, id, name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2959,8 +2889,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, "id", "name") `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2972,8 +2902,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, 1, 3) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [2, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2985,8 +2915,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, c(id, name)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -2998,8 +2928,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, c("id", "name")) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3011,8 +2941,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, 1:2) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [2, 2], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3024,8 +2954,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, id:name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3037,8 +2967,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, sample(1:3, 2)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3050,8 +2980,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: [], cols: [0, 0], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], []], cols: [0, 0], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3063,8 +2993,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, -name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'label'], cols: [2, 2], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'label'], []], cols: [2, 2], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3076,8 +3006,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, -name, -label) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3089,8 +3019,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, id, -name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['id'], []], cols: [1, 1], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3102,8 +3032,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, c(-id, -name)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['label'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['label'], []], cols: [1, 1], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3115,8 +3045,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, -c(id, name)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['label'], cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [['label'], []], cols: [1, 1], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3128,8 +3058,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, -c(1, 2)) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [1, 1], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [1, 1], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3138,11 +3068,11 @@ df <- dplyr::select(df, -c(1, 2)) shell, ` df <- data.frame(id = 1:3, name = 4:6, label = "A") -df <- dplyr::select(df, id, "name", 2) +df <- dplyr::select(df, id, "name", -2) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3154,8 +3084,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, nr = id) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: Top, cols: [1, 1], rows: [3, 3] }] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], Top], cols: [1, 1], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3167,8 +3097,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, id, \`id\`, "id") `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3180,8 +3110,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, 1, 1, 1) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3193,8 +3123,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, !name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3206,8 +3136,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, id | 2) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3219,8 +3149,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, c(id, name) & 1:3) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3232,8 +3162,8 @@ df <- data.frame(id = 1:3, name = 4:6, label = "A") df <- dplyr::select(df, contains("a")) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'label'], cols: [3, 3], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [0, 3], rows: [3, 3] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name', 'label'], []], cols: [3, 3], rows: [3, 3] }], + ['2@df', { colnames: [[], ['id', 'name', 'label']], cols: [0, 3], rows: [3, 3] }] ], { skipRun: skipLibraries } ); @@ -3274,8 +3204,8 @@ df <- data.frame(id = 1:5) df <- transform(df, id = letters[1:5]) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 2], rows: [5, 5] }] ] ); @@ -3286,8 +3216,8 @@ df <- data.frame(id = 1:5) df <- transform(df, "name" = letters[1:5]) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [5, 5] }] ] ); @@ -3298,8 +3228,8 @@ df <- data.frame(id = 1:5, score = 31:35) df <- transform(df, name = letters[id], level = score^2) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'score', 'name', 'level'], cols: [2, 4], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'score', 'name', 'level'], []], cols: [2, 4], rows: [5, 5] }] ] ); @@ -3310,8 +3240,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- transform(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ] ); @@ -3322,8 +3252,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- transform(df, \`:D\` = 11:15) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [2, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], Top], cols: [2, 3], rows: [5, 5] }] ] ); @@ -3334,8 +3264,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- transform(df, score = 31:35, \`score\` = 36:40) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [2, 4], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], Top], cols: [2, 4], rows: [5, 5] }] ] ); @@ -3346,8 +3276,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- transform(df, name = NULL) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 2], rows: [5, 5] }] ] ); @@ -3358,8 +3288,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- transform(df, "A") `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [2, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], Top], cols: [2, 3], rows: [5, 5] }] ] ); @@ -3376,6 +3306,24 @@ df <- transform(df, name = letters[id], level = score^2) shell, ` df <- data.frame(id = 1:5, name = 6:10) +df <- transform(df, score = id, level = score / max(score)) + `.trim(), + [['2@transform', [{ operation: 'accessCols', columns: ['id'] }]]] + ); + + assertDataFrameOperation( + shell, + ` +df <- data.frame(id = 1:5, score = 31:35) +df <- transform(df, name = letters[id], level = score^2) + `.trim(), + [['2@transform', [{ operation: 'accessCols', columns: ['id', 'score'] }]]] + ); + + assertDataFrameOperation( + shell, + ` +df <- data.frame(id = 1:5, name = 6:10) df <- transform(df, score = id, level = score / max(score)) `.trim(), [['2@transform', [{ operation: 'accessCols', columns: ['id'] }]]] @@ -3390,8 +3338,8 @@ df <- data.frame(id = 1:5) df <- dplyr::mutate(df, id = letters[1:5]) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3403,8 +3351,8 @@ df <- data.frame(id = 1:5) df <- dplyr::mutate(df, "name" = letters[1:5]) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3416,8 +3364,8 @@ df <- data.frame(id = 1:5) df <- dplyr::mutate(df, 6:10, 11:15) `.trim(), [ - ['1@df', { colnames: ['id'], cols: [1, 1], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [2, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id'], []], cols: [1, 1], rows: [5, 5] }], + ['2@df', { colnames: [['id'], Top], cols: [2, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3429,8 +3377,8 @@ df <- data.frame(id = 1:5, score = 31:35) df <- dplyr::mutate(df, name = letters[id], level = score^2) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'score', 'name', 'level'], cols: [2, 4], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'score', 'name', 'level'], []], cols: [2, 4], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3442,8 +3390,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3455,8 +3403,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df, \`:D\` = 11:15) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', ':D'], cols: [2, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', ':D'], []], cols: [2, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3468,8 +3416,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df, score = 31:35, \`score\` = 36:40) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', 'score'], cols: [2, 4], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', 'score'], []], cols: [2, 4], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3481,8 +3429,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df, name = NULL) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id'], []], cols: [1, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3494,8 +3442,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df, new = NULL) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name'], cols: [1, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [1, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3507,8 +3455,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df, new = -id, new = NULL) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', 'new'], cols: [1, 3], rows: [5, 5] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name'], []], cols: [1, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3520,8 +3468,8 @@ df <- data.frame(id = 1:5, name = 6:10) df <- dplyr::mutate(df, label = "A", .before = NULL) `.trim(), [ - ['1@df', { colnames: ['id', 'name'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', 'label'], cols: [2, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', 'label'], []], cols: [2, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3553,8 +3501,8 @@ df <- data.frame(id = 1:5, score = c(80, 75, 90, 70, 85)) df <- dplyr::group_by(df, id) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3566,8 +3514,8 @@ df <- data.frame(id = 1:5, score = c(80, 75, 90, 70, 85)) df <- dplyr::group_by(df, \`id\`) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3579,8 +3527,8 @@ df <- data.frame(id = 1:5, name = c("A", "A", "B", "A", "B"), score = c(80, 75, df <- dplyr::group_by(df, id, name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3592,8 +3540,8 @@ df <- data.frame(id = 1:5, score = c(80, 75, 90, 70, 85)) df <- dplyr::group_by(df) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3605,8 +3553,8 @@ df <- data.frame(id = 1:5, name = 6:10, score = c(80, 75, 90, 70, 85)) df <- dplyr::group_by(df, id + name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: Top, cols: [3, 4], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', 'score'], Top], cols: [3, 4], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3618,8 +3566,8 @@ df <- data.frame(id = 1:5, name = 6:10, score = c(80, 75, 90, 70, 85)) df <- dplyr::group_by(df, group = id + name) `.trim(), [ - ['1@df', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'name', 'score', 'group'], cols: [3, 4], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'name', 'score', 'group'], []], cols: [3, 4], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3631,8 +3579,8 @@ df <- data.frame(id = 1:5, score = c(80, 75, 90, 70, 85)) df <- dplyr::group_by(df, id, .add = TRUE) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -3644,8 +3592,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- dplyr::summarize(df, mean = mean(score), sum = sum(score)) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['2@df', { colnames: ['id', 'category', 'score', 'mean', 'sum'], cols: [2, 5], rows: [1, 6] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['2@df', { colnames: [['mean', 'sum'], ['id', 'category', 'score']], cols: [2, 5], rows: [1, 6] }] ], { skipRun: skipLibraries } ); @@ -3658,8 +3606,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- group_by(df, category) |> summarize(mean = mean(score), sum = sum(score)) `.trim(), [ - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'category', 'score', 'mean', 'sum'], cols: [2, 5], rows: [1, 6] }, ColNamesOverapproximation] + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['mean', 'sum'], ['id', 'category', 'score']], cols: [2, 5], rows: [1, 6] }] ], { skipRun: skipLibraries, minRVersion: MIN_VERSION_PIPE } ); @@ -3672,8 +3620,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- group_by(df, id, category) |> summarize(mean = mean(score), sum = sum(score)) `.trim(), [ - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'category', 'score', 'mean', 'sum'], cols: [2, 5], rows: [1, 6] }, ColNamesOverapproximation] + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['mean', 'sum'], ['id', 'category', 'score']], cols: [2, 5], rows: [1, 6] }] ], { skipRun: skipLibraries, minRVersion: MIN_VERSION_PIPE } ); @@ -3685,8 +3633,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- dplyr::summarize(df, 1) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['2@df', { colnames: Top, cols: [1, 4], rows: [1, 6] }] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['2@df', { colnames: [[], Top], cols: [1, 4], rows: [1, 6] }] ], { skipRun: skipLibraries } ); @@ -3698,8 +3646,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- dplyr::summarize(df) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['2@df', { colnames: ['id', 'category', 'score'], cols: [0, 3], rows: [1, 6] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['2@df', { colnames: [[], ['id', 'category', 'score']], cols: [0, 3], rows: [1, 6] }] ], { skipRun: skipLibraries } ); @@ -3712,8 +3660,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- group_by(df, category) |> summarize() `.trim(), [ - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [0, 3], rows: [1, 6] }, ColNamesOverapproximation] + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], ['id', 'category', 'score']], cols: [0, 3], rows: [1, 6] }] ], { skipRun: skipLibraries, minRVersion: MIN_VERSION_PIPE } ); @@ -3725,8 +3673,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- dplyr::summarize(df, mean = mean(score), sum = sum(score), .groups = "drop") `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['2@df', { colnames: ['id', 'category', 'score', 'mean', 'sum'], cols: [2, 5], rows: [1, 6] }, ColNamesOverapproximation] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['2@df', { colnames: [['mean', 'sum'], ['id', 'category', 'score']], cols: [2, 5], rows: [1, 6] }] ], { skipRun: skipLibraries } ); @@ -3739,8 +3687,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- filter(df, FALSE) |> group_by(category) |> summarize(score = mean(score)) `.trim(), [ - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [1, 4], rows: [0, 1] }, ColNamesOverapproximation] + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['score'], ['id', 'category']], cols: [1, 4], rows: [0, 1] }] ], { skipRun: skipLibraries, minRVersion: MIN_VERSION_PIPE } ); @@ -3753,8 +3701,8 @@ df <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B"), score = c df <- filter(df, FALSE) |> summarize(score = mean(score)) `.trim(), [ - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [1, 4], rows: [0, 1] }, ColNamesOverapproximation] + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['score'], ['id', 'category']], cols: [1, 4], rows: [0, 1] }] ], { skipRun: skipLibraries, minRVersion: MIN_VERSION_PIPE } ); @@ -3798,9 +3746,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::inner_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3813,9 +3761,9 @@ df2 <- data.frame(id = 1:4, score = c(80, 75, 90, 70)) df <- dplyr::inner_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3828,9 +3776,9 @@ df2 <- data.frame(id = 5:8, score = c(80, 75, 90, 70)) df <- dplyr::inner_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [2, 4], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [2, 4], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3843,9 +3791,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::inner_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3858,9 +3806,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::inner_join(df1, df2, by = c("id", "name")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [4, 4], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [4, 4], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3873,9 +3821,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::inner_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [3, 6], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [3, 6], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3888,9 +3836,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::inner_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3903,9 +3851,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::inner_join(df1, df2, list(x = "id", y = "nr")) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [0, 24] }] ], { skipRun: skipLibraries } ); @@ -3918,9 +3866,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::inner_join(df1, df2, dplyr::join_by(id == nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [0, 24] }] ], { skipRun: skipLibraries } ); @@ -3933,9 +3881,9 @@ df2 <- data.frame(id = 1:6, level = 80, category = c("A", "B", "B", "A", "C", "B df <- dplyr::inner_join(df1, df2, dplyr::join_by(score >= level)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [0, 24] }] ], { skipRun: skipLibraries } ); @@ -3948,9 +3896,9 @@ df2 <- data.frame(nr = 5:10, level = 80, category = c("A", "B", "B", "A", "C", " df <- dplyr::inner_join(df1, df2, dplyr::join_by(id <= nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [0, 24] }] ], { skipRun: skipLibraries } ); @@ -3963,9 +3911,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::inner_join(df1, df2, "id", suffix = c(".df1", ".df2")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [0, 4] }] ], { skipRun: skipLibraries } ); @@ -3978,8 +3926,8 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::inner_join(df1, df2, "id", keep = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], ['3@df', DataFrameTop] ], { skipRun: skipLibraries } @@ -3993,9 +3941,9 @@ df2 <- data.frame(id = 1:6, name = "Y", category = c("A", "B", "B", "A", "C", "B df <- dplyr::inner_join(df1, df2, by = sample(colnames(df1)[1:3], 2)) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'category', 'score'], cols: [4, 4], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category', 'amount'], cols: [4, 4], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [4, 8], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'name', 'category', 'score'], []], cols: [4, 4], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category', 'amount'], []], cols: [4, 4], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [4, 8], rows: [0, 24] }] ], { skipRun: skipLibraries } ); @@ -4008,9 +3956,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::left_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4023,9 +3971,9 @@ df2 <- data.frame(id = 1:4, score = c(80, 75, 90, 70)) df <- dplyr::left_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4038,9 +3986,9 @@ df2 <- data.frame(id = 5:8, score = c(80, 75, 90, 70)) df <- dplyr::left_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [2, 4], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [2, 4], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4053,9 +4001,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::left_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4068,9 +4016,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::left_join(df1, df2, by = c("id", "name")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [4, 4], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [4, 4], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4083,9 +4031,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::left_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [3, 6], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [3, 6], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4098,9 +4046,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::left_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4113,9 +4061,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::left_join(df1, df2, list(x = "id", y = "nr")) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [4, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [4, 24] }] ], { skipRun: skipLibraries } ); @@ -4128,9 +4076,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::left_join(df1, df2, dplyr::join_by(id == nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [4, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [4, 24] }] ], { skipRun: skipLibraries } ); @@ -4143,9 +4091,9 @@ df2 <- data.frame(id = 1:6, level = 80, category = c("A", "B", "B", "A", "C", "B df <- dplyr::left_join(df1, df2, dplyr::join_by(score >= level)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [4, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [4, 24] }] ], { skipRun: skipLibraries } ); @@ -4158,9 +4106,9 @@ df2 <- data.frame(nr = 5:10, level = 80, category = c("A", "B", "B", "A", "C", " df <- dplyr::left_join(df1, df2, dplyr::join_by(id <= nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [4, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [4, 24] }] ], { skipRun: skipLibraries } ); @@ -4173,9 +4121,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::left_join(df1, df2, "id", suffix = c(".df1", ".df2")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4188,8 +4136,8 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::left_join(df1, df2, "id", keep = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], ['3@df', DataFrameTop] ], { skipRun: skipLibraries } @@ -4203,9 +4151,9 @@ df2 <- data.frame(id = 1:6, name = "Y", category = c("A", "B", "B", "A", "C", "B df <- dplyr::left_join(df1, df2, by = sample(colnames(df1)[1:3], 2)) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'category', 'score'], cols: [4, 4], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category', 'amount'], cols: [4, 4], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [4, 8], rows: [4, 24] }] + ['1@df1', { colnames: [['id', 'name', 'category', 'score'], []], cols: [4, 4], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category', 'amount'], []], cols: [4, 4], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [4, 8], rows: [4, 24] }] ], { skipRun: skipLibraries } ); @@ -4218,9 +4166,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::right_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4233,9 +4181,9 @@ df2 <- data.frame(id = 1:4, score = c(80, 75, 90, 70)) df <- dplyr::right_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4248,9 +4196,9 @@ df2 <- data.frame(id = 5:8, score = c(80, 75, 90, 70)) df <- dplyr::right_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [2, 4], rows: [4, 4] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [2, 4], rows: [4, 4] }] ], { skipRun: skipLibraries } ); @@ -4263,9 +4211,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::right_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4278,9 +4226,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::right_join(df1, df2, by = c("id", "name")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [4, 4], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [4, 4], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4293,9 +4241,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::right_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [3, 6], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [3, 6], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4308,9 +4256,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::right_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4323,9 +4271,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::right_join(df1, df2, list(x = "id", y = "nr")) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4338,9 +4286,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::right_join(df1, df2, dplyr::join_by(id == nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4353,9 +4301,9 @@ df2 <- data.frame(id = 1:6, level = 80, category = c("A", "B", "B", "A", "C", "B df <- dplyr::right_join(df1, df2, dplyr::join_by(score >= level)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4368,9 +4316,9 @@ df2 <- data.frame(nr = 5:10, level = 80, category = c("A", "B", "B", "A", "C", " df <- dplyr::right_join(df1, df2, dplyr::join_by(id <= nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4383,9 +4331,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::right_join(df1, df2, "id", suffix = c(".df1", ".df2")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [6, 6] }] ], { skipRun: skipLibraries } ); @@ -4398,8 +4346,8 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::right_join(df1, df2, "id", keep = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], ['3@df', DataFrameTop] ], { skipRun: skipLibraries } @@ -4413,9 +4361,9 @@ df2 <- data.frame(id = 1:6, name = "Y", category = c("A", "B", "B", "A", "C", "B df <- dplyr::right_join(df1, df2, by = sample(colnames(df1)[1:3], 2)) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'category', 'score'], cols: [4, 4], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category', 'amount'], cols: [4, 4], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [4, 8], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'name', 'category', 'score'], []], cols: [4, 4], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category', 'amount'], []], cols: [4, 4], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [4, 8], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4428,9 +4376,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::full_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4443,9 +4391,9 @@ df2 <- data.frame(id = 1:4, score = c(80, 75, 90, 70)) df <- dplyr::full_join(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4458,9 +4406,9 @@ df2 <- data.frame(id = 5:8, score = c(80, 75, 90, 70)) df <- dplyr::full_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [2, 4], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [2, 4], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4473,9 +4421,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::full_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4488,9 +4436,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::full_join(df1, df2, by = c("id", "name")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [4, 4], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [4, 4], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4503,9 +4451,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- dplyr::full_join(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [3, 6], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [3, 6], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4518,9 +4466,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::full_join(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4533,9 +4481,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::full_join(df1, df2, list(x = "id", y = "nr")) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4548,9 +4496,9 @@ df2 <- data.frame(nr = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::full_join(df1, df2, dplyr::join_by(id == nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [2, 4], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [2, 4], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4563,9 +4511,9 @@ df2 <- data.frame(id = 1:6, level = 80, category = c("A", "B", "B", "A", "C", "B df <- dplyr::full_join(df1, df2, dplyr::join_by(score >= level)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4578,9 +4526,9 @@ df2 <- data.frame(nr = 5:10, level = 80, category = c("A", "B", "B", "A", "C", " df <- dplyr::full_join(df1, df2, dplyr::join_by(id <= nr)) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'level', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 5], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'level', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 5], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4593,9 +4541,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- dplyr::full_join(df1, df2, "id", suffix = c(".df1", ".df2")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [6, 10] }] ], { skipRun: skipLibraries } ); @@ -4608,8 +4556,8 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- dplyr::full_join(df1, df2, "id", keep = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], ['3@df', DataFrameTop] ], { skipRun: skipLibraries } @@ -4623,9 +4571,9 @@ df2 <- data.frame(id = 1:6, name = "Y", category = c("A", "B", "B", "A", "C", "B df <- dplyr::full_join(df1, df2, by = sample(colnames(df1)[1:3], 2)) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'category', 'score'], cols: [4, 4], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category', 'amount'], cols: [4, 4], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [4, 8], rows: [6, 24] }] + ['1@df1', { colnames: [['id', 'name', 'category', 'score'], []], cols: [4, 4], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category', 'amount'], []], cols: [4, 4], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [4, 8], rows: [6, 24] }] ], { skipRun: skipLibraries } ); @@ -4680,9 +4628,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [0, 4] }] ] ); @@ -4694,9 +4642,9 @@ df2 <- data.frame(id = 1:4, score = c(80, 75, 90, 70)) df <- merge(df1, df2, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [0, 4] }] ] ); @@ -4708,9 +4656,9 @@ df2 <- data.frame(id = 5:8, score = c(80, 75, 90, 70)) df <- merge(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [2, 4], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [2, 4], rows: [0, 4] }] ] ); @@ -4722,9 +4670,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [0, 4] }] ] ); @@ -4736,9 +4684,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, 1) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [3, 3], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [3, 3], rows: [0, 4] }] ] ); @@ -4750,9 +4698,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- merge(df1, df2, by = c("id", "name")) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [4, 4], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [4, 4], rows: [0, 4] }] ] ); @@ -4764,9 +4712,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- merge(df1, df2, by = 1:2) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [4, 4], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [[], Top], cols: [4, 4], rows: [0, 4] }] ] ); @@ -4778,9 +4726,9 @@ df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B df <- merge(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'name', 'score', 'category'], cols: [3, 6], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'name', 'score', 'category'], []], cols: [3, 6], rows: [0, 4] }] ] ); @@ -4792,9 +4740,9 @@ df2 <- data.frame(name = "A", category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['name', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'name', 'category'], cols: [2, 4], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['name', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'name', 'category'], []], cols: [2, 4], rows: [0, 24] }] ] ); @@ -4806,9 +4754,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, by = c()) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [4, 4], rows: [0, 24] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['score', 'category'], Top], cols: [4, 4], rows: [0, 24] }] ] ); @@ -4820,8 +4768,8 @@ lst <- list(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, lst, by = "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: Top, cols: [1, Infinity], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id'], Top], cols: [1, Infinity], rows: [0, 4] }] ] ); @@ -4833,8 +4781,8 @@ lst <- list(id = 3:8, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, lst, by = "id", all = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: Top, cols: [1, Infinity], rows: [4, Infinity] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id'], Top], cols: [1, Infinity], rows: [4, Infinity] }] ] ); @@ -4846,9 +4794,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- merge(df1, df2, "id") `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [0, 4] }] ] ); @@ -4860,8 +4808,8 @@ df2 <- data.frame(nr = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- merge(df1, df2, by.x = "id", by.y = "nr") `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['nr', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['nr', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], ['3@df', DataFrameTop] ] ); @@ -4874,9 +4822,9 @@ df2 <- data.frame(id = 1:4, score = c(80, 75, 90, 70)) df <- merge(df1, df2, "id", all.x = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ] ); @@ -4888,9 +4836,9 @@ df2 <- data.frame(id = 5:8, score = c(80, 75, 90, 70)) df <- merge(df1, df2, "id", all.x = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ] ); @@ -4902,9 +4850,9 @@ df2 <- data.frame(id = 7:10, score = c(80, 75, 90, 70)) df <- merge(df1, df2, "id", all.x = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['2@df2', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['2@df2', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ] ); @@ -4916,9 +4864,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all.y = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ] ); @@ -4930,9 +4878,9 @@ df2 <- data.frame(id = 3:8, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all.y = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ] ); @@ -4944,9 +4892,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all.y = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 6] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 6] }] ] ); @@ -4958,8 +4906,8 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all = runif(1) >= 0.5) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], ['3@df', DataFrameTop] ] ); @@ -4972,9 +4920,9 @@ df2 <- data.frame(id = 1:6, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 10] }] ] ); @@ -4986,9 +4934,9 @@ df2 <- data.frame(id = 3:8, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 10] }] ] ); @@ -5000,9 +4948,9 @@ df2 <- data.frame(id = 5:10, category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, "id", all = TRUE) `.trim(), [ - ['1@df1', { colnames: ['id', 'score'], cols: [2, 2], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['3@df', { colnames: ['id', 'score', 'category'], cols: [3, 3], rows: [6, 10] }] + ['1@df1', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], []], cols: [3, 3], rows: [6, 10] }] ] ); @@ -5014,9 +4962,9 @@ df2 <- data.frame(id = 1:6, name = "B", category = c("A", "B", "B", "A", "C", "B df <- merge(df1, df2, "id", no.dups = FALSE) `.trim(), [ - ['1@df1', { colnames: ['id', 'name', 'score'], cols: [3, 3], rows: [4, 4] }], - ['2@df2', { colnames: ['id', 'name', 'category'], cols: [3, 3], rows: [6, 6] }], - ['3@df', { colnames: Top, cols: [5, 5], rows: [0, 4] }] + ['1@df1', { colnames: [['id', 'name', 'score'], []], cols: [3, 3], rows: [4, 4] }], + ['2@df2', { colnames: [['id', 'name', 'category'], []], cols: [3, 3], rows: [6, 6] }], + ['3@df', { colnames: [['id', 'score', 'category'], Top], cols: [5, 5], rows: [0, 4] }] ] ); @@ -5025,6 +4973,16 @@ df <- merge(df1, df2, "id", no.dups = FALSE) ` df1 <- data.frame(id = 1:4, name = "A", score = c(80, 75, 90, 70)) df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B")) +df <- merge(df1, df2, by = c("id", "name")) + `.trim(), + [['3@merge', [{ operation: 'accessCols', columns: ['id', 'name'] }]]] + ); + + assertDataFrameOperation( + shell, + ` +df1 <- data.frame(id = 1:4, name = "A", score = c(80, 75, 90, 70)) +df2 <- data.frame(id = 1:6, name = "A", category = c("A", "B", "B", "A", "C", "B")) df <- merge(df1, df2, by = c("id", "name")) `.trim(), [['3@merge', [{ operation: 'accessCols', columns: ['id', 'name'] }]]] @@ -5039,8 +4997,8 @@ df <- data.frame(id = 1:5, category = c("A", "B", "A", "C", "B"), score = c(80, df <- dplyr::relocate(df, category) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -5052,8 +5010,8 @@ df <- data.frame(id = 1:5, category = c("A", "B", "A", "C", "B"), score = c(80, df <- dplyr::relocate(df, score, .before = category) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -5065,7 +5023,7 @@ df <- data.frame(id = 1:5, category = c("A", "B", "A", "C", "B"), score = c(80, df <- dplyr::relocate(df, label = category) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }], + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }], ['2@df', DataFrameTop] ], { skipRun: skipLibraries } @@ -5078,8 +5036,8 @@ df <- data.frame(id = 1:5, category = c("A", "B", "A", "C", "B"), score = c(80, df <- dplyr::arrange(df, -score, id) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -5091,8 +5049,8 @@ df <- data.frame(id = 1:5, category = c("A", "B", "A", "C", "B"), score = c(80, df <- dplyr::arrange(df, desc(score)) `.trim(), [ - ['1@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }], - ['2@df', { colnames: ['id', 'category', 'score'], cols: [3, 3], rows: [5, 5] }] + ['1@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['2@df', { colnames: [['id', 'category', 'score'], []], cols: [3, 3], rows: [5, 5] }] ], { skipRun: skipLibraries } ); @@ -5113,7 +5071,7 @@ df <- data.frame(id = c(1, 2, 3, 1, 3), score = c(80, 75, 90, 70, 85)) df <- aggregate(df, list(group = df$id), mean) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], ['2@df', DataFrameTop, DataFrameShapeOverapproximation] ] ); @@ -5129,7 +5087,7 @@ df <- within(df, { print(df) `.trim(), [ - ['1@df', { colnames: ['id', 'score'], cols: [2, 2], rows: [5, 5] }], + ['1@df', { colnames: [['id', 'score'], []], cols: [2, 2], rows: [5, 5] }], ['6@df', DataFrameTop, DataFrameShapeOverapproximation] ] ); @@ -5152,9 +5110,9 @@ df3 <- df1 %>% print(df3$level) `.trim(), [ - ['3@df1', { colnames: ['id', 'age', 'score'], cols: [3, 3], rows: [5, 5] }], - ['4@df2', { colnames: ['id', 'category'], cols: [2, 2], rows: [6, 6] }], - ['11@df3', { colnames: ['id', 'score', 'level', 'category'], cols: [3, 4], rows: [0, 5] }] + ['3@df1', { colnames: [['id', 'age', 'score'], []], cols: [3, 3], rows: [5, 5] }], + ['4@df2', { colnames: [['id', 'category'], []], cols: [2, 2], rows: [6, 6] }], + ['11@df3', { colnames: [['id', 'score', 'level', 'category'], []], cols: [3, 4], rows: [0, 5] }] ], { skipRun: skipLibraries } ); @@ -5179,13 +5137,13 @@ result <- result %>% mutate(grade = ifelse(avg_score >= 90, "Excellent", ifelse( result <- result %>% arrange(desc(avg_score)) `.trim(), [ - ['10@df', { colnames: ['id', 'name', 'age', 'score'], cols: [4, 4], rows: [10, 10] }], - ['10@result', { colnames: ['id', 'age', 'score'], cols: [3, 3], rows: [10, 10] }], - ['11@result', { colnames: ['id', 'age', 'score'], cols: [3, 3], rows: [0, 10] }], - ['12@result', { colnames: ['id', 'age', 'score'], cols: [3, 3], rows: [0, 10] }], - ['13@result', { colnames: ['id', 'age', 'score', 'avg_score'], cols: [1, 4], rows: [0, 10] }, ColNamesOverapproximation], - ['14@result', { colnames: ['id', 'age', 'score', 'avg_score', 'grade'], cols: [1, 5], rows: [0, 10] }, ColNamesOverapproximation], - ['15@result', { colnames: ['id', 'age', 'score', 'avg_score', 'grade'], cols: [1, 5], rows: [0, 10] }, ColNamesOverapproximation] + ['10@df', { colnames: [['id', 'name', 'age', 'score'], []], cols: [4, 4], rows: [10, 10] }], + ['10@result', { colnames: [['id', 'age', 'score'], []], cols: [3, 3], rows: [10, 10] }], + ['11@result', { colnames: [['id', 'age', 'score'], []], cols: [3, 3], rows: [0, 10] }], + ['12@result', { colnames: [['id', 'age', 'score'], []], cols: [3, 3], rows: [0, 10] }], + ['13@result', { colnames: [['avg_score'], ['id', 'age', 'score']], cols: [1, 4], rows: [0, 10] }], + ['14@result', { colnames: [['avg_score', 'grade'], ['id', 'age', 'score']], cols: [1, 5], rows: [0, 10] }], + ['15@result', { colnames: [['avg_score', 'grade'], ['id', 'age', 'score']], cols: [1, 5], rows: [0, 10] }] ], { skipRun: skipLibraries } ); @@ -5199,10 +5157,10 @@ df <- df |> rbind(c(4, 32), c(5, 35)) df <- df[2:3, 1:2] `.trim(), [ - ['1@df', { colnames: ['id', 'age'], cols: [2, 2], rows: [3, 3] }], - ['2@df', { colnames: ['id', 'age'], cols: [2, 2], rows: [0, 3] }], - ['3@df', { colnames: ['id', 'age'], cols: [2, 2], rows: [2, 5] }], - ['4@df', { colnames: ['id', 'age'], cols: [2, 2], rows: [2, 2] }], + ['1@df', { colnames: [['id', 'age'], []], cols: [2, 2], rows: [3, 3] }], + ['2@df', { colnames: [['id', 'age'], []], cols: [2, 2], rows: [0, 3] }], + ['3@df', { colnames: [['id', 'age'], []], cols: [2, 2], rows: [2, 5] }], + ['4@df', { colnames: [[], ['id', 'age']], cols: [2, 2], rows: [2, 2] }], ], { minRVersion: MIN_VERSION_PIPE } ); diff --git a/test/functionality/abstract-interpretation/domains/domain.ts b/test/functionality/abstract-interpretation/domains/domain.ts index 356d8070af4..5ee03aecbe5 100644 --- a/test/functionality/abstract-interpretation/domains/domain.ts +++ b/test/functionality/abstract-interpretation/domains/domain.ts @@ -1,8 +1,10 @@ import { assert, test } from 'vitest'; -import { DEFAULT_INFERENCE_LIMIT, type AnyAbstractDomain, type ConcreteDomain } from '../../../../src/abstract-interpretation/domains/abstract-domain'; -import { Top } from '../../../../src/abstract-interpretation/domains/lattice'; +import { type AnyAbstractDomain, type ConcreteDomain } from '../../../../src/abstract-interpretation/domains/abstract-domain'; +import { Top, TopSymbol } from '../../../../src/abstract-interpretation/domains/lattice'; -export interface DomainTestExpectation{ +const ConcretizationLimit = 20; + +export interface DomainTestExpectation{ readonly equal: boolean, readonly leq: boolean, readonly join: AbstractValue, @@ -21,7 +23,7 @@ export function assertAbstractDomain Domain, value1: AbstractValue, value2: AbstractValue, - expected: DomainTestExpectation, AbstractValue> + expected: DomainTestExpectation> ) { const domain1 = create(value1); const domain2 = create(value2); @@ -33,18 +35,22 @@ export function assertAbstractDomain { - assert.strictEqual(domain1.equals(domain2), expected.equal); + assert.strictEqual(domain1.equals(domain2), expected.equal, `expected ${domain1.toString()} to equal ${domain2.toString()}`); + assert.strictEqual(domain2.equals(domain1), expected.equal, `expected ${domain2.toString()} to equal ${domain1.toString()}`); }); test(`${domain1.toString()} ⊑ ${domain2.toString()}`, () => { - assert.strictEqual(domain1.leq(domain2), expected.leq); + assert.strictEqual(domain1.leq(domain2), expected.leq, `expected ${domain1.toString()} to less than or equal to ${domain2.toString()}`); + assert.isTrue(!expected.leq || domain1.equals(domain2) || !domain2.leq(domain1), `expected ${domain2.toString()} to be greater than or equal to ${domain1.toString()}`); }); test(`${domain1.toString()} ⊔ ${domain2.toString()}`, () => { assert.isTrue(domain1.join(domain2).equals(join), `expected ${join.toString()} but was ${domain1.join(domain2).toString()}`); + assert.isTrue(domain2.join(domain1).equals(join), `expected ${join.toString()} but was ${domain2.join(domain1).toString()}`); assert.isTrue(domain1.leq(domain1.join(domain2)), `expected ${domain1.toString()} to be less than or equal to join ${domain1.join(domain2).toString()}`); assert.isTrue(domain2.leq(domain1.join(domain2)), `expected ${domain2.toString()} to be less than or equal to join ${domain1.join(domain2).toString()}`); }); test(`${domain1.toString()} ⊓ ${domain2.toString()}`, () => { assert.isTrue(domain1.meet(domain2).equals(meet), `expected ${meet.toString()} but was ${domain1.meet(domain2).toString()}`); + assert.isTrue(domain2.meet(domain1).equals(meet), `expected ${meet.toString()} but was ${domain2.meet(domain1).toString()}`); assert.isTrue(domain1.meet(domain2).leq(domain1), `expected meet ${domain1.meet(domain2).toString()} to be less than or equal to ${domain1.toString()}`); assert.isTrue(domain1.meet(domain2).leq(domain2), `expected meet ${domain1.meet(domain2).toString()} to be less than or equal to ${domain2.toString()}`); }); @@ -61,16 +67,20 @@ export function assertAbstractDomain { - assert.deepStrictEqual(domain1.concretize(DEFAULT_INFERENCE_LIMIT), concrete, `expected ${toString(concrete)} but was ${toString(domain1.concretize(DEFAULT_INFERENCE_LIMIT))}`); + assert.deepStrictEqual(domain1.concretize(ConcretizationLimit), concrete, `expected ${toString(concrete)} but was ${toString(domain1.concretize(ConcretizationLimit))}`); }); test(`α(γ(${domain1.toString()}))`, () => { - assert.isTrue(domain1.abstract(domain1.concretize(DEFAULT_INFERENCE_LIMIT)).equals(abstract), `expected ${abstract.toString()} but was ${domain1.abstract(domain1.concretize(DEFAULT_INFERENCE_LIMIT)).toString()}`); + assert.isTrue(domain1.abstract(domain1.concretize(ConcretizationLimit)).equals(abstract), `expected ${abstract.toString()} but was ${domain1.abstract(domain1.concretize(ConcretizationLimit)).toString()}`); }); } -function toString(set: ReadonlySet | typeof Top): string { - if(set === Top) { - return '⊤'; +function toString(value: ReadonlySet | typeof Top | unknown): string { + if(value instanceof Map) { + return `{${value.entries().map(([key, value]) => `${toString(key)} -> ${toString(value)}`).toArray().join(', ')}}`; + } else if(value instanceof Set) { + return `{${value.values().map(value => toString(value)).toArray().join(', ')}}`; + } else if(value === Top) { + return TopSymbol; } - return `{${set.values().map(value => JSON.stringify(value)).toArray().join(', ')}}`; + return JSON.stringify(value); } diff --git a/test/functionality/abstract-interpretation/domains/domains.test.ts b/test/functionality/abstract-interpretation/domains/domains.test.ts index d83ef24dbbb..70128fb9ba4 100644 --- a/test/functionality/abstract-interpretation/domains/domains.test.ts +++ b/test/functionality/abstract-interpretation/domains/domains.test.ts @@ -4,6 +4,8 @@ import { BoundedSetDomain } from '../../../../src/abstract-interpretation/domain import { IntervalDomain, IntervalTop } from '../../../../src/abstract-interpretation/domains/interval-domain'; import { Bottom, Top } from '../../../../src/abstract-interpretation/domains/lattice'; import { PosIntervalDomain, PosIntervalTop } from '../../../../src/abstract-interpretation/domains/positive-interval-domain'; +import { SetRangeDomain } from '../../../../src/abstract-interpretation/domains/set-range-domain'; +import { SetUpperBoundDomain } from '../../../../src/abstract-interpretation/domains/set-upper-bound-domain'; import { SingletonDomain } from '../../../../src/abstract-interpretation/domains/singleton-domain'; import { assertAbstractDomain } from './domain'; @@ -46,58 +48,147 @@ describe('Abstract Domains', () => { }); }); - describe('Bounded Set Domain', () => { - const create = (value: string[] | typeof Top) => new BoundedSetDomain(value); + const setTests = [{ + name: 'Bounded Set Domain', + create: (value: string[] | typeof Top) => new BoundedSetDomain(value) as AnyAbstractDomain, + concrete: (...values: string[]) => values + }, { + name: 'Set Upper Bound Domain', + create: (value: string[] | typeof Top) => new SetUpperBoundDomain(value) as AnyAbstractDomain, + concrete: (...values: string[]) => values.reduce((sets, value) => [...sets, ...sets.map(set => new Set([...set, value]))], [new Set()]) + }]; - assertAbstractDomain(create, [], [], { - equal: true, leq: true, join: [], meet: [], widen: [], narrow: [], concrete: [] + for(const { name, create, concrete } of setTests) { + describe(name, () => { + assertAbstractDomain(create, [], [], { + equal: true, leq: true, join: [], meet: [], widen: [], narrow: [], concrete: concrete() + }); + assertAbstractDomain(create, Top, Top, { + equal: true, leq: true, join: Top, meet: Top, widen: Top, narrow: Top, concrete: Top + }); + assertAbstractDomain(create, [], Top, { + equal: false, leq: true, join: Top, meet: [], widen: Top, narrow: [], concrete: concrete() + }); + assertAbstractDomain(create, Top, [], { + equal: false, leq: false, join: Top, meet: [], widen: Top, narrow: [], concrete: Top + }); + assertAbstractDomain(create, [], ['id', 'age'], { + equal: false, leq: true, join: ['id', 'age'], meet: [], widen: Top, narrow: [], concrete: concrete() + }); + assertAbstractDomain(create, ['id', 'age'], [], { + equal: false, leq: false, join: ['id', 'age'], meet: [], widen: ['id', 'age'], narrow: ['id', 'age'], concrete: concrete('id', 'age') + }); + assertAbstractDomain(create, ['id', 'age'], ['age', 'id'], { + equal: true, leq: true, join: ['id', 'age'], meet: ['id', 'age'], widen: ['id', 'age'], narrow: ['id', 'age'], concrete: concrete('id', 'age') + }); + assertAbstractDomain(create, ['id', 'age'], ['id', 'age', 'score'], { + equal: false, leq: true, join: ['id', 'age', 'score'], meet: ['id', 'age'], widen: Top, narrow: ['id', 'age'], concrete: concrete('id', 'age') + }); + assertAbstractDomain(create, ['id', 'age', 'score'], ['id', 'age'], { + equal: false, leq: false, join: ['id', 'age', 'score'], meet: ['id', 'age'], widen: ['id', 'age', 'score'], narrow: ['id', 'age', 'score'], concrete: concrete('id', 'age', 'score') + }); + assertAbstractDomain(create, ['id', 'age', 'score'], ['id', 'category'], { + equal: false, leq: false, join: ['id', 'age', 'score', 'category'], meet: ['id'], widen: Top, narrow: ['id', 'age', 'score'], concrete: concrete('id', 'age', 'score') + }); + assertAbstractDomain(create, ['id', 'category'], ['id', 'age', 'score'], { + equal: false, leq: false, join: ['id', 'age', 'score', 'category'], meet: ['id'], widen: Top, narrow: ['id', 'category'], concrete: concrete('id', 'category') + }); + assertAbstractDomain(create, ['id', 'age'], Top, { + equal: false, leq: true, join: Top, meet: ['id', 'age'], widen: Top, narrow: ['id', 'age'], concrete: concrete('id', 'age') + }); + assertAbstractDomain(create, Top, ['id', 'age'], { + equal: false, leq: false, join: Top, meet: ['id', 'age'], widen: Top, narrow: ['id', 'age'], concrete: Top + }); }); - assertAbstractDomain(create, Top, Top, { - equal: true, leq: true, join: Top, meet: Top, widen: Top, narrow: Top, concrete: Top + } + + describe('Set Range Domain', () => { + const create = (value: [min: string[], range: string[] | typeof Top] | typeof Bottom) => + new SetRangeDomain(value === Bottom ? value : { min: value[0], range: value[1] === Top ? Top : value[1] }); + + const concrete = (...lists: string[][]) => lists.map(list => new Set(list)); + + assertAbstractDomain(create, Bottom, Bottom, { + equal: true, leq: true, join: Bottom, meet: Bottom, widen: Bottom, narrow: Bottom, concrete: [] + }); + assertAbstractDomain(create, [[], Top], [[], Top], { + equal: true, leq: true, join: [[], Top], meet: [[], Top], widen: [[], Top], narrow: [[], Top], concrete: Top + }); + assertAbstractDomain(create, Bottom, [[], Top], { + equal: false, leq: true, join: [[], Top], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: [] + }); + assertAbstractDomain(create, [[], Top], Bottom, { + equal: false, leq: false, join: [[], Top], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: Top + }); + assertAbstractDomain(create, Bottom, [['id'], ['name', 'age']], { + equal: false, leq: true, join: [['id'], ['name', 'age']], meet: Bottom, widen: [['id'], ['name', 'age']], narrow: Bottom, concrete: [] + }); + assertAbstractDomain(create, [['id'], ['name', 'age']], Bottom, { + equal: false, leq: false, join: [['id'], ['name', 'age']], meet: Bottom, widen: [['id'], ['name', 'age']], narrow: Bottom, concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age']) + }); + assertAbstractDomain(create, [[], []], [['id'], ['name', 'age']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: concrete([]) + }); + assertAbstractDomain(create, [['id'], ['name', 'age']], [[], []], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: Bottom, widen: [[], ['id', 'name', 'age']], narrow: Bottom, concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age']) + }); + assertAbstractDomain(create, [[], ['id']], [['id'], ['name', 'age']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: [['id'], []], widen: [[], Top], narrow: [['id'], []], concrete: concrete([], ['id']) + }); + assertAbstractDomain(create, [['id'], ['name', 'age']], [[], ['id']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: [['id'], []], widen: [[], ['id', 'name', 'age']], narrow: [['id'], ['name', 'age']], concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age']) + }); + assertAbstractDomain(create, [['id'], ['name']], [[], ['id', 'name', 'age']], { + equal: false, leq: true, join: [[], ['id', 'name', 'age']], meet: [['id'], ['name']], widen: [[], Top], narrow: [['id'], ['name']], concrete: concrete(['id'], ['id', 'name']) + }); + assertAbstractDomain(create, [[], ['id', 'name', 'age']], [['id'], ['name']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: [['id'], ['name']], widen: [[], ['id', 'name', 'age']], narrow: [['id'], ['name', 'age']], concrete: concrete([], ['id'], ['name'], ['id', 'name'], ['age'], ['id', 'age'], ['name', 'age'], ['id', 'name', 'age']) }); - assertAbstractDomain(create, [], Top, { - equal: false, leq: true, join: Top, meet: [], widen: Top, narrow: [], concrete: [] + assertAbstractDomain(create, [[], ['score']], [['id'], ['name', 'age']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age', 'score']], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: concrete([], ['score']) }); - assertAbstractDomain(create, Top, [], { - equal: false, leq: false, join: Top, meet: [], widen: Top, narrow: [], concrete: Top + assertAbstractDomain(create, [['id'], ['name', 'age']], [[], ['score']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age', 'score']], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age']) }); - assertAbstractDomain(create, [], ['id', 'age'], { - equal: false, leq: true, join: ['id', 'age'], meet: [], widen: Top, narrow: [], concrete: [] + assertAbstractDomain(create, [['id'], []], [['id'], ['name', 'age']], { + equal: false, leq: true, join: [['id'], ['name', 'age']], meet: [['id'], []], widen: [['id'], Top], narrow: [['id'], []], concrete: concrete(['id']) }); - assertAbstractDomain(create, ['id', 'age'], [], { - equal: false, leq: false, join: ['id', 'age'], meet: [], widen: ['id', 'age'], narrow: ['id', 'age'], concrete: ['id', 'age'] + assertAbstractDomain(create, [['id'], ['name', 'age']], [['id'], []], { + equal: false, leq: false, join: [['id'], ['name', 'age']], meet: [['id'], []], widen: [['id'], ['name', 'age']], narrow: [['id'], ['name', 'age']], concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age']) }); - assertAbstractDomain(create, ['id', 'age'], ['age', 'id'], { - equal: true, leq: true, join: ['id', 'age'], meet: ['id', 'age'], widen: ['id', 'age'], narrow: ['id', 'age'], concrete: ['id', 'age'] + assertAbstractDomain(create, [['id'], ['name', 'age', 'score']], [['id', 'name'], ['age']], { + equal: false, leq: false, join: [['id'], ['name', 'age', 'score']], meet: [['id', 'name'], ['age']], widen: [['id'], ['name', 'age', 'score']], narrow: [['id'], ['name', 'age', 'score']], concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age'], ['id', 'score'], ['id', 'name', 'score'], ['id', 'age', 'score'], ['id', 'name', 'age', 'score']) }); - assertAbstractDomain(create, ['id', 'age'], ['id', 'age', 'score'], { - equal: false, leq: true, join: ['id', 'age', 'score'], meet: ['id', 'age'], widen: Top, narrow: ['id', 'age'], concrete: ['id', 'age'] + assertAbstractDomain(create, [['id', 'name'], ['age']], [['id'], ['name', 'age', 'score']], { + equal: false, leq: true, join: [['id'], ['name', 'age', 'score']], meet: [['id', 'name'], ['age']], widen: [[], Top], narrow: [['id', 'name'], ['age']], concrete: concrete(['id', 'name'], ['id', 'name', 'age']) }); - assertAbstractDomain(create, ['id', 'age', 'score'], ['id', 'age'], { - equal: false, leq: false, join: ['id', 'age', 'score'], meet: ['id', 'age'], widen: ['id', 'age', 'score'], narrow: ['id', 'age', 'score'], concrete: ['id', 'age', 'score'] + assertAbstractDomain(create, [['id'], []], [[], ['name', 'age']], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: concrete(['id']) }); - assertAbstractDomain(create, ['id', 'age', 'score'], ['id', 'category'], { - equal: false, leq: false, join: ['id', 'age', 'score', 'category'], meet: ['id'], widen: Top, narrow: ['id', 'age', 'score'], concrete: ['id', 'age', 'score'] + assertAbstractDomain(create, [[], ['name', 'age']], [['id'], []], { + equal: false, leq: false, join: [[], ['id', 'name', 'age']], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: concrete([], ['name'], ['age'], ['name', 'age']) }); - assertAbstractDomain(create, ['id', 'category'], ['id', 'age', 'score'], { - equal: false, leq: false, join: ['id', 'age', 'score', 'category'], meet: ['id'], widen: Top, narrow: ['id', 'category'], concrete: ['id', 'category'] + assertAbstractDomain(create, [['id', 'name'], Top], [['id'], []], { + equal: false, leq: false, join: [['id'], Top], meet: Bottom, widen: [[], Top], narrow: Bottom, concrete: Top, abstract: [[], Top] }); - assertAbstractDomain(create, ['id', 'age'], Top, { - equal: false, leq: true, join: Top, meet: ['id', 'age'], widen: Top, narrow: ['id', 'age'], concrete: ['id', 'age'] + assertAbstractDomain(create, [['id'], []], [['id', 'name'], Top], { + equal: false, leq: false, join: [['id'], Top], meet: Bottom, widen: [['id'], Top], narrow: Bottom, concrete: concrete(['id']) }); - assertAbstractDomain(create, Top, ['id', 'age'], { - equal: false, leq: false, join: Top, meet: ['id', 'age'], widen: Top, narrow: ['id', 'age'], concrete: Top + assertAbstractDomain(create, [['id'], Top], [['id', 'name'], ['age']], { + equal: false, leq: false, join: [['id'], Top], meet: [['id', 'name'], ['age']], widen: [['id'], Top], narrow: [['id'], ['name', 'age']], concrete: Top, abstract: [[], Top] + }); + assertAbstractDomain(create, [['id', 'name'], ['age']], [['id'], Top], { + equal: false, leq: true, join: [['id'], Top], meet: [['id', 'name'], ['age']], widen: [[], Top], narrow: [['id', 'name'], ['age']], concrete: concrete(['id', 'name'], ['id', 'name', 'age']) + }); + assertAbstractDomain(create, [[], Top], [['id'], ['name', 'age']], { + equal: false, leq: false, join: [[], Top], meet: [['id'], ['name', 'age']], widen: [[], Top], narrow: [['id'], ['name', 'age']], concrete: Top, abstract: [[], Top] + }); + assertAbstractDomain(create, [['id'], ['name', 'age']], [[], Top], { + equal: false, leq: true, join: [[], Top], meet: [['id'], ['name', 'age']], widen: [[], Top], narrow: [['id'], ['name', 'age']], concrete: concrete(['id'], ['id', 'name'], ['id', 'age'], ['id', 'name', 'age']) }); }); - interface IntervalTest { - name: string, - create: (value: AbstractDomainValue) => AnyAbstractDomain, - min: number, - max: number - } - - const intervalTests: IntervalTest[] = [{ + const intervalTests = [{ name: 'Interval Domain', create: (value: AbstractDomainValue) => new IntervalDomain(value), min: IntervalTop[0], @@ -138,11 +229,17 @@ describe('Abstract Domains', () => { assertAbstractDomain(create, [2, 8], [2, 8], { equal: true, leq: true, join: [2, 8], meet: [2, 8], widen: [2, 8], narrow: [2, 8], concrete: [2, 3, 4, 5, 6, 7, 8] }); + assertAbstractDomain(create, [0, 4], [2, 8], { + equal: false, leq: false, join: [0, 8], meet: [2, 4], widen: [0, max], narrow: [min === 0 ? 2 : 0, 4], concrete: [0, 1, 2, 3, 4] + }); assertAbstractDomain(create, [2, 8], [0, 4], { equal: false, leq: false, join: [0, 8], meet: [2, 4], widen: [min, 8], narrow: [2, 8], concrete: [2, 3, 4, 5, 6, 7, 8] }); - assertAbstractDomain(create, [0, 4], [2, 8], { - equal: false, leq: false, join: [0, 8], meet: [2, 4], widen: [0, max], narrow: [min === 0 ? 2 : 0, 4], concrete: [0, 1, 2, 3, 4] + assertAbstractDomain(create, [0, 0], [1, 3], { + equal: false, leq: false, join: [0, 3], meet: Bottom, widen: [0, max], narrow: Bottom, concrete: [0] + }); + assertAbstractDomain(create, [1, 3], [0, 0], { + equal: false, leq: false, join: [0, 3], meet: Bottom, widen: [min, 3], narrow: Bottom, concrete: [1, 2, 3] }); assertAbstractDomain(create, [2, 8], [4, 12], { equal: false, leq: false, join: [2, 12], meet: [4, 8], widen: [2, max], narrow: [2, 8], concrete: [2, 3, 4, 5, 6, 7, 8] diff --git a/test/functionality/benchmark/slicer.test.ts b/test/functionality/benchmark/slicer.test.ts index 6b22db47b7b..2bf252ea802 100644 --- a/test/functionality/benchmark/slicer.test.ts +++ b/test/functionality/benchmark/slicer.test.ts @@ -295,33 +295,36 @@ e <- 5`, numberOfNonDataFrameFiles: 0, numberOfResultConstraints: 2, numberOfResultingValues: 2, - numberOfResultingTop: 0, numberOfResultingBottom: 0, + numberOfResultingTop: 0, numberOfOperationNodes: 1, numberOfValueNodes: 2, numberOfEntriesPerNode: { min: 1, max: 2, median: 2, mean: 1.5, std: 0.5, total: 3 }, numberOfOperations: 1, numberOfTotalValues: 1, - numberOfTotalTop: 0, numberOfTotalBottom: 0, + numberOfTotalTop: 0, inferredColNames: { min: 2, max: 2, median: 2, mean: 2, std: 0, total: 2 }, + approxRangeColNames: { min: 0, max: 0, median: 0, mean: 0, std: 0, total: 0 }, + numberOfColNamesExact: 1, numberOfColNamesValues: 1, - numberOfColNamesTop: 0, numberOfColNamesBottom: 0, + numberOfColNamesInfinite: 0, + numberOfColNamesTop: 0, inferredColCount: { min: 2, max: 2, median: 2, mean: 2, std: 0, total: 2 }, + approxRangeColCount: { min: 0, max: 0, median: 0, mean: 0, std: 0, total: 0 }, numberOfColCountExact: 1, numberOfColCountValues: 1, - numberOfColCountTop: 0, - numberOfColCountInfinite: 0, numberOfColCountBottom: 0, - approxRangeColCount: { min: 0, max: 0, median: 0, mean: 0, std: 0, total: 0 }, + numberOfColCountInfinite: 0, + numberOfColCountTop: 0, inferredRowCount: { min: 3, max: 3, median: 3, mean: 3, std: 0, total: 3 }, + approxRangeRowCount: { min: 0, max: 0, median: 0, mean: 0, std: 0, total: 0 }, numberOfRowCountExact: 1, numberOfRowCountValues: 1, - numberOfRowCountTop: 0, - numberOfRowCountInfinite: 0, numberOfRowCountBottom: 0, - approxRangeRowCount: { min: 0, max: 0, median: 0, mean: 0, std: 0, total: 0 }, + numberOfRowCountInfinite: 0, + numberOfRowCountTop: 0, perOperationNumber: new Map([...DataFrameOperationNames.map<[DataFrameOperationName, number]>(name => [name, 0]), ['create', 1]]) }, statInfo); });