Path: blob/21.2-virgl/src/gallium/frontends/clover/util/factor.hpp
4572 views
//1// Copyright 2013 Francisco Jerez2//3// Permission is hereby granted, free of charge, to any person obtaining a4// copy of this software and associated documentation files (the "Software"),5// to deal in the Software without restriction, including without limitation6// the rights to use, copy, modify, merge, publish, distribute, sublicense,7// and/or sell copies of the Software, and to permit persons to whom the8// Software is furnished to do so, subject to the following conditions:9//10// The above copyright notice and this permission notice shall be included in11// all copies or substantial portions of the Software.12//13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19// OTHER DEALINGS IN THE SOFTWARE.20//2122#ifndef CLOVER_UTIL_FACTOR_HPP23#define CLOVER_UTIL_FACTOR_HPP2425#include "util/range.hpp"2627namespace clover {28namespace factor {29///30/// Calculate all prime integer factors of \p x.31///32/// If \p limit is non-zero, terminate early as soon as enough33/// factors have been collected to reach the product \p limit.34///35template<typename T>36std::vector<T>37find_integer_prime_factors(T x, T limit = 0)38{39const T max_d = (limit > 0 && limit < x ? limit : x);40const T min_x = x / max_d;41std::vector<T> factors;4243for (T d = 2; d <= max_d && x > min_x; d++) {44if (x % d == 0) {45for (; x % d == 0; x /= d);46factors.push_back(d);47}48}4950return factors;51}5253namespace detail {54///55/// Walk the power set of prime factors of the n-dimensional56/// integer array \p grid subject to the constraints given by57/// \p limits.58///59template<typename T>60std::pair<T, std::vector<T>>61next_grid_factor(const std::pair<T, std::vector<T>> &limits,62const std::vector<T> &grid,63const std::vector<std::vector<T>> &factors,64std::pair<T, std::vector<T>> block,65unsigned d = 0, unsigned i = 0) {66if (d >= factors.size()) {67// We're done.68return {};6970} else if (i >= factors[d].size()) {71// We're done with this grid dimension, try the next.72return next_grid_factor(limits, grid, factors,73std::move(block), d + 1, 0);7475} else {76T f = factors[d][i];7778// Try the next power of this factor.79block.first *= f;80block.second[d] *= f;8182if (block.first <= limits.first &&83block.second[d] <= limits.second[d] &&84grid[d] % block.second[d] == 0) {85// We've found a valid grid divisor.86return block;8788} else {89// Overflow, back off to the zeroth power,90while (block.second[d] % f == 0) {91block.second[d] /= f;92block.first /= f;93}9495// ...and carry to the next factor.96return next_grid_factor(limits, grid, factors,97std::move(block), d, i + 1);98}99}100}101}102103///104/// Find the divisor of the integer array \p grid that gives the105/// highest possible product not greater than \p product_limit106/// subject to the constraints given by \p coord_limit.107///108template<typename T>109std::vector<T>110find_grid_optimal_factor(T product_limit,111const std::vector<T> &coord_limit,112const std::vector<T> &grid) {113const std::vector<std::vector<T>> factors =114map(find_integer_prime_factors<T>, grid, coord_limit);115const auto limits = std::make_pair(product_limit, coord_limit);116auto best = std::make_pair(T(1), std::vector<T>(grid.size(), T(1)));117118for (auto block = best;119block.first != 0 && best.first != product_limit;120block = detail::next_grid_factor(limits, grid, factors, block)) {121if (block.first > best.first)122best = block;123}124125return best.second;126}127}128}129130#endif131132133