/* Copyright (C) 2021 Daniel Schultz This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mod_mpoly.h" /* sort terms in [left, right) by exponent assuming that bits in position >= pos are already sorted and assuming exponent vectors fit into one word and assuming that all bit positions that need to be sorted are in totalmask */ void _fmpz_mod_mpoly_radix_sort1( fmpz * Acoeffs, ulong * Aexps, slong left, slong right, flint_bitcnt_t pos, ulong cmpmask, ulong totalmask) { ulong mask, cmp; slong mid, cur; while (pos > 0) { pos--; FLINT_ASSERT(left <= right); FLINT_ASSERT(pos < FLINT_BITS); mask = UWORD(1) << pos; cmp = cmpmask & mask; /* insertion base case */ if (right - left < 10) { slong i, j; for (i = left + 1; i < right; i++) { for (j = i; j > left && mpoly_monomial_gt1(Aexps[j], Aexps[j - 1], cmpmask); j--) { fmpz_swap(Acoeffs + j, Acoeffs + j - 1); ULONG_SWAP(Aexps[j], Aexps[j - 1]); } } return; } /* return if there is no information to sort on this bit */ if ((totalmask & mask) == 0) continue; /* find first 'zero' */ mid = left; while (mid < right && (Aexps[mid] & mask) != cmp) mid++; /* make sure [left,mid) doesn't match cmpmask in position pos 'one' [mid,right) does match cmpmask in position pos 'zero' */ cur = mid; while (++cur < right) { if ((Aexps[cur] & mask) != cmp) { fmpz_swap(Acoeffs + cur, Acoeffs + mid); ULONG_SWAP(Aexps[cur], Aexps[mid]); mid++; } } if (mid - left < right - mid) { _fmpz_mod_mpoly_radix_sort1(Acoeffs, Aexps, left, mid, pos, cmpmask, totalmask); left = mid; } else { _fmpz_mod_mpoly_radix_sort1(Acoeffs, Aexps, mid, right, pos, cmpmask, totalmask); right = mid; } } } /* sort terms in [left, right) by exponent assuming that bits in position >= pos are already sorted */ void _fmpz_mod_mpoly_radix_sort( fmpz * Acoeffs, ulong * Aexps, slong left, slong right, flint_bitcnt_t pos, slong N, ulong * cmpmask) { ulong off, bit, mask, cmp; slong mid, check; while (pos > 0) { pos--; FLINT_ASSERT(left <= right); FLINT_ASSERT(pos < N*FLINT_BITS); off = pos/FLINT_BITS; bit = pos%FLINT_BITS; mask = UWORD(1) << bit; cmp = cmpmask[off] & mask; /* insertion base case */ if (right - left < 20) { slong i, j; for (i = left + 1; i < right; i++) { for (j = i; j > left && mpoly_monomial_gt(Aexps + N*j, Aexps + N*(j - 1), N, cmpmask); j--) { fmpz_swap(Acoeffs + j, Acoeffs + j - 1); mpoly_monomial_swap(Aexps + N*j, Aexps + N*(j - 1), N); } } return; } /* find first 'zero' */ mid = left; while (mid < right && ((Aexps+N*mid)[off] & mask) != cmp) mid++; /* make sure [left,mid) doesn't match cmpmask in position pos 'one' [mid,right) does match cmpmask in position pos 'zero' */ check = mid; while (++check < right) { if (((Aexps + N*check)[off] & mask) != cmp) { fmpz_swap(Acoeffs + check, Acoeffs + mid); mpoly_monomial_swap(Aexps + N*check, Aexps + N*mid, N); mid++; } } FLINT_ASSERT(left <= mid && mid <= right); if (mid - left < right - mid) { _fmpz_mod_mpoly_radix_sort(Acoeffs, Aexps, left, mid, pos, N, cmpmask); left = mid; } else { _fmpz_mod_mpoly_radix_sort(Acoeffs, Aexps, mid, right, pos, N, cmpmask); right = mid; } } } /* sort the terms in A by exponent assuming that the exponents are valid (other than being in order) */ void fmpz_mod_mpoly_sort_terms(fmpz_mod_mpoly_t A, const fmpz_mod_mpoly_ctx_t ctx) { slong i, N; flint_bitcnt_t pos; fmpz * Acoeffs = A->coeffs; ulong * Aexps = A->exps; ulong himask, * ptempexp; TMP_INIT; TMP_START; N = mpoly_words_per_exp(A->bits, ctx->minfo); ptempexp = (ulong *) TMP_ALLOC(N*sizeof(ulong)); mpoly_get_cmpmask(ptempexp, N, A->bits, ctx->minfo); himask = 0; for (i = 0; i < A->length; i++) himask |= (Aexps + N*i)[N - 1]; pos = FLINT_BIT_COUNT(himask); if (N == 1) _fmpz_mod_mpoly_radix_sort1(Acoeffs, Aexps, 0, A->length, pos, ptempexp[0], himask); else _fmpz_mod_mpoly_radix_sort(Acoeffs, Aexps, 0, A->length, (N - 1)*FLINT_BITS + pos, N, ptempexp); TMP_END; }