見出し画像

生成AIはプログラムに使えるか?

 結局、アルゴリズムを知らないと使えない。取りあえず単純かつ極端な例をあげてみる。これはJPEGデコーダの一部IDCTの部分の実装になる。

Q. pythonで8x8のDCTを逆変換する関数を書いて

Chat GPT
以下はPythonで8x8のDCTを逆変換する関数の例です。この関数は、与えられた8x8のDCT係数行列を逆DCT変換して元の画像を復元します。

import numpy as np

def idct_8x8(dct_coeffs):
    """
    Perform inverse Discrete Cosine Transform (IDCT) on an 8x8 block.

    Args:
    - dct_coeffs: 8x8 array of DCT coefficients

    Returns:
    - img: 8x8 array of pixel values (uint8)
    """
    alpha = np.zeros((8, 8))
    alpha[0, :] = 1 / np.sqrt(8)
    alpha[1:, :] = np.sqrt(2 / 8)
    
    img = np.zeros((8, 8))
    
    for u in range(8):
        for v in range(8):
            sum_val = 0
            for x in range(8):
                for y in range(8):
                    sum_val += alpha[x, u] * alpha[y, v] * dct_coeffs[x, y] * np.cos((2 * x + 1) * u * np.pi / 16) * np.cos((2 * y + 1) * v * np.pi / 16)
            img[u, v] = sum_val

    img = np.clip(img + 128, 0, 255).astype(np.uint8)
    return img

 このコード恐らく正しいと思うけど、検証に時間がかかるのでパス。そもそもこのコードはダメ。理由は遅すぎて使えない。

Cでも変わらぬ

#include <stdio.h>
#include <math.h>

#define N 8

void idct_8x8(float dct_coeffs[N][N], unsigned char img[N][N]) {
    float alpha[N][N];
    int u, v, x, y;
    
    for (u = 0; u < N; u++) {
        for (v = 0; v < N; v++) {
            if (u == 0)
                alpha[u][v] = 1.0 / sqrt(N);
            else
                alpha[u][v] = sqrt(2.0 / N);
        }
    }

    for (u = 0; u < N; u++) {
        for (v = 0; v < N; v++) {
            float sum_val = 0.0;
            for (x = 0; x < N; x++) {
                for (y = 0; y < N; y++) {
                    sum_val += alpha[x][u] * alpha[y][v] * dct_coeffs[x][y] *
                               cos((2 * x + 1) * u * M_PI / (2 * N)) *
                               cos((2 * y + 1) * v * M_PI / (2 * N));
                }
            }
            img[u][v] = (unsigned char)(sum_val + 128);
        }
    }
}

だから使い物にならないと。そもそもcos関数が遅い。

  現在使われて居るライブラリの100倍以上遅くなるかと……。GPUで8x8行列を一度に計算すればあまり差は出ないかも知れないけど。

Q. LL&M : The Loeffler-Ligtenberg-Moschytz (LLM) algorithm を使ってください

#include <stdio.h>
#include <math.h>

#define N 8

void idct_8x8(float dct_coeffs[N][N], unsigned char img[N][N]) {
    int x, y, u, v;
    float F[N][N];
    float CU[N], CV[N];
    float tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
    float tmp10, tmp11, tmp12, tmp13;
    float z1, z2, z3, z4, z5;
    
    // Precompute CU and CV
    for (u = 0; u < N; u++) {
        CU[u] = (u == 0) ? 1.0 / sqrt(2) : 1.0;
        CV[u] = (u == 0) ? 1.0 / sqrt(2) : 1.0;
    }
    
    // Compute intermediate variables
    for (x = 0; x < N; x++) {
        for (y = 0; y < N; y++) {
            float sum = 0.0;
            for (u = 0; u < N; u++) {
                for (v = 0; v < N; v++) {
                    sum += dct_coeffs[u][v] * cos((2 * x + 1) * u * M_PI / 16) * cos((2 * y + 1) * v * M_PI / 16) *
                           CU[u] * CV[v];
                }
            }
            F[x][y] = sum * 0.25;
        }
    }

    // Compute output values
    for (x = 0; x < N; x += 2) {
        for (y = 0; y < N; y += 2) {
            tmp0 = F[x][y] + F[x][y+1];
            tmp1 = F[x][y] - F[x][y+1];
            tmp2 = F[x+1][y] + F[x+1][y+1];
            tmp3 = F[x+1][y] - F[x+1][y+1];

            tmp10 = tmp0 + tmp2;
            tmp13 = tmp0 - tmp2;
            tmp11 = tmp1 + tmp3;
            tmp12 = tmp1 - tmp3;

            img[x][y]     = (unsigned char)(tmp10 + tmp11);
            img[x][y+1]   = (unsigned char)(tmp12 + tmp13);
            img[x+1][y]   = (unsigned char)(tmp10 - tmp11);
            img[x+1][y+1] = (unsigned char)(tmp13 - tmp12);
        }
    }
}

 半分しか適用されていない……。

この記事が気に入ったらサポートをしてみませんか?