Source code for node_cartesian_product

# This file is part of Sympathy for Data.
# Copyright (c) 2017, Combine Control Systems AB
#
# Sympathy for Data is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Sympathy for Data is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Sympathy for Data.  If not, see <http://www.gnu.org/licenses/>.
from sympathy.api import node as synode
from sympathy.api.nodeconfig import Port, Ports, Tag, Tags
# from sympathy.api.exceptions import SyDataError

import numpy as np


common_docs = """
Cartesian product of a number of tables create a new table
containing all combinations of rows of the inputs. This output have
one column for each unique column in the input tables. For example two
tables with A and B columns of length N and M each create a new table
of length N * M and containing A + B columns. It is an error to have
duplicate column names.
"""


[docs]class CartesianProductTable(synode.Node): __doc__ = common_docs name = 'Cartesian Product Table' description = 'Cartesian product of two or more Tables into a single Table.' nodeid = 'se.combine.sympathy.data.table.cartesian_product_table' author = "Mathias Broxvall" version = '1.0' icon = 'cartesian_product.svg' tags = Tags(Tag.DataProcessing.TransformStructure) related = ['se.combine.sympathy.data.table.cartesian_product_tables'] parameters = {} parameter_root = synode.parameters(parameters) inputs = Ports([ Port.Custom('table', 'Input Tables', name='in', n=(2, None))]) outputs = Ports([ Port.Table('Table with cartesian product of inputs', name='out')]) def execute(self, node_context): """Execute""" inputs = node_context.input.group('in') output = node_context.output['out'] lens = [i.number_of_rows() for i in inputs] for i in range(len(list(inputs))): left = int(np.product(lens[:i])) right = int(np.product(lens[i+1:])) for column in inputs[i].cols(): data = [val for val in column.data for _ in range(right)] * left output.set_column_from_array(column.name, np.array(data))
[docs]class CartesianProductTables(synode.Node): __doc__ = common_docs name = 'Cartesian Product Tables' description = 'Cartesian product of a list of Tables into a single Table.' nodeid = 'se.combine.sympathy.data.table.cartesian_product_tables' author = "Mathias Broxvall" version = '1.0' icon = 'cartesian_product.svg' tags = Tags(Tag.DataProcessing.TransformStructure) related = ['se.combine.sympathy.data.table.cartesian_product_table'] parameters = {} parameter_root = synode.parameters(parameters) inputs = Ports([ Port.Custom('[table]', 'List of input tables', name='in')]) outputs = Ports([ Port.Table('Table with cartesian product of inputs', name='out')]) def execute(self, node_context): """Execute""" inputs = node_context.input['in'] output = node_context.output['out'] lens = [i.number_of_rows() for i in inputs] for i in range(len(list(inputs))): left = int(np.product(lens[:i])) right = int(np.product(lens[i+1:])) for column in inputs[i].cols(): data = [val for val in column.data for _ in range(right)] * left output.set_column_from_array(column.name, np.array(data))