<commit_before>from fontTools.varLib.models import supportScalar, normalizeValue
from fontTools.misc.fixedTools import MAX_F2DOT14
from functools import cache

__all__ = ['rebaseTent']

def _reverse_negate(v):
    return (-v[2], -v[1], -v[0])

def _solve(tent, axisLimit):
    axisMin, axisDef, axisMax = axisLimit
    lower, peak, upper = tent

    # Mirror the problem such that axisDef <= peak
    if axisDef > peak:
        return [(scalar, _reverse_negate(t) if t is not None else None)
                for scalar,t
                in _solve(_reverse_negate(tent), _reverse_negate(axisLimit))]
    # axisDef <= peak

    # case 1: The whole deltaset falls outside the new limit; we can drop it
    #
    #                                          peak
    #  1.........................................o..........
    #                                           / \
    #                                          /   \
    #                                         /     \
    #                                        /       \
    #  0---|-----------|----------|-------- o         o----1
    #    axisMin     axisDef    axisMax   lower     upper
    #
    if axisMax <= lower and axisMax < peak:
        return [] # No overlap

    # case 2: Only the peak and outermost bound fall outside the new limit;
    # we keep the deltaset, update peak and outermost bound and and scale deltas
    # by the scalar value for the restricted axis at the new limit, and solve
    # recursively.
    #
    #                                  |peak
    #  1...............................|.o..........
    #                                  |/ \
    #                                  /   \
    #                                 /|    \
    #                                / |     \
    #  0---|-----------|----------- o  |      o----1
    #    axisMin     axisDef    lower  |      upper
    #                                  |
    #                                axisMax
    #
    # Convert to:
    #
    #  1............................................
    #                                  |
    #                                  o peak
    #                                 /|
    #                                /x|
    #  0---|-----------|----------- o  o upper ----1
    #    axisMin     axisDef    lower  |
    #                                  |
    #                                axisMax
    if axisMax < peak:
        mult = supportScalar({'tag': axisMax}, {'tag': tent})
        tent = (lower, axisMax, axisMax)
        return [(scalar*mult, t) for scalar,t in _solve(tent, axisLimit)]

    # lower <= axisDef <= peak <= axisMax

    gain = supportScalar({'tag': axisDef}, {'tag': tent})
    out = [(gain, None)]

    # First, the positive side

    # outGain is the scalar of axisMax at the tent.
    outGain = supportScalar({'tag': axisMax}, {'tag': tent})

    # Case 3a: Gain is more than outGain. The tent down-slope crosses
    # the axis into negative. We have to split it into multiples.
    #
    #                      | peak  |
    #  1...................|.o.....|..............
    #                      |/x\_   |
    #  gain................+....+_.|..............
    #                     /|    |y\|
    #  ................../.|....|..+_......outGain
    #                   /  |    |  | \
    #  0---|-----------o   |    |  |  o----------1
    #    axisMin    lower  |    |  |   upper
    #                      |    |  |
    #                axisDef    |  axisMax
    #                           |
    #                      crossing
    if gain > outGain:

        # Crossing point on the axis.
        crossing = peak + ((1 - gain) * (upper - peak) / (1 - outGain))

        loc = (peak, peak, crossing)
        scalar = 1

        # The part before the crossing point.
        out.append((scalar - gain, loc))

        # The part after the crossing point may use one or two tents,
        # depending on whether upper is before axisMax or not, in one
        # case we need to keep it down to eternity.

        # Case 3a1, similar to case 1neg; just one tent needed, as in
        # the drawing above.
        if upper >= axisMax:
            loc = (crossing, axisMax, axisMax)
            scalar = supportScalar({'tag': axisMax}, {'tag': tent})

            out.append((scalar - gain, loc))

        # Case 3a2: Similar to case 2neg; two tents needed, to keep
        # down to eternity.
        #
        #                      | peak             |
        #  1...................|.o................|...
        #                      |/ \_              |
        #  gain................+....+_............|...
        #                     /|    | \xxxxxxxxxxy|
        #                    / |    |  \_xxxxxyyyy|
        #                   /  |    |    \xxyyyyyy|
        #  0---|-----------o   |    |     o-------|--1
        #    axisMin    lower  |    |      upper  |
        #                      |    |             |
        #                axisDef    |             axisMax
        #                           |
        #                      crossing
        else:
            # Downslope.
            loc1 = (crossing, upper, axisMax)
            scalar1 = 0

            # Eternity justify.
            loc2 = (upper, axisMax, axisMax)
            scalar2 = supportScalar({'tag': axisMax}, {'tag': tent})

            out.append((scalar1 - gain, loc1))
            out.append((scalar2 - gain, loc2))

    # Case 3: Outermost limit still fits within F2Dot14 bounds;
    # we keep deltas as is and only scale the axes bounds. Deltas beyond -1.0
    # or +1.0 will never be applied as implementations must clamp to that range.
    #
    #            |           peak |
    #  1.........|............o...|..................
    #            |           /x\  |
    #            |          /xxx\ |
    #            |         /xxxxx\|
    #            |        /xxxxxxx+
    #            |       /xxxxxxxx|\
    #  0---|-----|------oxxxxxxxxx|xo---------------1
    #    axisMin |  lower         | upper
    #            |                |
    #          axisDef          axisMax
    #
    elif axisDef + (axisMax - axisDef) * 2 >= upper:

        if axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper:<commit_msg>[instancer.solver] Fix negative -2 case<commit_after>from fontTools.varLib.models import supportScalar, normalizeValue
from fontTools.misc.fixedTools import MAX_F2DOT14
from functools import cache

__all__ = ['rebaseTent']

def _reverse_negate(v):
    return (-v[2], -v[1], -v[0])

def _solve(tent, axisLimit, negative=False):
    axisMin, axisDef, axisMax = axisLimit
    lower, peak, upper = tent

    # Mirror the problem such that axisDef <= peak
    if axisDef > peak:
        return [(scalar, _reverse_negate(t) if t is not None else None)
                for scalar,t
                in _solve(_reverse_negate(tent), _reverse_negate(axisLimit), not negative)]
    # axisDef <= peak

    # case 1: The whole deltaset falls outside the new limit; we can drop it
    #
    #                                          peak
    #  1.........................................o..........
    #                                           / \
    #                                          /   \
    #                                         /     \
    #                                        /       \
    #  0---|-----------|----------|-------- o         o----1
    #    axisMin     axisDef    axisMax   lower     upper
    #
    if axisMax <= lower and axisMax < peak:
        return [] # No overlap

    # case 2: Only the peak and outermost bound fall outside the new limit;
    # we keep the deltaset, update peak and outermost bound and and scale deltas
    # by the scalar value for the restricted axis at the new limit, and solve
    # recursively.
    #
    #                                  |peak
    #  1...............................|.o..........
    #                                  |/ \
    #                                  /   \
    #                                 /|    \
    #                                / |     \
    #  0---|-----------|----------- o  |      o----1
    #    axisMin     axisDef    lower  |      upper
    #                                  |
    #                                axisMax
    #
    # Convert to:
    #
    #  1............................................
    #                                  |
    #                                  o peak
    #                                 /|
    #                                /x|
    #  0---|-----------|----------- o  o upper ----1
    #    axisMin     axisDef    lower  |
    #                                  |
    #                                axisMax
    if axisMax < peak:
        mult = supportScalar({'tag': axisMax}, {'tag': tent})
        tent = (lower, axisMax, axisMax)
        return [(scalar*mult, t) for scalar,t in _solve(tent, axisLimit)]

    # lower <= axisDef <= peak <= axisMax

    gain = supportScalar({'tag': axisDef}, {'tag': tent})
    out = [(gain, None)]

    # First, the positive side

    # outGain is the scalar of axisMax at the tent.
    outGain = supportScalar({'tag': axisMax}, {'tag': tent})

    # Case 3a: Gain is more than outGain. The tent down-slope crosses
    # the axis into negative. We have to split it into multiples.
    #
    #                      | peak  |
    #  1...................|.o.....|..............
    #                      |/x\_   |
    #  gain................+....+_.|..............
    #                     /|    |y\|
    #  ................../.|....|..+_......outGain
    #                   /  |    |  | \
    #  0---|-----------o   |    |  |  o----------1
    #    axisMin    lower  |    |  |   upper
    #                      |    |  |
    #                axisDef    |  axisMax
    #                           |
    #                      crossing
    if gain > outGain:

        # Crossing point on the axis.
        crossing = peak + ((1 - gain) * (upper - peak) / (1 - outGain))

        loc = (peak, peak, crossing)
        scalar = 1

        # The part before the crossing point.
        out.append((scalar - gain, loc))

        # The part after the crossing point may use one or two tents,
        # depending on whether upper is before axisMax or not, in one
        # case we need to keep it down to eternity.

        # Case 3a1, similar to case 1neg; just one tent needed, as in
        # the drawing above.
        if upper >= axisMax:
            loc = (crossing, axisMax, axisMax)
            scalar = supportScalar({'tag': axisMax}, {'tag': tent})

            out.append((scalar - gain, loc))

        # Case 3a2: Similar to case 2neg; two tents needed, to keep
        # down to eternity.
        #
        #                      | peak             |
        #  1...................|.o................|...
        #                      |/ \_              |
        #  gain................+....+_............|...
        #                     /|    | \xxxxxxxxxxy|
        #                    / |    |  \_xxxxxyyyy|
        #                   /  |    |    \xxyyyyyy|
        #  0---|-----------o   |    |     o-------|--1
        #    axisMin    lower  |    |      upper  |
        #                      |    |             |
        #                axisDef    |             axisMax
        #                           |
        #                      crossing
        else:
            # Downslope.
            loc1 = (crossing, upper, axisMax)
            scalar1 = 0

            # Eternity justify.
            loc2 = (upper, axisMax, axisMax)
            scalar2 = supportScalar({'tag': axisMax}, {'tag': tent})

            out.append((scalar1 - gain, loc1))
            out.append((scalar2 - gain, loc2))

    # Case 3: Outermost limit still fits within F2Dot14 bounds;
    # we keep deltas as is and only scale the axes bounds. Deltas beyond -1.0
    # or +1.0 will never be applied as implementations must clamp to that range.
    #
    #            |           peak |
    #  1.........|............o...|..................
    #            |           /x\  |
    #            |          /xxx\ |
    #            |         /xxxxx\|
    #            |        /xxxxxxx+
    #            |       /xxxxxxxx|\
    #  0---|-----|------oxxxxxxxxx|xo---------------1
    #    axisMin |  lower         | upper
    #            |                |
    #          axisDef          axisMax
    #
    elif axisDef + (axisMax - axisDef) * 2 >= upper:

        if not negative and axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper:
{'fraction_non_alphanumeric': 0.16922343215960575, 'fraction_numerical': 0.009140767824497258, 'mean_word_length': 0.8127071027229505, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 8, 'word_list_counts': {'cursed_substrings.json': 72, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '962519', 'n_tokens_mistral': 3445, 'n_tokens_neox': 3225, 'n_words': 911}