Skip to content

Commit

Permalink
try
Browse files Browse the repository at this point in the history
  • Loading branch information
rui-mo committed Apr 12, 2024
1 parent 8c9c123 commit d797f71
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 92 deletions.
82 changes: 82 additions & 0 deletions velox/expression/tests/ArgGenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "velox/expression/tests/ArgGenerator.h"

namespace facebook::velox::test {
namespace {
int32_t rand32(FuzzerGenerator& rng) {
return boost::random::uniform_int_distribution<int32_t>()(rng);
}
} // namespace

std::vector<TypePtr> DecimalArgGeneratorBase::generateArgs(
const exec::FunctionSignature& /*signature*/,
const TypePtr& returnType,
FuzzerGenerator& rng) override {
auto inputs = findInputs(returnType, rng);
for (const auto& input : inputs) {
if (input == nullptr) {
return {};
}
}
return inputs;
}

const Inputs& DecimalArgGeneratorBase::findInputs(
const TypePtr& returnType,
FuzzerGenerator& rng) const {
auto [p, s] = getDecimalPrecisionScale(*returnType);
auto it = inputs_.find({p, s});
if (it == inputs_.end()) {
LOG(ERROR) << "Cannot find input types for " << returnType->toString();
return {nullptr, nullptr};
}

auto index = rand32(rng) % it->second.size();
return it->second[index];
}

const std::vector<TypePtr>& DecimalArgGeneratorBase::getAllTypes() const {
const auto generateAllTypes = []() {
std::vector<TypePtr> allTypes;
for (auto p = 1; p < 38; ++p) {
for (auto s = 0; s <= p; ++s) {
allTypes.push_back(DECIMAL(p, s));
}
}
return allTypes;
};

static std::vector<TypePtr> allTypes = generateAllTypes();
return allTypes;
}

void DecimalArgGeneratorBase::initialize() {
// By default, the result type is considered to be calculated from two input
// decimal types.
for (const auto& a : getAllTypes()) {
for (const auto& b : getAllTypes()) {
auto [p1, s1] = getDecimalPrecisionScale(*a);
auto [p2, s2] = getDecimalPrecisionScale(*b);

if (auto returnType = toReturnType(4, p1, s1, p2, s2)) {
inputs_[returnType.value()].push_back({a, b});
}
}
}
}
} // namespace facebook::velox::test
63 changes: 63 additions & 0 deletions velox/expression/tests/ArgGenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "velox/expression/FunctionSignature.h"
#include "velox/vector/fuzzer/Utils.h"

namespace facebook::velox::test {

class ArgGenerator {
public:
virtual ~ArgGenerator() = default;

/// Given a signature and a concrete return type return randomly selected
/// valid input types. Returns empty vector if no input types can
/// produce the specified result type.
virtual std::vector<TypePtr> generateArgs(
const exec::FunctionSignature& signature,
const TypePtr& returnType,
FuzzerGenerator& rng) = 0;
};

class DecimalArgGeneratorBase : public ArgGenerator {
public:
std::vector<TypePtr> generateArgs(
const exec::FunctionSignature& /*signature*/,
const TypePtr& returnType,
FuzzerGenerator& rng) override;

protected:
using Inputs = std::vector<TypePtr>;

// Return randomly selected pair of input types that produce the specified
// result type.
const Inputs& findInputs(const TypePtr& returnType, FuzzerGenerator& rng)
const;

const std::vector<TypePtr>& getAllTypes() const;

// Compute result type for all possible pairs of decimal input types. Store
// the results in 'inputs_' maps keyed by return type.
void initialize();

// Given precisions and scales of the inputs, return precision and scale of
// the result.
virtual std::optional<std::pair<int, int>> toReturnType(int count, ...) = 0;

std::map<std::pair<int, int>, std::vector<Inputs>> inputs_;
};

} // namespace facebook::velox::test
2 changes: 1 addition & 1 deletion velox/expression/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ target_link_libraries(
velox_expression_verifier velox_vector_test_lib velox_vector_fuzzer
velox_type velox_expression_test_utility)

add_library(velox_expression_fuzzer ExpressionFuzzer.cpp FuzzerRunner.cpp
add_library(velox_expression_fuzzer ArgGenerator.cpp ExpressionFuzzer.cpp FuzzerRunner.cpp
ExpressionFuzzerVerifier.cpp)

target_link_libraries(
Expand Down
85 changes: 7 additions & 78 deletions velox/expression/tests/ExpressionFuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,88 +26,13 @@
#include "velox/expression/FunctionSignature.h"
#include "velox/expression/ReverseSignatureBinder.h"
#include "velox/expression/SimpleFunctionRegistry.h"
#include "velox/expression/tests/ArgGenerator.h"
#include "velox/expression/tests/ExpressionFuzzer.h"
#include "velox/expression/tests/utils/ArgumentTypeFuzzer.h"

namespace facebook::velox::test {

namespace {

int32_t rand(FuzzerGenerator& rng) {
return boost::random::uniform_int_distribution<int32_t>()(rng);
}

class DecimalArgGeneratorBase : public ArgGenerator {
public:
std::vector<TypePtr> generateArgs(
const exec::FunctionSignature& /*signature*/,
const TypePtr& returnType,
FuzzerGenerator& rng) override {
auto inputs = findInputs(returnType, rng);
for (const auto& input : inputs) {
if (input == nullptr) {
return {};
}
}
return inputs;
}

protected:
// Compute result type for all possible pairs of decimal input types. Store
// the results in 'inputs_' maps keyed by return type.
void initialize() {
// By default, the result type is considered to be calculated from two input
// decimal types.
for (const auto& a : getAllTypes()) {
for (const auto& b : getAllTypes()) {
auto [p1, s1] = getDecimalPrecisionScale(*a);
auto [p2, s2] = getDecimalPrecisionScale(*b);

if (auto returnType = toReturnType(4, p1, s1, p2, s2)) {
inputs_[returnType.value()].push_back({a, b});
}
}
}
}

using Inputs = std::vector<TypePtr>;

// Return randomly selected pair of input types that produce the specified
// result type.
Inputs findInputs(const TypePtr& returnType, FuzzerGenerator& rng) const {
auto [p, s] = getDecimalPrecisionScale(*returnType);
auto it = inputs_.find({p, s});
if (it == inputs_.end()) {
LOG(ERROR) << "Cannot find input types for " << returnType->toString();
return {nullptr, nullptr};
}

auto index = rand(rng) % it->second.size();
return it->second[index];
}

const std::vector<TypePtr>& getAllTypes() const {
const auto generateAllTypes = []() {
std::vector<TypePtr> allTypes;
for (auto p = 1; p < 38; ++p) {
for (auto s = 0; s <= p; ++s) {
allTypes.push_back(DECIMAL(p, s));
}
}
return allTypes;
};

static std::vector<TypePtr> allTypes = generateAllTypes();
return allTypes;
}

// Given precisions and scales of the inputs, return precision and scale of
// the result.
virtual std::optional<std::pair<int, int>> toReturnType(int count, ...) = 0;

std::map<std::pair<int, int>, std::vector<Inputs>> inputs_;
};

class PlusMinusArgGenerator : public DecimalArgGeneratorBase {
public:
PlusMinusArgGenerator() {
Expand Down Expand Up @@ -211,7 +136,11 @@ class FloorAndRoundArgGenerator : public ArgGenerator {
return {};
}

auto s1 = rand(rng) % (38 - p + 1);
const auto rand32 = [](FuzzerGenerator& rng) {
return boost::random::uniform_int_distribution<int32_t>()(rng);
};

auto s1 = rand32(rng) % (38 - p + 1);
if (s1 == 0) {
return {DECIMAL(p, 0)};
}
Expand Down Expand Up @@ -818,7 +747,7 @@ ExpressionFuzzer::ExpressionFuzzer(
}
if (!isDeterministic(function.first, argTypes)) {
LOG(WARNING) << "Skipping non-deterministic function: "
<< function.first << signature->toString();
<< function.first << signature->toString();
continue;
}

Expand Down
13 changes: 0 additions & 13 deletions velox/expression/tests/ExpressionFuzzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,6 @@

namespace facebook::velox::test {

class ArgGenerator {
public:
virtual ~ArgGenerator() = default;

/// Given a signature and a concrete return type return randomly selected
/// valid input types. Returns empty vector if no input types can
/// produce the specified result type.
virtual std::vector<TypePtr> generateArgs(
const exec::FunctionSignature& signature,
const TypePtr& returnType,
FuzzerGenerator& rng) = 0;
};

// A tool that can be used to generate random expressions.
class ExpressionFuzzer {
public:
Expand Down

0 comments on commit d797f71

Please sign in to comment.