وقتی طولِ یک دنبالهٔ ویژگی را در یک رمزگشا بزرگ می‌کنیم، نامِ «کانولوشنِ ترانهاده» ممکن است این تصور را بسازد که عملِ قبلی را وارونه کرده‌ایم. بازگشتنِ تعدادِ مختصات، چنین تضمینی نمی‌دهد. این درس با ضرایبِ صحیحِ ازپیش‌داده‌شده، یک عملگرِ محدود می‌سازد تا فرقِ شکل، ترانهاده و وارون روشن شود. داده‌ها ویژگیِ بی‌بعد و ساختگی‌اند؛ مولدِ گفتار، وزنِ آموزش‌دیده و صوتِ ضبط‌شده در آزمایش نداریم.

۱. گام و مرزها را پیش از بزرگ‌کردنِ طول مشخص کنیم

شابلونِ فاصله‌دار و قطعه‌های مرزی روی یک مسیرِ محدود
تصویر مفهومی: شابلونِ فاصله‌دار و قطعه‌های مرزی روی یک مسیرِ محدود؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

در درسِ چیدمانِ Conv1d، پنجرهٔ معتبر با گامِ یک روی ورودی حرکت می‌کرد و سهمِ کانال‌ها را جمع می‌زد. اینجا مسئله تبدیلِ محورهای چندکاناله نیست. یک بردار، یک کرنلِ حقیقی، گام، فاصلهٔ ضرایب و مرزِ محدود داریم؛ بایاس و تابعِ فعال‌سازی را کنار می‌گذاریم تا عملگر خطی بماند.

نگاشتِ جلو را همبستگیِ لغزشی تعریف می‌کنیم: دو سوی بردار را به اندازهٔ padding با صفر گسترش می‌دهیم، پنجره را با stride جلو می‌بریم و ضرایبِ کرنل را بدونِ وارونه‌کردن روی نقاطِ آن می‌گذاریم. dilation فاصلهٔ نقاطِ کرنل است؛ با مقدارِ دو، بین دو ضریبِ متوالی یک جایگاه فاصله می‌افتد. صفرهای مرزی، مختصاتِ اعلام‌شدهٔ قراردادند، نه اطلاعاتِ مشاهده‌شدهٔ تازه.

بردارِ ورودیِ عملِ ترانهاده را u می‌نامیم. طولش از یک تا شش و اعضایش صحیحِ منفی شانزده تا شانزده‌اند. کرنل یک تا چهار ضریبِ صحیحِ منفی چهار تا چهار دارد. گام یک تا سه، padding صفر تا دو و dilation یک یا دو است. همهٔ ظرف‌ها tuple و نوع‌ها دقیق‌اند؛ bool، زیرکلاس، شناور و مولد تبدیلِ ضمنی نمی‌شوند.

اگر طولِ u برابر M و طولِ کرنل K باشد، طولِ انتخابیِ خروجی از رابطهٔ L=(M-1)*stride-2*padding+dilation*(K-1)+output_padding+1 می‌آید. قراردادِ ما 0 <= output_padding < stride و طولِ مثبت می‌خواهد. این دامنهٔ کوچک، همهٔ حالت‌های نوع، کانال و اندازهٔ یک کتابخانه را پوشش نمی‌دهد.

۲. چرا output_padding خانهٔ صفرِ تضمین‌شده نیست؟

دو قابِ هم‌اندازه در بخشِ مشترک و یک قطعهٔ رنگیِ افزوده در لبهٔ یکی
تصویر مفهومی: دو قابِ هم‌اندازه در بخشِ مشترک و یک قطعهٔ رنگیِ افزوده در لبهٔ یکی؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

مثالِ دستی، u برابرِ دو و سه و کرنلِ یک، دو و چهار است. گامِ دو، padding یک و dilation یک می‌گیریم. هر عضوِ u، نسخه‌ای مقیاس‌خورده از ضرایب را در چند جایگاه پخش می‌کند. عضوِ دو به جایگاه‌های منفی یک، صفر و یک سهم می‌دهد؛ سهمِ بیرونِ محدوده کنار می‌رود. عضوِ سه به جایگاه‌های یک، دو و سه سهم می‌دهد.

با output_padding صفر، طولِ سه انتخاب می‌شود: جایگاه صفر چهار، جایگاه یک هشت به‌اضافهٔ سه و جایگاه دو شش است؛ پاسخ چهار، یازده و شش می‌شود. با output_padding یک، طولِ چهار را انتخاب می‌کنیم و سهمِ دوازده در جایگاهِ سه هم داخلِ خروجی می‌افتد. نتیجه چهار، یازده، شش و دوازده است؛ نه همان پاسخ با یک صفرِ چسبانده‌شده.

توضیحِ کاملِ ConvTranspose1d در PyTorch 2.14، ابهامِ شکل در گامِ بزرگ‌تر از یک و نقشِ output_padding را جدا می‌کند. در همین مثال، نگاشتِ جلو هم بردارِ سه‌عضوی و هم چهارعضوی را به دو مختصات می‌رساند. پس طولِ دو به‌تنهایی نمی‌گوید فضایِ مبدأ سه عضو داشته یا چهار عضو؛ باید شکلِ موردنظر را صریح انتخاب کنیم.

۳. عملگرِ ترانهاده را با ضربِ داخلی بشناسیم

دو آرایشِ عمود از وزن‌های اتصال در کنار دو سینیِ مستقل
تصویر مفهومی: دو آرایشِ عمود از وزن‌های اتصال در کنار دو سینیِ مستقل؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

برای مبدأِ چهارعضوی، ماتریسِ نگاشتِ جلو دو ردیف دارد: ردیفِ نخست دو، چهار، صفر و صفر و ردیفِ دوم صفر، یک، دو و چهار است. آن را A می‌نامیم. ضربِ این ماتریس در x برابرِ یک، منفی دو، چهار و پنج، پاسخِ منفی شش و بیست‌وشش می‌دهد. ترانهادهٔ A ضرب‌درِ u همان چهار، یازده، شش و دوازده است.

در فضایِ حقیقیِ این درس، رابطهٔ مشخص‌کنندهٔ ترانهاده، برابریِ دو ضربِ داخلی است: dot(Ax,u)=dot(x,A^T u). سمتِ نخست منفی دوازده به‌اضافهٔ هفتادوهشت و سمتِ دوم چهار منهای بیست‌ودو به‌اضافهٔ بیست‌وچهار و شصت است؛ هر دو شصت‌وشش‌اند. برای ضریبِ مختلط، بحثِ مزدوج لازم می‌شود؛ آن حالت جزو قراردادِ حاضر نیست.

مرجعِ کاملِ TensorFlow برای conv1d_transpose نیز عمل را ترانهاده یا گرادیانِ کانولوشن معرفی می‌کند، نه واپیچشِ واقعی. در این برنامه مشتق‌گیریِ خودکار اجرا نمی‌شود؛ رابطهٔ خطی را مستقیماً با عددِ صحیح می‌سنجیم. نامِ «deconvolution» مجوزِ ادعایِ بازیابیِ ورودی نیست.

شاهدِ ساده‌تر، کرنلِ تک‌عضویِ یک و گامِ دو است. نگاشتِ جلو از بردارِ یک، دو، سه و چهار فقط یک و سه را می‌خواند. ترانهاده با شکلِ چهارعضوی، یک، صفر، سه و صفر می‌دهد؛ اطلاعاتِ جایگاه‌های حذف‌شده را ندارد. حتی نگاشتِ مربعیِ ضرب در دو هم با ترانهاده‌اش وارونه نمی‌شود: دو بار اعمال‌شدن، چهار برابرِ ورودی است.

۴. کدِ صحیح و مرجعِ ماتریسِ کانولوشن

یک ابزارِ پخشِ سهم‌ها و یک قابِ شفافِ مستقل برای وارسیِ همان قطعه‌ها
تصویر مفهومی: یک ابزارِ پخشِ سهم‌ها و یک قابِ شفافِ مستقل برای وارسیِ همان قطعه‌ها؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

مسیرِ اصلی بعد از اعتبارسنجیِ کامل، خروجیِ صفر با طولِ اعلام‌شده می‌سازد. سهمِ عضو i و ضریب k به جایگاهِ i*stride-padding+k*dilation افزوده می‌شود، اگر آن جایگاه داخلِ محدوده باشد. ضرایبِ نامتقارن جهت را آشکار می‌کنند. صفرهای انتهایی به بهانهٔ بی‌ارزش‌بودن حذف نمی‌شوند و ورودیِ صفر، بررسیِ ضریبِ نامعتبرِ آخر را دور نمی‌زند.

"""Finite real integer ConvTranspose adjoint lesson; no framework execution."""
from itertools import product
import json
import platform
import sys


def _admit(values, kernel, stride, padding, dilation, output_padding):
    if type(values) is not tuple or not 1 <= len(values) <= 6:
        raise ValueError("values must be an exact tuple of length 1..6")
    if any(type(x) is not int or not -16 <= x <= 16 for x in values):
        raise ValueError("values require exact integers in -16..16")
    if type(kernel) is not tuple or not 1 <= len(kernel) <= 4:
        raise ValueError("kernel must be an exact tuple of length 1..4")
    if any(type(x) is not int or not -4 <= x <= 4 for x in kernel):
        raise ValueError("kernel requires exact integers in -4..4")
    for name, value, low, high in (
            ("stride", stride, 1, 3), ("padding", padding, 0, 2),
            ("dilation", dilation, 1, 2)):
        if type(value) is not int or not low <= value <= high:
            raise ValueError(name + " violates the exact bounded integer contract")
    if type(output_padding) is not int or not 0 <= output_padding < stride:
        raise ValueError("own profile requires 0 <= output_padding < stride")
    length = ((len(values) - 1) * stride - 2 * padding
              + dilation * (len(kernel) - 1) + output_padding + 1)
    if length <= 0:
        raise ValueError("selected output length must be positive")
    return length


def transpose_1d(values, kernel, stride=1, padding=0, dilation=1, output_padding=0):
    """Scatter into a selected finite extent; single channel, real and no bias.

    Coordinates and supplied coefficients are dimensionless integers. This
    declared small profile is not the complete type or mode contract of an API.
    """
    length = _admit(values, kernel, stride, padding, dilation, output_padding)
    answer = [0] * length
    for i, value in enumerate(values):
        for tap, coefficient in enumerate(kernel):
            target = i * stride - padding + tap * dilation
            if 0 <= target < length:
                answer[target] += value * coefficient
    return tuple(answer)


def forward_reference(signal, kernel, stride, padding, dilation):
    """Independent FORWARD map on valid finite fixtures, not a public API.

    Explicit padding and strided windows form each forward dot product. No
    transpose function, target-index scatter, main validator or output adapter
    builds these values. The forward map has no bias, activation or channels.
    """
    extended = (0,) * padding + tuple(signal) + (0,) * padding
    span = 1 + (len(kernel) - 1) * dilation
    windows = []
    start = 0
    while start + span <= len(extended):
        window = extended[start:start + span:dilation]
        windows.append(sum(a * b for a, b in zip(window, kernel)))
        start += stride
    return tuple(windows)


def forward_matrix_reference(source_length, kernel, stride, padding, dilation):
    """Probe the separate forward map with one-hot sources, then arrange rows."""
    columns = []
    for coordinate in range(source_length):
        basis = tuple(int(j == coordinate) for j in range(source_length))
        columns.append(forward_reference(basis, kernel, stride, padding, dilation))
    return tuple(tuple(row) for row in zip(*columns))


def matrix_transpose_reference(values, kernel, stride, padding, dilation, source_length):
    matrix = forward_matrix_reference(source_length, kernel, stride, padding, dilation)
    if len(matrix) != len(values):
        raise AssertionError("fixture forward map has the wrong output dimension")
    return tuple(sum(matrix[row][column] * values[row] for row in range(len(values)))
                 for column in range(source_length))


def dot(left, right):
    assert len(left) == len(right)
    return sum(a * b for a, b in zip(left, right))


def rejects(*args):
    try:
        transpose_1d(*args)
    except ValueError:
        return True
    return False


def run_example():
    values, kernel = (2, 3), (1, 2, 4)
    short = transpose_1d(values, kernel, 2, 1, 1, 0)
    long = transpose_1d(values, kernel, 2, 1, 1, 1)
    matrix3 = forward_matrix_reference(3, kernel, 2, 1, 1)
    matrix4 = forward_matrix_reference(4, kernel, 2, 1, 1)
    x = (1, -2, 4, 5)
    ax = forward_reference(x, kernel, 2, 1, 1)
    checks = {}
    checks["manual_asymmetric_extent_extension_is_nonzero"] = (
        short == (4, 11, 6) and long == (4, 11, 6, 12)
        and long[:-1] == short and long[-1] != 0)
    checks["two_forward_source_lengths_have_same_output_dimension"] = (
        matrix3 == ((2, 4, 0), (0, 1, 2))
        and matrix4 == ((2, 4, 0, 0), (0, 1, 2, 4))
        and len(matrix3) == len(matrix4) == len(values)
        and (len(short), len(long)) == (3, 4))
    checks["manual_adjoint_identity_uses_same_finite_forward_map"] = (
        ax == (-6, 26) and dot(ax, values) == dot(x, long) == 66
        and matrix_transpose_reference(values, kernel, 2, 1, 1, 4) == long)
    inverse_x = (1, 2, 3, 4)
    encoded = forward_reference(inverse_x, (1,), 2, 0, 1)
    not_inverse = transpose_1d(encoded, (1,), 2, 0, 1, 1)
    gain_x = (1, -2, 3)
    gain_encoded = forward_reference(gain_x, (2,), 1, 0, 1)
    gain_restored = transpose_1d(gain_encoded, (2,))
    checks["shape_restoration_does_not_invert_lost_samples_or_square_gain"] = (
        encoded == (1, 3) and not_inverse == (1, 0, 3, 0)
        and len(not_inverse) == len(inverse_x) and not_inverse != inverse_x
        and gain_encoded == (2, -4, 6) and gain_restored == (4, -8, 12)
        and gain_restored != gain_x)
    checks["asymmetric_scatter_taps_are_not_silently_reversed"] = (
        transpose_1d((1,), kernel) == (1, 2, 4)
        and transpose_1d((1,), tuple(reversed(kernel))) == (4, 2, 1)
        and matrix_transpose_reference((1,), kernel, 1, 0, 1, 3) == (1, 2, 4))
    checks["one_tap_stride_gaps_differ_from_nonzero_boundary_extension"] = (
        transpose_1d((2, -1), (1,), 3) == (2, 0, 0, -1)
        and transpose_1d((2, -1), (1,), 3, 0, 1, 2) == (2, 0, 0, -1, 0, 0)
        and long[-1] == 12)
    checks["dilated_tap_spacing_changes_effective_width"] = (
        transpose_1d((1, 2), (1, -1), 1, 0, 2) == (1, 2, -1, -2)
        and transpose_1d((1, 2), (1, -1)) == (1, 1, -2))
    full = transpose_1d(values, kernel, 2)
    checks["forward_padding_clips_transpose_contributions_at_both_edges"] = (
        full == (2, 4, 11, 6, 12) and short == full[1:-1]
        and transpose_1d(values, kernel, 2, 2) == (11,)
        and long == full[1:])
    checks["zero_data_and_zero_taps_keep_structural_output_length"] = (
        transpose_1d((0, 0, 0), (1, 0, -1), 3, 1, 2, 2) == (0,) * 11
        and transpose_1d(values, (0, 0, 0), 2, 1, 1, 1) == (0,) * 4)

    value_profiles = tuple(t for size in (1, 2) for t in product((-1, 0, 1), repeat=size))
    kernel_profiles = tuple(t for size in (1, 2, 3) for t in product((-1, 0, 1), repeat=size))
    candidates = admitted = nonpositive_lengths = compared_values = 0
    family_ok = True
    for u in value_profiles:
        for h in kernel_profiles:
            for stride in (1, 2, 3):
                for padding in (0, 1, 2):
                    for dilation in (1, 2):
                        for output_padding in range(stride):
                            candidates += 1
                            length = ((len(u) - 1) * stride - 2 * padding
                                      + dilation * (len(h) - 1) + output_padding + 1)
                            if length <= 0:
                                nonpositive_lengths += 1
                                continue
                            actual = transpose_1d(u, h, stride, padding, dilation, output_padding)
                            expected = matrix_transpose_reference(u, h, stride, padding, dilation, length)
                            test_x = tuple((j * 3 + len(h)) % 5 - 2 for j in range(length))
                            forward = forward_reference(test_x, h, stride, padding, dilation)
                            family_ok &= (actual == expected and len(actual) == length
                                          and dot(forward, u) == dot(test_x, actual))
                            admitted += 1
                            compared_values += length
    checks["finite_one_hot_forward_matrix_and_adjoint_cases_ONE_group"] = bool(
        family_ok and admitted > 0 and candidates == admitted + nonpositive_lengths)

    a, b, h = (1, -2, 3), (3, 1, -1), (2, -1, 3)
    summed = tuple(x + y for x, y in zip(a, b))
    ya = transpose_1d(a, h, 2, 1, 2, 1)
    yb = transpose_1d(b, h, 2, 1, 2, 1)
    checks["fixed_operator_linearity_and_sign_reversal_are_exact"] = (
        transpose_1d(summed, h, 2, 1, 2, 1) == tuple(x + y for x, y in zip(ya, yb))
        and transpose_1d(tuple(-x for x in a), h, 2, 1, 2, 1) == tuple(-x for x in ya))

    class IntSubclass(int):
        pass
    class TupleSubclass(tuple):
        pass
    coerced = []
    class IndexTrap:
        def __index__(self):
            coerced.append("coerced")
            return 1
    base = ((1, -1), (1, 2), 2, 0, 1, 0)
    invalid = []
    for bad in (None, [1], "1", TupleSubclass((1,)), (True,), (IntSubclass(1),),
                (1.0,), (float("nan"),), (float("inf"),), ("1",), (17,), (-17,), (IndexTrap(),)):
        invalid.append((bad,) + base[1:])
    for bad in (None, [1], "1", TupleSubclass((1,)), (True,), (IntSubclass(1),),
                (1.0,), (float("nan"),), ("1",), (5,), (-5,), (0, False), (IndexTrap(),)):
        invalid.append((base[0], bad) + base[2:])
    for parameter in range(2, 6):
        for bad in (True, False, IntSubclass(1), 1.0, "1", None, IndexTrap()):
            args = list(base); args[parameter] = bad; invalid.append(tuple(args))
    pulled = []
    def generator():
        pulled.append("pulled")
        yield 1
    checks["all_types_and_late_entries_validate_without_coercion_ONE_group"] = (
        all(rejects(*args) for args in invalid)
        and rejects(generator(), base[1], 2, 0, 1, 0)
        and rejects(base[0], generator(), 2, 0, 1, 0)
        and rejects((0,), (0, False), 1, 0, 1, 0)
        and pulled == [] and coerced == [])
    cap_values, cap_kernel = (16, -16) * 3, (4, -4, 4, -4)
    cap = transpose_1d(cap_values, cap_kernel, 3, 0, 2, 2)
    bounds_invalid = (
        ((), (1,), 1, 0, 1, 0), ((1,), (), 1, 0, 1, 0),
        ((0,) * 7, (1,), 1, 0, 1, 0), ((1,), (0,) * 5, 1, 0, 1, 0),
        ((1,), (1,), 0, 0, 1, 0), ((1,), (1,), 4, 0, 1, 0),
        ((1,), (1,), 1, -1, 1, 0), ((1,), (1,), 1, 3, 1, 0),
        ((1,), (1,), 1, 0, 0, 0), ((1,), (1,), 1, 0, 3, 0),
        ((1,), (1,), 2, 0, 1, -1), ((1,), (1,), 2, 0, 1, 2),
        ((1,), (1,), 1, 1, 1, 0), ((1,), (1,), 3, 1, 1, 1),
    )
    checks["inclusive_caps_output_padding_policy_and_nonpositive_lengths"] = (
        len(cap) == 24 and cap == matrix_transpose_reference(cap_values, cap_kernel, 3, 0, 2, 24)
        and all(rejects(*args) for args in bounds_invalid))
    before = repr((values, kernel, cap_values, cap_kernel))
    first = transpose_1d(values, kernel, 2, 1, 1, 1)
    transpose_1d((-16,), (-4,))
    second = transpose_1d(values, kernel, 2, 1, 1, 1)
    checks["fresh_immutable_outputs_and_inputs_without_hidden_state"] = (
        first == second == long and first is not second and type(first) is tuple
        and all(type(x) is int for x in first)
        and before == repr((values, kernel, cap_values, cap_kernel)))
    assert len(checks) == 14 and all(type(x) is bool and x for x in checks.values()), checks
    return {
        "runtime": {"python": platform.python_version(), "implementation": platform.python_implementation()},
        "dependencies": "Python standard library only; no PyTorch/TensorFlow/NumPy/model/audio execution",
        "units": "dimensionless synthetic integer coordinates and supplied real coefficients",
        "manual": {"values": values, "kernel": kernel, "stride": 2, "padding": 1, "dilation": 1,
                   "output_padding0": short, "output_padding1": long,
                   "forward_matrix_source_length3": matrix3, "forward_matrix_source_length4": matrix4,
                   "x": x, "forward_Ax": ax, "dot_Ax_u": dot(ax, values), "dot_x_ATu": dot(x, long)},
        "not_inverse": {"original_x": inverse_x, "forward_Ax": encoded, "transpose_ATAx": not_inverse,
                        "square_gain_x": gain_x, "square_gain_ATAx": gain_restored},
        "finite_family": {"value_profiles": len(value_profiles), "kernel_profiles": len(kernel_profiles),
                          "candidate_parameter_profiles": candidates, "admitted_positive_length_cases": admitted,
                          "nonpositive_length_profiles_excluded": nonpositive_lengths,
                          "compared_output_values": compared_values, "meaningful_groups": 1},
        "invalid_type_and_value_profiles_ONE_group": len(invalid) + 3,
        "invalid_bound_or_output_length_profiles_ONE_group": len(bounds_invalid),
        "maximum_declared_output_length": 24,
        "unique_executed_checks": len(checks), "checks": checks, "all_passed": True,
        "limitations": [
            "Real single-channel finite integer linear map, no batch/groups/bias/activation or complex adjoint.",
            "Own bounded profile requires output_padding < stride and positive selected output length.",
            "Transpose/adjoint is generally not an inverse, even when dimensions match.",
            "No learned weights, framework execution, filter design, speech quality, rate-conversion or hardware guarantee.",
            "Finite matrix comparisons form one check group, not a proof for all inputs or a timing benchmark.",
        ],
    }


if __name__ == "__main__":
    sys.stdout.buffer.write((json.dumps(run_example(), ensure_ascii=True, indent=2) + "\n").encode("ascii"))

مرجعِ مستقل از بردارهای تک‌واحدیِ فضایِ مبدأ شروع می‌کند. هر بردار را با صفرهای صریح و پنجره‌های لغزشی از نگاشتِ جلو عبور می‌دهد و ستون‌های ماتریس را می‌سازد؛ سپس ترانهادهٔ ماتریس را در u ضرب می‌کند. این مسیر، تابعِ پخشِ سهم‌ها، اعتبارسنجِ اصلی یا خروجیِ آن را برای ساختنِ جوابِ انتظار فراخوانی نمی‌کند.

چهارده گروهِ نام‌دار تعریف شده‌اند. خانوادهٔ محدود، بردارهای یک‌عضوی و دو‌عضوی و کرنل‌های تا سه عضو روی منفی یک، صفر و یک را با پارامترهایِ مجاز ترکیب می‌کند؛ حالتِ طولِ نامثبت کنار گذاشته می‌شود. تعدادِ واقعیِ حالت‌های پذیرفته و مختصاتِ مقایسه‌شده را خودِ اجرا ثبت می‌کند. تمامِ این خانواده یک گروه است؛ شمارِ داده‌ها جایِ شمارِ ادعاهای مستقل نمی‌نشیند.

{
  "runtime": {
    "python": "3.14.5",
    "implementation": "CPython"
  },
  "dependencies": "Python standard library only; no PyTorch/TensorFlow/NumPy/model/audio execution",
  "units": "dimensionless synthetic integer coordinates and supplied real coefficients",
  "manual": {
    "values": [
      2,
      3
    ],
    "kernel": [
      1,
      2,
      4
    ],
    "stride": 2,
    "padding": 1,
    "dilation": 1,
    "output_padding0": [
      4,
      11,
      6
    ],
    "output_padding1": [
      4,
      11,
      6,
      12
    ],
    "forward_matrix_source_length3": [
      [
        2,
        4,
        0
      ],
      [
        0,
        1,
        2
      ]
    ],
    "forward_matrix_source_length4": [
      [
        2,
        4,
        0,
        0
      ],
      [
        0,
        1,
        2,
        4
      ]
    ],
    "x": [
      1,
      -2,
      4,
      5
    ],
    "forward_Ax": [
      -6,
      26
    ],
    "dot_Ax_u": 66,
    "dot_x_ATu": 66
  },
  "not_inverse": {
    "original_x": [
      1,
      2,
      3,
      4
    ],
    "forward_Ax": [
      1,
      3
    ],
    "transpose_ATAx": [
      1,
      0,
      3,
      0
    ],
    "square_gain_x": [
      1,
      -2,
      3
    ],
    "square_gain_ATAx": [
      4,
      -8,
      12
    ]
  },
  "finite_family": {
    "value_profiles": 12,
    "kernel_profiles": 39,
    "candidate_parameter_profiles": 16848,
    "admitted_positive_length_cases": 15111,
    "nonpositive_length_profiles_excluded": 1737,
    "compared_output_values": 65781,
    "meaningful_groups": 1
  },
  "invalid_type_and_value_profiles_ONE_group": 57,
  "invalid_bound_or_output_length_profiles_ONE_group": 14,
  "maximum_declared_output_length": 24,
  "unique_executed_checks": 14,
  "checks": {
    "manual_asymmetric_extent_extension_is_nonzero": true,
    "two_forward_source_lengths_have_same_output_dimension": true,
    "manual_adjoint_identity_uses_same_finite_forward_map": true,
    "shape_restoration_does_not_invert_lost_samples_or_square_gain": true,
    "asymmetric_scatter_taps_are_not_silently_reversed": true,
    "one_tap_stride_gaps_differ_from_nonzero_boundary_extension": true,
    "dilated_tap_spacing_changes_effective_width": true,
    "forward_padding_clips_transpose_contributions_at_both_edges": true,
    "zero_data_and_zero_taps_keep_structural_output_length": true,
    "finite_one_hot_forward_matrix_and_adjoint_cases_ONE_group": true,
    "fixed_operator_linearity_and_sign_reversal_are_exact": true,
    "all_types_and_late_entries_validate_without_coercion_ONE_group": true,
    "inclusive_caps_output_padding_policy_and_nonpositive_lengths": true,
    "fresh_immutable_outputs_and_inputs_without_hidden_state": true
  },
  "all_passed": true,
  "limitations": [
    "Real single-channel finite integer linear map, no batch/groups/bias/activation or complex adjoint.",
    "Own bounded profile requires output_padding < stride and positive selected output length.",
    "Transpose/adjoint is generally not an inverse, even when dimensions match.",
    "No learned weights, framework execution, filter design, speech quality, rate-conversion or hardware guarantee.",
    "Finite matrix comparisons form one check group, not a proof for all inputs or a timing benchmark."
  ]
}

شاهدهایِ دستی، ابهامِ طول، رابطهٔ ضربِ داخلی، خطی‌بودن، جهتِ ضریب، شکافِ گام، فاصلهٔ ضرایب، مرزهایِ نوع و اندازه و تازگیِ خروجی نیز بررسی می‌شوند. حساب‌ها صحیحِ پایتون‌اند و تلورانسِ ممیزشناور نداریم. خروجیِ کامل، نسخهٔ واقعیِ مفسر و نتیجهٔ گروه‌ها را نگه می‌دارد؛ PyTorch، TensorFlow و NumPy در این فایل وارد یا اجرا نمی‌شوند.

۵. چهار پرسش دربارهٔ وارون، کیفیت و مرزِ مدل

قالبِ بازشده در کنار ورودیِ اصلی که هنوز قطعه‌های بازیابی‌نشده دارد
تصویر مفهومی: قالبِ بازشده در کنار ورودیِ اصلی که هنوز قطعه‌های بازیابی‌نشده دارد؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

پرسش اول: output_padding یک، یعنی افزودنِ صفر؟ پاسخ: خیر؛ در مثالِ دستی، طولِ بزرگ‌تر سهمِ دوازده را آشکار کرد. این پارامتر شکل را انتخاب می‌کند؛ مقدارِ مختصات از سهمِ ضرایب به دست می‌آید. در کرنلِ تک‌عضوی ممکن است جایگاهِ افزوده واقعاً صفر باشد، اما این شاهد را نمی‌توان به همهٔ کرنل‌ها تعمیم داد.

پرسش دوم: چرا شکلِ یکسان برای وارون‌بودن کافی نیست؟ پاسخ: گام می‌تواند مختصاتی را حذف کند و ترانهاده آن اطلاعات را حدس نمی‌زند. مثالِ ضرب در دو نیز نشان داد حتی بدونِ کاهشِ بُعد، ترانهاده لزوماً وارون نیست. ادعایِ وارون به رابطه‌ای جدا از برابریِ طول نیاز دارد.

پرسش سوم: چه رابطه‌ای را باید برای ترانهاده آزمایش کنیم؟ پاسخ: با همان کرنل، گام، مرز و فضایِ مبدأ، دو ضربِ داخلیِ اعلام‌شده باید برابر شوند. عوض‌کردنِ طول یا سیاستِ مرز، ماتریسِ A را عوض می‌کند؛ نمی‌توان یک سمت را از قراردادی دیگر آورد و فقط انتظارِ برابری داشت.

پرسش چهارم: این نتیجه بازسازی یا کیفیتِ صوت را تأیید می‌کند؟ پاسخ: خیر. بازسازیِ وزن‌دارِ STFT از تبدیلِ معکوس و مخرجِ پوشش استفاده می‌کرد؛ اینجا فقط ترانهادهٔ یک نگاشتِ محدود داریم. طراحیِ فیلترِ تغییرِ نرخ، آموزشِ رمزگشا، کیفیتِ گفتار و اجرایِ سخت‌افزاری آزمایش‌های دیگری می‌خواهند.

دو دامنهٔ دقیقِ منابع در ۳۰ مهر ۱۴۰۵ کامل خوانده شدند. نسخهٔ صفحهٔ PyTorch برابرِ 2.14 و نسخهٔ صفحهٔ TensorFlow برابرِ v2.16.1 است؛ هیچ‌کدام را انتشارِ تازه یا نسخهٔ اجرایِ این برنامه معرفی نمی‌کنیم. تاریخِ انتشارِ نخستِ صفحه‌ها معلوم فرض نشده و از تاریخِ دسترسی یا سرآیندِ وب استنتاج نمی‌شود. منابعِ مرتبط، متن‌هایِ ذخیره‌شده و قبلاً منتشرشده‌اند؛ مشاهدهٔ تازهٔ دسترس‌پذیریِ سایت یا تضمینِ همهٔ ورودی‌هایِ ممکن از این آزمایش به دست نمی‌آید.

منابع و مطالعهٔ بیشتر

بررسی منابع: ۳۰ مهر ۱۴۰۵. تحلیل‌ها و پیشنهادهای اجرایی، جمع‌بندی نویسنده‌اند.