ClickHouse/src/Functions/vectorFunctions.cpp

1328 lines
53 KiB
C++
Raw Normal View History

#include <Columns/ColumnTuple.h>
#include <DataTypes/DataTypeArray.h>
#include <DataTypes/DataTypeTuple.h>
#include <DataTypes/DataTypesNumber.h>
2021-09-23 12:54:00 +00:00
#include <DataTypes/DataTypeNothing.h>
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionHelpers.h>
2021-09-09 12:41:22 +00:00
#include <Functions/ITupleFunction.h>
#include <Functions/castTypeToEither.h>
#include "Functions/IFunction.h"
namespace DB
{
namespace ErrorCodes
{
2021-08-20 21:14:26 +00:00
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
2021-09-23 12:54:00 +00:00
extern const int ILLEGAL_COLUMN;
extern const int ARGUMENT_OUT_OF_BOUND;
}
2021-09-09 12:41:22 +00:00
struct PlusName { static constexpr auto name = "plus"; };
struct MinusName { static constexpr auto name = "minus"; };
struct MultiplyName { static constexpr auto name = "multiply"; };
struct DivideName { static constexpr auto name = "divide"; };
2021-08-30 12:52:00 +00:00
2021-09-09 12:41:22 +00:00
struct L1Label { static constexpr auto name = "1"; };
struct L2Label { static constexpr auto name = "2"; };
2022-06-28 19:27:53 +00:00
struct L2SquaredLabel { static constexpr auto name = "2Squared"; };
2021-09-09 12:41:22 +00:00
struct LinfLabel { static constexpr auto name = "inf"; };
struct LpLabel { static constexpr auto name = "p"; };
2021-08-30 12:52:00 +00:00
2021-08-27 15:02:37 +00:00
/// str starts from the lowercase letter; not constexpr due to the compiler version
2021-09-09 12:41:22 +00:00
/*constexpr*/ std::string makeFirstLetterUppercase(const std::string& str)
2021-08-27 15:02:37 +00:00
{
std::string res(str);
res[0] += 'A' - 'a';
return res;
}
2021-09-09 12:41:22 +00:00
template <class FuncName>
class FunctionTupleOperator : public ITupleFunction
2021-08-26 18:17:44 +00:00
{
2021-08-25 14:56:31 +00:00
public:
2021-08-27 15:02:37 +00:00
/// constexpr cannot be used due to std::string has not constexpr constructor in this compiler version
2021-09-09 12:41:22 +00:00
static inline auto name = "tuple" + makeFirstLetterUppercase(FuncName::name);
2021-08-27 15:02:37 +00:00
2021-09-09 12:41:22 +00:00
explicit FunctionTupleOperator(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-27 15:44:04 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionTupleOperator>(context_); }
2021-08-27 15:02:37 +00:00
String getName() const override { return name; }
2021-08-25 14:56:31 +00:00
size_t getNumberOfArguments() const override { return 2; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * left_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto * right_tuple = checkAndGetDataType<DataTypeTuple>(arguments[1].type.get());
if (!left_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-25 14:56:31 +00:00
getName(), arguments[0].type->getName());
if (!right_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 1 of function {} should be tuple, got {}",
2021-08-25 14:56:31 +00:00
getName(), arguments[1].type->getName());
const auto & left_types = left_tuple->getElements();
const auto & right_types = right_tuple->getElements();
Columns left_elements;
Columns right_elements;
if (arguments[0].column)
left_elements = getTupleElements(*arguments[0].column);
if (arguments[1].column)
right_elements = getTupleElements(*arguments[1].column);
if (left_types.size() != right_types.size())
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Expected tuples of the same size as arguments of function {}. Got {} and {}",
getName(), arguments[0].type->getName(), arguments[1].type->getName());
size_t tuple_size = left_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
2021-09-09 12:41:22 +00:00
auto func = FunctionFactory::instance().get(FuncName::name, context);
2021-08-25 14:56:31 +00:00
DataTypes types(tuple_size);
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName left{left_elements.empty() ? nullptr : left_elements[i], left_types[i], {}};
ColumnWithTypeAndName right{right_elements.empty() ? nullptr : right_elements[i], right_types[i], {}};
auto elem_func = func->build(ColumnsWithTypeAndName{left, right});
types[i] = elem_func->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
return std::make_shared<DataTypeTuple>(types);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * left_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto * right_tuple = checkAndGetDataType<DataTypeTuple>(arguments[1].type.get());
const auto & left_types = left_tuple->getElements();
const auto & right_types = right_tuple->getElements();
auto left_elements = getTupleElements(*arguments[0].column);
auto right_elements = getTupleElements(*arguments[1].column);
size_t tuple_size = left_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
2021-09-09 12:41:22 +00:00
auto func = FunctionFactory::instance().get(FuncName::name, context);
2021-08-25 14:56:31 +00:00
Columns columns(tuple_size);
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName left{left_elements[i], left_types[i], {}};
ColumnWithTypeAndName right{right_elements[i], right_types[i], {}};
auto elem_func = func->build(ColumnsWithTypeAndName{left, right});
2021-08-27 13:14:32 +00:00
columns[i] = elem_func->execute({left, right}, elem_func->getResultType(), input_rows_count)
->convertToFullColumnIfConst();
2021-08-25 14:56:31 +00:00
}
return ColumnTuple::create(columns);
}
};
2021-09-09 12:41:22 +00:00
using FunctionTuplePlus = FunctionTupleOperator<PlusName>;
2021-09-09 12:41:22 +00:00
using FunctionTupleMinus = FunctionTupleOperator<MinusName>;
2021-09-09 12:41:22 +00:00
using FunctionTupleMultiply = FunctionTupleOperator<MultiplyName>;
2021-09-09 12:41:22 +00:00
using FunctionTupleDivide = FunctionTupleOperator<DivideName>;
2021-09-09 12:41:22 +00:00
class FunctionTupleNegate : public ITupleFunction
{
public:
2021-08-25 14:02:04 +00:00
static constexpr auto name = "tupleNegate";
2021-09-09 12:41:22 +00:00
explicit FunctionTupleNegate(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-25 14:02:04 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionTupleNegate>(context_); }
String getName() const override { return name; }
2021-08-25 14:02:04 +00:00
size_t getNumberOfArguments() const override { return 1; }
2021-08-20 16:23:51 +00:00
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
2021-08-25 14:02:04 +00:00
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
2021-08-25 14:02:04 +00:00
if (!cur_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
getName(), arguments[0].type->getName());
2021-08-25 14:02:04 +00:00
const auto & cur_types = cur_tuple->getElements();
2021-08-25 14:02:04 +00:00
Columns cur_elements;
if (arguments[0].column)
2021-08-25 14:02:04 +00:00
cur_elements = getTupleElements(*arguments[0].column);
2021-08-25 14:02:04 +00:00
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
2021-08-25 14:02:04 +00:00
auto negate = FunctionFactory::instance().get("negate", context);
DataTypes types(tuple_size);
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
2021-08-25 14:02:04 +00:00
ColumnWithTypeAndName cur{cur_elements.empty() ? nullptr : cur_elements[i], cur_types[i], {}};
auto elem_negate = negate->build(ColumnsWithTypeAndName{cur});
types[i] = elem_negate->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
return std::make_shared<DataTypeTuple>(types);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
2021-08-25 14:02:04 +00:00
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto & cur_types = cur_tuple->getElements();
auto cur_elements = getTupleElements(*arguments[0].column);
2021-08-25 14:02:04 +00:00
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
2021-08-25 14:02:04 +00:00
auto negate = FunctionFactory::instance().get("negate", context);
Columns columns(tuple_size);
for (size_t i = 0; i < tuple_size; ++i)
{
2021-08-25 14:02:04 +00:00
ColumnWithTypeAndName cur{cur_elements[i], cur_types[i], {}};
2021-08-27 15:44:04 +00:00
auto elem_negate = negate->build(ColumnsWithTypeAndName{cur});
columns[i] = elem_negate->execute({cur}, elem_negate->getResultType(), input_rows_count)
->convertToFullColumnIfConst();
}
return ColumnTuple::create(columns);
}
};
2021-09-09 12:41:22 +00:00
template <class FuncName>
class FunctionTupleOperatorByNumber : public ITupleFunction
2021-08-27 15:44:04 +00:00
{
public:
/// constexpr cannot be used due to std::string has not constexpr constructor in this compiler version
2021-09-09 12:41:22 +00:00
static inline auto name = "tuple" + makeFirstLetterUppercase(FuncName::name) + "ByNumber";
2021-08-27 15:44:04 +00:00
2021-09-09 12:41:22 +00:00
explicit FunctionTupleOperatorByNumber(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-27 15:44:04 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionTupleOperatorByNumber>(context_); }
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 2; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
if (!cur_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-27 15:44:04 +00:00
getName(), arguments[0].type->getName());
const auto & cur_types = cur_tuple->getElements();
Columns cur_elements;
if (arguments[0].column)
cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
const auto & p_column = arguments[1];
2021-09-09 12:41:22 +00:00
auto func = FunctionFactory::instance().get(FuncName::name, context);
2021-08-27 15:44:04 +00:00
DataTypes types(tuple_size);
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName cur{cur_elements.empty() ? nullptr : cur_elements[i], cur_types[i], {}};
auto elem_func = func->build(ColumnsWithTypeAndName{cur, p_column});
types[i] = elem_func->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
return std::make_shared<DataTypeTuple>(types);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto & cur_types = cur_tuple->getElements();
auto cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
const auto & p_column = arguments[1];
2021-09-09 12:41:22 +00:00
auto func = FunctionFactory::instance().get(FuncName::name, context);
2021-08-27 15:44:04 +00:00
Columns columns(tuple_size);
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName cur{cur_elements[i], cur_types[i], {}};
auto elem_func = func->build(ColumnsWithTypeAndName{cur, p_column});
columns[i] = elem_func->execute({cur, p_column}, elem_func->getResultType(), input_rows_count)
->convertToFullColumnIfConst();
2021-08-27 15:44:04 +00:00
}
return ColumnTuple::create(columns);
}
};
2021-09-09 12:41:22 +00:00
using FunctionTupleMultiplyByNumber = FunctionTupleOperatorByNumber<MultiplyName>;
2021-08-27 15:44:04 +00:00
2021-09-09 12:41:22 +00:00
using FunctionTupleDivideByNumber = FunctionTupleOperatorByNumber<DivideName>;
2021-08-27 15:44:04 +00:00
2021-09-09 12:41:22 +00:00
class FunctionDotProduct : public ITupleFunction
2021-08-23 13:41:20 +00:00
{
public:
2021-08-25 14:02:04 +00:00
static constexpr auto name = "dotProduct";
2021-08-23 13:41:20 +00:00
2021-09-09 12:41:22 +00:00
explicit FunctionDotProduct(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-25 14:02:04 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionDotProduct>(context_); }
2021-08-23 13:41:20 +00:00
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 2; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * left_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto * right_tuple = checkAndGetDataType<DataTypeTuple>(arguments[1].type.get());
if (!left_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-23 13:41:20 +00:00
getName(), arguments[0].type->getName());
if (!right_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 1 of function {} should be tuple, got {}",
2021-08-23 13:41:20 +00:00
getName(), arguments[1].type->getName());
const auto & left_types = left_tuple->getElements();
const auto & right_types = right_tuple->getElements();
Columns left_elements;
Columns right_elements;
if (arguments[0].column)
left_elements = getTupleElements(*arguments[0].column);
if (arguments[1].column)
right_elements = getTupleElements(*arguments[1].column);
if (left_types.size() != right_types.size())
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Expected tuples of the same size as arguments of function {}. Got {} and {}",
getName(), arguments[0].type->getName(), arguments[1].type->getName());
size_t tuple_size = left_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
2021-08-25 14:02:04 +00:00
auto multiply = FunctionFactory::instance().get("multiply", context);
auto plus = FunctionFactory::instance().get("plus", context);
DataTypePtr res_type;
2021-08-23 13:41:20 +00:00
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName left{left_elements.empty() ? nullptr : left_elements[i], left_types[i], {}};
ColumnWithTypeAndName right{right_elements.empty() ? nullptr : right_elements[i], right_types[i], {}};
2021-08-25 14:02:04 +00:00
auto elem_multiply = multiply->build(ColumnsWithTypeAndName{left, right});
if (i == 0)
{
res_type = elem_multiply->getResultType();
continue;
}
ColumnWithTypeAndName left_type{res_type, {}};
ColumnWithTypeAndName right_type{elem_multiply->getResultType(), {}};
auto plus_elem = plus->build({left_type, right_type});
res_type = plus_elem->getResultType();
2021-08-23 13:41:20 +00:00
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
2021-08-25 14:02:04 +00:00
return res_type;
2021-08-23 13:41:20 +00:00
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * left_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto * right_tuple = checkAndGetDataType<DataTypeTuple>(arguments[1].type.get());
const auto & left_types = left_tuple->getElements();
const auto & right_types = right_tuple->getElements();
auto left_elements = getTupleElements(*arguments[0].column);
auto right_elements = getTupleElements(*arguments[1].column);
size_t tuple_size = left_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
2021-08-25 14:02:04 +00:00
auto multiply = FunctionFactory::instance().get("multiply", context);
auto plus = FunctionFactory::instance().get("plus", context);
ColumnWithTypeAndName res;
2021-08-23 13:41:20 +00:00
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName left{left_elements[i], left_types[i], {}};
ColumnWithTypeAndName right{right_elements[i], right_types[i], {}};
2021-08-25 14:02:04 +00:00
auto elem_multiply = multiply->build(ColumnsWithTypeAndName{left, right});
2021-08-23 13:41:20 +00:00
2021-08-25 14:02:04 +00:00
ColumnWithTypeAndName column;
column.type = elem_multiply->getResultType();
column.column = elem_multiply->execute({left, right}, column.type, input_rows_count);
2021-08-23 13:41:20 +00:00
2021-08-25 14:02:04 +00:00
if (i == 0)
2021-08-23 13:41:20 +00:00
{
2021-08-25 14:02:04 +00:00
res = std::move(column);
2021-08-23 13:41:20 +00:00
}
2021-08-25 14:02:04 +00:00
else
2021-08-23 13:41:20 +00:00
{
2021-08-25 14:02:04 +00:00
auto plus_elem = plus->build({res, column});
auto res_type = plus_elem->getResultType();
res.column = plus_elem->execute({res, column}, res_type, input_rows_count);
res.type = res_type;
2021-08-23 13:41:20 +00:00
}
}
2021-08-25 14:02:04 +00:00
return res.column;
2021-08-23 13:41:20 +00:00
}
};
2021-08-30 12:52:00 +00:00
/// this is for convenient usage in LNormalize
2021-09-09 12:41:22 +00:00
template <class FuncLabel>
class FunctionLNorm : public ITupleFunction {};
2021-08-30 12:52:00 +00:00
template <>
2021-09-09 12:41:22 +00:00
class FunctionLNorm<L1Label> : public ITupleFunction
2021-08-25 14:56:31 +00:00
{
public:
static constexpr auto name = "L1Norm";
2021-09-09 12:41:22 +00:00
explicit FunctionLNorm(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 12:52:00 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLNorm>(context_); }
2021-08-25 14:56:31 +00:00
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 1; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
if (!cur_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-25 14:56:31 +00:00
getName(), arguments[0].type->getName());
const auto & cur_types = cur_tuple->getElements();
Columns cur_elements;
if (arguments[0].column)
cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
auto abs = FunctionFactory::instance().get("abs", context);
auto plus = FunctionFactory::instance().get("plus", context);
DataTypePtr res_type;
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName cur{cur_elements.empty() ? nullptr : cur_elements[i], cur_types[i], {}};
auto elem_abs = abs->build(ColumnsWithTypeAndName{cur});
if (i == 0)
{
res_type = elem_abs->getResultType();
continue;
}
ColumnWithTypeAndName left_type{res_type, {}};
ColumnWithTypeAndName right_type{elem_abs->getResultType(), {}};
auto plus_elem = plus->build({left_type, right_type});
res_type = plus_elem->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
return res_type;
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto & cur_types = cur_tuple->getElements();
auto cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
auto abs = FunctionFactory::instance().get("abs", context);
auto plus = FunctionFactory::instance().get("plus", context);
ColumnWithTypeAndName res;
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName cur{cur_elements[i], cur_types[i], {}};
auto elem_abs = abs->build(ColumnsWithTypeAndName{cur});
ColumnWithTypeAndName column;
column.type = elem_abs->getResultType();
column.column = elem_abs->execute({cur}, column.type, input_rows_count);
if (i == 0)
{
res = std::move(column);
}
else
{
auto plus_elem = plus->build({res, column});
auto res_type = plus_elem->getResultType();
res.column = plus_elem->execute({res, column}, res_type, input_rows_count);
res.type = res_type;
}
}
return res.column;
}
};
2021-09-09 12:41:22 +00:00
using FunctionL1Norm = FunctionLNorm<L1Label>;
2021-08-25 14:56:31 +00:00
2021-08-30 12:52:00 +00:00
template <>
2022-06-30 11:39:31 +00:00
class FunctionLNorm<L2SquaredLabel> : public ITupleFunction
2021-08-25 15:44:35 +00:00
{
public:
2022-06-30 11:39:31 +00:00
static constexpr auto name = "L2SquaredNorm";
2021-08-25 15:44:35 +00:00
2021-09-09 12:41:22 +00:00
explicit FunctionLNorm(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 12:52:00 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLNorm>(context_); }
2021-08-25 15:44:35 +00:00
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 1; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
if (!cur_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-25 15:44:35 +00:00
getName(), arguments[0].type->getName());
const auto & cur_types = cur_tuple->getElements();
Columns cur_elements;
if (arguments[0].column)
cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
auto multiply = FunctionFactory::instance().get("multiply", context);
auto plus = FunctionFactory::instance().get("plus", context);
DataTypePtr res_type;
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName cur{cur_elements.empty() ? nullptr : cur_elements[i], cur_types[i], {}};
auto elem_multiply = multiply->build(ColumnsWithTypeAndName{cur, cur});
if (i == 0)
{
res_type = elem_multiply->getResultType();
continue;
}
ColumnWithTypeAndName left_type{res_type, {}};
ColumnWithTypeAndName right_type{elem_multiply->getResultType(), {}};
auto plus_elem = plus->build({left_type, right_type});
res_type = plus_elem->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
2022-06-30 11:39:31 +00:00
return res_type;
2021-08-25 15:44:35 +00:00
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto & cur_types = cur_tuple->getElements();
auto cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
auto multiply = FunctionFactory::instance().get("multiply", context);
auto plus = FunctionFactory::instance().get("plus", context);
ColumnWithTypeAndName res;
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName cur{cur_elements[i], cur_types[i], {}};
auto elem_multiply = multiply->build(ColumnsWithTypeAndName{cur, cur});
ColumnWithTypeAndName column;
column.type = elem_multiply->getResultType();
column.column = elem_multiply->execute({cur, cur}, column.type, input_rows_count);
if (i == 0)
{
res = std::move(column);
}
else
{
auto plus_elem = plus->build({res, column});
auto res_type = plus_elem->getResultType();
res.column = plus_elem->execute({res, column}, res_type, input_rows_count);
res.type = res_type;
}
}
2022-06-30 11:39:31 +00:00
return res.column;
2021-08-25 15:44:35 +00:00
}
};
2022-06-30 11:39:31 +00:00
using FunctionL2SquaredNorm = FunctionLNorm<L2SquaredLabel>;
2021-08-25 15:44:35 +00:00
2022-06-28 19:27:53 +00:00
template <>
2022-06-30 11:39:31 +00:00
class FunctionLNorm<L2Label> : public FunctionL2SquaredNorm
2022-06-28 19:27:53 +00:00
{
2022-06-30 11:39:31 +00:00
private:
using Base = FunctionL2SquaredNorm;
2022-06-28 19:27:53 +00:00
public:
2022-06-30 11:39:31 +00:00
static constexpr auto name = "L2Norm";
2022-06-28 19:27:53 +00:00
2022-06-30 11:39:31 +00:00
explicit FunctionLNorm(ContextPtr context_) : Base(context_) {}
2022-06-28 19:27:53 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLNorm>(context_); }
String getName() const override { return name; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
if (!cur_tuple)
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
getName(), arguments[0].type->getName());
const auto & cur_types = cur_tuple->getElements();
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
2022-06-30 11:39:31 +00:00
auto sqrt = FunctionFactory::instance().get("sqrt", context);
return sqrt->build({ColumnWithTypeAndName{Base::getReturnTypeImpl(arguments), {}}})->getResultType();
2022-06-28 19:27:53 +00:00
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
auto cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
2022-06-30 11:39:31 +00:00
ColumnWithTypeAndName squared_res;
squared_res.type = Base::getReturnTypeImpl(arguments);
squared_res.column = Base::executeImpl(arguments, squared_res.type, input_rows_count);
2022-06-28 19:27:53 +00:00
2022-06-30 11:39:31 +00:00
auto sqrt = FunctionFactory::instance().get("sqrt", context);
auto sqrt_elem = sqrt->build({squared_res});
return sqrt_elem->execute({squared_res}, sqrt_elem->getResultType(), input_rows_count);
2022-06-28 19:27:53 +00:00
}
};
2022-06-30 11:39:31 +00:00
using FunctionL2Norm = FunctionLNorm<L2Label>;
2022-06-28 19:27:53 +00:00
2021-08-30 12:52:00 +00:00
template <>
2021-09-09 12:41:22 +00:00
class FunctionLNorm<LinfLabel> : public ITupleFunction
2021-08-26 12:34:46 +00:00
{
public:
static constexpr auto name = "LinfNorm";
2021-09-09 12:41:22 +00:00
explicit FunctionLNorm(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 12:52:00 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLNorm>(context_); }
2021-08-26 12:34:46 +00:00
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 1; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
if (!cur_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-26 12:34:46 +00:00
getName(), arguments[0].type->getName());
const auto & cur_types = cur_tuple->getElements();
Columns cur_elements;
if (arguments[0].column)
cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
auto abs = FunctionFactory::instance().get("abs", context);
auto max = FunctionFactory::instance().get("max2", context);
DataTypePtr res_type;
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName cur{cur_elements.empty() ? nullptr : cur_elements[i], cur_types[i], {}};
auto elem_abs = abs->build(ColumnsWithTypeAndName{cur});
if (i == 0)
{
res_type = elem_abs->getResultType();
continue;
}
ColumnWithTypeAndName left_type{res_type, {}};
ColumnWithTypeAndName right_type{elem_abs->getResultType(), {}};
auto max_elem = max->build({left_type, right_type});
res_type = max_elem->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
return res_type;
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto & cur_types = cur_tuple->getElements();
auto cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
auto abs = FunctionFactory::instance().get("abs", context);
auto max = FunctionFactory::instance().get("max2", context);
ColumnWithTypeAndName res;
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName cur{cur_elements[i], cur_types[i], {}};
auto elem_abs = abs->build(ColumnsWithTypeAndName{cur});
ColumnWithTypeAndName column;
column.type = elem_abs->getResultType();
column.column = elem_abs->execute({cur}, column.type, input_rows_count);
if (i == 0)
{
res = std::move(column);
}
else
{
auto max_elem = max->build({res, column});
auto res_type = max_elem->getResultType();
res.column = max_elem->execute({res, column}, res_type, input_rows_count);
res.type = res_type;
}
}
return res.column;
}
};
2021-09-09 12:41:22 +00:00
using FunctionLinfNorm = FunctionLNorm<LinfLabel>;
2021-08-26 12:34:46 +00:00
2021-08-30 12:52:00 +00:00
template <>
2021-09-09 12:41:22 +00:00
class FunctionLNorm<LpLabel> : public ITupleFunction
2021-08-26 18:17:44 +00:00
{
public:
static constexpr auto name = "LpNorm";
2021-09-09 12:41:22 +00:00
explicit FunctionLNorm(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 12:52:00 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLNorm>(context_); }
2021-08-26 18:17:44 +00:00
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 2; }
2021-09-16 12:43:10 +00:00
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
2021-08-26 18:17:44 +00:00
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
if (!cur_tuple)
2021-09-09 12:41:22 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument 0 of function {} should be tuple, got {}",
2021-08-26 18:17:44 +00:00
getName(), arguments[0].type->getName());
const auto & cur_types = cur_tuple->getElements();
Columns cur_elements;
if (arguments[0].column)
cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_types.size();
if (tuple_size == 0)
return std::make_shared<DataTypeUInt8>();
const auto & p_column = arguments[1];
auto abs = FunctionFactory::instance().get("abs", context);
auto pow = FunctionFactory::instance().get("pow", context);
auto plus = FunctionFactory::instance().get("plus", context);
DataTypePtr res_type;
for (size_t i = 0; i < tuple_size; ++i)
{
try
{
ColumnWithTypeAndName cur{cur_elements.empty() ? nullptr : cur_elements[i], cur_types[i], {}};
auto elem_abs = abs->build(ColumnsWithTypeAndName{cur});
cur.type = elem_abs->getResultType();
2021-08-30 13:55:38 +00:00
cur.column = cur.type->createColumn();
2021-08-26 18:17:44 +00:00
auto elem_pow = pow->build(ColumnsWithTypeAndName{cur, p_column});
if (i == 0)
{
res_type = elem_pow->getResultType();
continue;
}
ColumnWithTypeAndName left_type{res_type, {}};
ColumnWithTypeAndName right_type{elem_pow->getResultType(), {}};
auto plus_elem = plus->build({left_type, right_type});
res_type = plus_elem->getResultType();
}
catch (DB::Exception & e)
{
e.addMessage("While executing function {} for tuple element {}", getName(), i);
throw;
}
}
2021-09-16 12:43:10 +00:00
ColumnWithTypeAndName inv_p_column{std::make_shared<DataTypeFloat64>(), {}};
2021-08-26 18:17:44 +00:00
return pow->build({ColumnWithTypeAndName{res_type, {}}, inv_p_column})->getResultType();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const auto * cur_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());
const auto & cur_types = cur_tuple->getElements();
auto cur_elements = getTupleElements(*arguments[0].column);
size_t tuple_size = cur_elements.size();
if (tuple_size == 0)
return DataTypeUInt8().createColumnConstWithDefaultValue(input_rows_count);
const auto & p_column = arguments[1];
2021-09-16 12:43:10 +00:00
if (!isColumnConst(*p_column.column) && p_column.column->size() != 1)
throw Exception{"Second argument for function " + getName() + " must be either constant Float64 or constant UInt", ErrorCodes::ILLEGAL_COLUMN};
2021-09-16 12:43:10 +00:00
double p;
if (isFloat(p_column.column->getDataType()))
p = p_column.column->getFloat64(0);
else if (isUnsignedInteger(p_column.column->getDataType()))
p = p_column.column->getUInt(0);
2021-09-16 12:43:10 +00:00
else
throw Exception{"Second argument for function " + getName() + " must be either constant Float64 or constant UInt", ErrorCodes::ILLEGAL_COLUMN};
2022-05-27 16:25:11 +00:00
if (p < 1 || p >= HUGE_VAL)
2021-09-16 12:43:10 +00:00
throw Exception{"Second argument for function " + getName() + " must be not less than one and not be an infinity", ErrorCodes::ARGUMENT_OUT_OF_BOUND};
2021-08-26 18:17:44 +00:00
auto abs = FunctionFactory::instance().get("abs", context);
auto pow = FunctionFactory::instance().get("pow", context);
auto plus = FunctionFactory::instance().get("plus", context);
ColumnWithTypeAndName res;
for (size_t i = 0; i < tuple_size; ++i)
{
ColumnWithTypeAndName cur{cur_elements[i], cur_types[i], {}};
auto elem_abs = abs->build(ColumnsWithTypeAndName{cur});
cur.column = elem_abs->execute({cur}, elem_abs->getResultType(), input_rows_count);
cur.type = elem_abs->getResultType();
auto elem_pow = pow->build(ColumnsWithTypeAndName{cur, p_column});
ColumnWithTypeAndName column;
column.type = elem_pow->getResultType();
column.column = elem_pow->execute({cur, p_column}, column.type, input_rows_count);
if (i == 0)
{
res = std::move(column);
}
else
{
auto plus_elem = plus->build({res, column});
auto res_type = plus_elem->getResultType();
res.column = plus_elem->execute({res, column}, res_type, input_rows_count);
res.type = res_type;
}
}
2021-09-16 12:43:10 +00:00
ColumnWithTypeAndName inv_p_column{DataTypeFloat64().createColumnConst(input_rows_count, 1 / p),
std::make_shared<DataTypeFloat64>(), {}};
2021-08-26 18:17:44 +00:00
auto pow_elem = pow->build({res, inv_p_column});
return pow_elem->execute({res, inv_p_column}, pow_elem->getResultType(), input_rows_count);
}
};
2021-09-09 12:41:22 +00:00
using FunctionLpNorm = FunctionLNorm<LpLabel>;
2021-08-26 18:17:44 +00:00
2021-09-09 12:41:22 +00:00
template <class FuncLabel>
class FunctionLDistance : public ITupleFunction
2021-08-27 13:14:32 +00:00
{
public:
2021-08-27 14:31:11 +00:00
/// constexpr cannot be used due to std::string has not constexpr constructor in this compiler version
2021-09-09 12:41:22 +00:00
static inline auto name = std::string("L") + FuncLabel::name + "Distance";
2021-08-27 14:31:11 +00:00
2021-09-09 12:41:22 +00:00
explicit FunctionLDistance(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 12:52:00 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLDistance>(context_); }
2021-08-27 14:31:11 +00:00
String getName() const override { return name; }
2021-08-27 13:14:32 +00:00
size_t getNumberOfArguments() const override
{
2021-09-09 12:41:22 +00:00
if constexpr (FuncLabel::name[0] == 'p')
2021-08-27 13:14:32 +00:00
return 3;
else
return 2;
}
2021-09-16 12:43:10 +00:00
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override
{
if constexpr (FuncLabel::name[0] == 'p')
return {2};
else
return {};
}
2021-08-27 13:14:32 +00:00
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
FunctionTupleMinus tuple_minus(context);
auto type = tuple_minus.getReturnTypeImpl(arguments);
2021-08-30 13:55:38 +00:00
ColumnWithTypeAndName minus_res{type, {}};
2021-08-27 13:14:32 +00:00
2021-09-09 12:41:22 +00:00
auto func = FunctionFactory::instance().get(std::string("L") + FuncLabel::name + "Norm", context);
if constexpr (FuncLabel::name[0] == 'p')
2021-08-27 13:14:32 +00:00
return func->build({minus_res, arguments[2]})->getResultType();
else
return func->build({minus_res})->getResultType();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
FunctionTupleMinus tuple_minus(context);
auto type = tuple_minus.getReturnTypeImpl(arguments);
auto column = tuple_minus.executeImpl(arguments, DataTypePtr(), input_rows_count);
ColumnWithTypeAndName minus_res{column, type, {}};
2021-09-09 12:41:22 +00:00
auto func = FunctionFactory::instance().get(std::string("L") + FuncLabel::name + "Norm", context);
if constexpr (FuncLabel::name[0] == 'p')
2021-08-27 13:14:32 +00:00
{
auto func_elem = func->build({minus_res, arguments[2]});
return func_elem->execute({minus_res, arguments[2]}, func_elem->getResultType(), input_rows_count);
}
else
{
auto func_elem = func->build({minus_res});
return func_elem->execute({minus_res}, func_elem->getResultType(), input_rows_count);
}
}
};
2021-09-09 12:41:22 +00:00
using FunctionL1Distance = FunctionLDistance<L1Label>;
2021-08-30 12:52:00 +00:00
2021-09-09 12:41:22 +00:00
using FunctionL2Distance = FunctionLDistance<L2Label>;
2021-08-30 12:52:00 +00:00
2022-06-28 19:27:53 +00:00
using FunctionL2SquaredDistance = FunctionLDistance<L2SquaredLabel>;
2021-09-09 12:41:22 +00:00
using FunctionLinfDistance = FunctionLDistance<LinfLabel>;
2021-08-30 12:52:00 +00:00
2021-09-09 12:41:22 +00:00
using FunctionLpDistance = FunctionLDistance<LpLabel>;
2021-08-30 12:52:00 +00:00
2021-09-09 12:41:22 +00:00
template <class FuncLabel>
class FunctionLNormalize : public ITupleFunction
2021-08-30 12:52:00 +00:00
{
public:
/// constexpr cannot be used due to std::string has not constexpr constructor in this compiler version
2021-09-09 12:41:22 +00:00
static inline auto name = std::string("L") + FuncLabel::name + "Normalize";
2021-08-30 12:52:00 +00:00
2021-09-09 12:41:22 +00:00
explicit FunctionLNormalize(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 12:52:00 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionLNormalize>(context_); }
String getName() const override { return name; }
size_t getNumberOfArguments() const override
{
2021-09-09 12:41:22 +00:00
if constexpr (FuncLabel::name[0] == 'p')
2021-08-30 12:52:00 +00:00
return 2;
else
return 1;
}
2021-09-16 12:43:10 +00:00
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override
{
if constexpr (FuncLabel::name[0] == 'p')
return {1};
else
return {};
}
2021-08-30 12:52:00 +00:00
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
2021-09-09 12:41:22 +00:00
FunctionLNorm<FuncLabel> norm(context);
2021-08-30 12:52:00 +00:00
auto type = norm.getReturnTypeImpl(arguments);
2021-08-30 13:55:38 +00:00
ColumnWithTypeAndName norm_res{type, {}};
2021-08-30 12:52:00 +00:00
FunctionTupleDivideByNumber divide(context);
return divide.getReturnTypeImpl({arguments[0], norm_res});
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
2021-09-09 12:41:22 +00:00
FunctionLNorm<FuncLabel> norm(context);
2021-08-30 12:52:00 +00:00
auto type = norm.getReturnTypeImpl(arguments);
auto column = norm.executeImpl(arguments, DataTypePtr(), input_rows_count);
ColumnWithTypeAndName norm_res{column, type, {}};
FunctionTupleDivideByNumber divide(context);
return divide.executeImpl({arguments[0], norm_res}, DataTypePtr(), input_rows_count);
}
};
2021-09-09 12:41:22 +00:00
using FunctionL1Normalize = FunctionLNormalize<L1Label>;
2021-08-27 13:14:32 +00:00
2021-09-09 12:41:22 +00:00
using FunctionL2Normalize = FunctionLNormalize<L2Label>;
2021-08-27 13:14:32 +00:00
2021-09-09 12:41:22 +00:00
using FunctionLinfNormalize = FunctionLNormalize<LinfLabel>;
2021-08-27 13:14:32 +00:00
2021-09-09 12:41:22 +00:00
using FunctionLpNormalize = FunctionLNormalize<LpLabel>;
2021-08-27 13:14:32 +00:00
2021-09-09 12:41:22 +00:00
class FunctionCosineDistance : public ITupleFunction
2021-08-30 13:55:38 +00:00
{
public:
/// constexpr cannot be used due to std::string has not constexpr constructor in this compiler version
static inline auto name = "cosineDistance";
2021-09-09 12:41:22 +00:00
explicit FunctionCosineDistance(ContextPtr context_) : ITupleFunction(context_) {}
2021-08-30 13:55:38 +00:00
static FunctionPtr create(ContextPtr context_) { return std::make_shared<FunctionCosineDistance>(context_); }
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 2; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
FunctionDotProduct dot(context);
ColumnWithTypeAndName dot_result{dot.getReturnTypeImpl(arguments), {}};
FunctionL2Norm norm(context);
ColumnWithTypeAndName first_norm{norm.getReturnTypeImpl({arguments[0]}), {}};
ColumnWithTypeAndName second_norm{norm.getReturnTypeImpl({arguments[1]}), {}};
2021-08-30 14:31:37 +00:00
auto minus = FunctionFactory::instance().get("minus", context);
2021-08-30 13:55:38 +00:00
auto multiply = FunctionFactory::instance().get("multiply", context);
auto divide = FunctionFactory::instance().get("divide", context);
2021-08-30 14:31:37 +00:00
ColumnWithTypeAndName one{std::make_shared<DataTypeUInt8>(), {}};
2021-08-30 13:55:38 +00:00
2021-08-30 14:31:37 +00:00
ColumnWithTypeAndName multiply_result{multiply->build({first_norm, second_norm})->getResultType(), {}};
ColumnWithTypeAndName divide_result{divide->build({dot_result, multiply_result})->getResultType(), {}};
return minus->build({one, divide_result})->getResultType();
2021-08-30 13:55:38 +00:00
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
2021-09-23 13:42:06 +00:00
if (getReturnTypeImpl(arguments)->isNullable())
{
2021-09-23 12:54:00 +00:00
return DataTypeNullable(std::make_shared<DataTypeNothing>())
.createColumnConstWithDefaultValue(input_rows_count);
}
2021-08-30 14:31:37 +00:00
FunctionDotProduct dot(context);
ColumnWithTypeAndName dot_result{dot.executeImpl(arguments, DataTypePtr(), input_rows_count),
dot.getReturnTypeImpl(arguments), {}};
2021-08-30 13:55:38 +00:00
2021-08-30 14:31:37 +00:00
FunctionL2Norm norm(context);
ColumnWithTypeAndName first_norm{norm.executeImpl({arguments[0]}, DataTypePtr(), input_rows_count),
norm.getReturnTypeImpl({arguments[0]}), {}};
ColumnWithTypeAndName second_norm{norm.executeImpl({arguments[1]}, DataTypePtr(), input_rows_count),
norm.getReturnTypeImpl({arguments[1]}), {}};
2021-08-30 13:55:38 +00:00
2021-08-30 14:31:37 +00:00
auto minus = FunctionFactory::instance().get("minus", context);
auto multiply = FunctionFactory::instance().get("multiply", context);
auto divide = FunctionFactory::instance().get("divide", context);
2021-09-09 12:41:22 +00:00
ColumnWithTypeAndName one{DataTypeUInt8().createColumnConst(input_rows_count, 1),
2021-08-30 14:31:37 +00:00
std::make_shared<DataTypeUInt8>(), {}};
auto multiply_elem = multiply->build({first_norm, second_norm});
ColumnWithTypeAndName multiply_result;
multiply_result.type = multiply_elem->getResultType();
multiply_result.column = multiply_elem->execute({first_norm, second_norm},
multiply_result.type, input_rows_count);
auto divide_elem = divide->build({dot_result, multiply_result});
ColumnWithTypeAndName divide_result;
divide_result.type = divide_elem->getResultType();
divide_result.column = divide_elem->execute({dot_result, multiply_result},
divide_result.type, input_rows_count);
auto minus_elem = minus->build({one, divide_result});
return minus_elem->execute({one, divide_result}, minus_elem->getResultType(), {});
2021-08-30 13:55:38 +00:00
}
2021-08-30 14:31:37 +00:00
};
2021-08-30 13:55:38 +00:00
/// An adaptor to call Norm/Distance function for tuple or array depending on the 1st argument type
template <class Traits>
class TupleOrArrayFunction : public IFunction
{
public:
static constexpr auto name = Traits::name;
explicit TupleOrArrayFunction(ContextPtr context_)
: IFunction()
, tuple_function(Traits::CreateTupleFunction(context_))
, array_function(Traits::CreateArrayFunction(context_)) {}
static FunctionPtr create(ContextPtr context_) { return std::make_shared<TupleOrArrayFunction>(context_); }
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return tuple_function->getNumberOfArguments(); }
bool useDefaultImplementationForConstants() const override { return true; }
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
bool is_array = checkDataTypes<DataTypeArray>(arguments[0].type.get());
return (is_array ? array_function : tuple_function)->getReturnTypeImpl(arguments);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
{
bool is_array = checkDataTypes<DataTypeArray>(arguments[0].type.get());
return (is_array ? array_function : tuple_function)->executeImpl(arguments, result_type, input_rows_count);
}
private:
FunctionPtr tuple_function;
FunctionPtr array_function;
};
extern FunctionPtr createFunctionArrayL1Norm(ContextPtr context_);
extern FunctionPtr createFunctionArrayL2Norm(ContextPtr context_);
2022-06-28 19:27:53 +00:00
extern FunctionPtr createFunctionArrayL2SquaredNorm(ContextPtr context_);
extern FunctionPtr createFunctionArrayLpNorm(ContextPtr context_);
extern FunctionPtr createFunctionArrayLinfNorm(ContextPtr context_);
extern FunctionPtr createFunctionArrayL1Distance(ContextPtr context_);
extern FunctionPtr createFunctionArrayL2Distance(ContextPtr context_);
2022-06-28 19:27:53 +00:00
extern FunctionPtr createFunctionArrayL2SquaredDistance(ContextPtr context_);
extern FunctionPtr createFunctionArrayLpDistance(ContextPtr context_);
extern FunctionPtr createFunctionArrayLinfDistance(ContextPtr context_);
extern FunctionPtr createFunctionArrayCosineDistance(ContextPtr context_);
struct L1NormTraits
{
static constexpr auto name = "L1Norm";
static constexpr auto CreateTupleFunction = FunctionL1Norm::create;
static constexpr auto CreateArrayFunction = createFunctionArrayL1Norm;
};
struct L2NormTraits
{
static constexpr auto name = "L2Norm";
static constexpr auto CreateTupleFunction = FunctionL2Norm::create;
static constexpr auto CreateArrayFunction = createFunctionArrayL2Norm;
};
2022-06-28 19:27:53 +00:00
struct L2SquaredNormTraits
{
static constexpr auto name = "L2SquaredNorm";
2022-06-28 19:27:53 +00:00
static constexpr auto CreateTupleFunction = FunctionL2SquaredNorm::create;
static constexpr auto CreateArrayFunction = createFunctionArrayL2SquaredNorm;
};
struct LpNormTraits
{
static constexpr auto name = "LpNorm";
static constexpr auto CreateTupleFunction = FunctionLpNorm::create;
static constexpr auto CreateArrayFunction = createFunctionArrayLpNorm;
};
struct LinfNormTraits
{
static constexpr auto name = "LinfNorm";
static constexpr auto CreateTupleFunction = FunctionLinfNorm::create;
static constexpr auto CreateArrayFunction = createFunctionArrayLinfNorm;
};
struct L1DistanceTraits
{
static constexpr auto name = "L1Distance";
static constexpr auto CreateTupleFunction = FunctionL1Distance::create;
static constexpr auto CreateArrayFunction = createFunctionArrayL1Distance;
};
struct L2DistanceTraits
{
static constexpr auto name = "L2Distance";
static constexpr auto CreateTupleFunction = FunctionL2Distance::create;
static constexpr auto CreateArrayFunction = createFunctionArrayL2Distance;
};
2022-06-28 19:27:53 +00:00
struct L2SquaredDistanceTraits
{
static constexpr auto name = "L2SquaredDistance";
2022-06-28 19:27:53 +00:00
static constexpr auto CreateTupleFunction = FunctionL2SquaredDistance::create;
static constexpr auto CreateArrayFunction = createFunctionArrayL2SquaredDistance;
};
struct LpDistanceTraits
{
static constexpr auto name = "LpDistance";
static constexpr auto CreateTupleFunction = FunctionLpDistance::create;
static constexpr auto CreateArrayFunction = createFunctionArrayLpDistance;
};
struct LinfDistanceTraits
{
static constexpr auto name = "LinfDistance";
static constexpr auto CreateTupleFunction = FunctionLinfDistance::create;
static constexpr auto CreateArrayFunction = createFunctionArrayLinfDistance;
};
struct CosineDistanceTraits
{
static constexpr auto name = "cosineDistance";
static constexpr auto CreateTupleFunction = FunctionCosineDistance::create;
static constexpr auto CreateArrayFunction = createFunctionArrayCosineDistance;
};
using TupleOrArrayFunctionL1Norm = TupleOrArrayFunction<L1NormTraits>;
using TupleOrArrayFunctionL2Norm = TupleOrArrayFunction<L2NormTraits>;
2022-06-28 19:27:53 +00:00
using TupleOrArrayFunctionL2SquaredNorm = TupleOrArrayFunction<L2SquaredNormTraits>;
using TupleOrArrayFunctionLpNorm = TupleOrArrayFunction<LpNormTraits>;
using TupleOrArrayFunctionLinfNorm = TupleOrArrayFunction<LinfNormTraits>;
using TupleOrArrayFunctionL1Distance = TupleOrArrayFunction<L1DistanceTraits>;
using TupleOrArrayFunctionL2Distance = TupleOrArrayFunction<L2DistanceTraits>;
2022-06-28 19:27:53 +00:00
using TupleOrArrayFunctionL2SquaredDistance = TupleOrArrayFunction<L2SquaredDistanceTraits>;
using TupleOrArrayFunctionLpDistance = TupleOrArrayFunction<LpDistanceTraits>;
using TupleOrArrayFunctionLinfDistance = TupleOrArrayFunction<LinfDistanceTraits>;
using TupleOrArrayFunctionCosineDistance = TupleOrArrayFunction<CosineDistanceTraits>;
void registerVectorFunctions(FunctionFactory & factory)
{
factory.registerFunction<FunctionTuplePlus>();
factory.registerAlias("vectorSum", FunctionTuplePlus::name, FunctionFactory::CaseInsensitive);
factory.registerFunction<FunctionTupleMinus>();
factory.registerAlias("vectorDifference", FunctionTupleMinus::name, FunctionFactory::CaseInsensitive);
factory.registerFunction<FunctionTupleMultiply>();
2021-08-23 13:41:20 +00:00
factory.registerFunction<FunctionTupleDivide>();
factory.registerFunction<FunctionTupleNegate>();
2021-08-27 15:44:04 +00:00
factory.registerFunction<FunctionTupleMultiplyByNumber>();
factory.registerFunction<FunctionTupleDivideByNumber>();
2021-08-23 13:41:20 +00:00
factory.registerFunction<FunctionDotProduct>();
factory.registerAlias("scalarProduct", FunctionDotProduct::name, FunctionFactory::CaseInsensitive);
factory.registerFunction<TupleOrArrayFunctionL1Norm>();
factory.registerFunction<TupleOrArrayFunctionL2Norm>();
2022-06-28 19:27:53 +00:00
factory.registerFunction<TupleOrArrayFunctionL2SquaredNorm>();
factory.registerFunction<TupleOrArrayFunctionLinfNorm>();
factory.registerFunction<TupleOrArrayFunctionLpNorm>();
factory.registerAlias("normL1", TupleOrArrayFunctionL1Norm::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("normL2", TupleOrArrayFunctionL2Norm::name, FunctionFactory::CaseInsensitive);
2022-06-28 19:27:53 +00:00
factory.registerAlias("normL2Squared", TupleOrArrayFunctionL2SquaredNorm::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("normLinf", TupleOrArrayFunctionLinfNorm::name, FunctionFactory::CaseInsensitive);
2021-09-09 15:45:05 +00:00
factory.registerAlias("normLp", FunctionLpNorm::name, FunctionFactory::CaseInsensitive);
factory.registerFunction<TupleOrArrayFunctionL1Distance>();
factory.registerFunction<TupleOrArrayFunctionL2Distance>();
2022-06-28 19:27:53 +00:00
factory.registerFunction<TupleOrArrayFunctionL2SquaredDistance>();
factory.registerFunction<TupleOrArrayFunctionLinfDistance>();
factory.registerFunction<TupleOrArrayFunctionLpDistance>();
2021-09-09 15:45:05 +00:00
factory.registerAlias("distanceL1", FunctionL1Distance::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("distanceL2", FunctionL2Distance::name, FunctionFactory::CaseInsensitive);
2022-06-28 19:27:53 +00:00
factory.registerAlias("distanceL2Squared", FunctionL2SquaredDistance::name, FunctionFactory::CaseInsensitive);
2021-09-09 15:45:05 +00:00
factory.registerAlias("distanceLinf", FunctionLinfDistance::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("distanceLp", FunctionLpDistance::name, FunctionFactory::CaseInsensitive);
2021-08-30 12:52:00 +00:00
factory.registerFunction<FunctionL1Normalize>();
factory.registerFunction<FunctionL2Normalize>();
factory.registerFunction<FunctionLinfNormalize>();
factory.registerFunction<FunctionLpNormalize>();
2021-08-30 14:31:37 +00:00
2021-09-09 15:45:05 +00:00
factory.registerAlias("normalizeL1", FunctionL1Normalize::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("normalizeL2", FunctionL2Normalize::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("normalizeLinf", FunctionLinfNormalize::name, FunctionFactory::CaseInsensitive);
factory.registerAlias("normalizeLp", FunctionLpNormalize::name, FunctionFactory::CaseInsensitive);
factory.registerFunction<TupleOrArrayFunctionCosineDistance>();
}
}