1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LLMにマイナー言語をプログラミングさせてみた

Last updated at Posted at 2025-03-05

本記事概要

LLMにお遊びでプログラミングさせてみたので、それを語りたくなっただけです。
一応検証記事ではありますが、実用というより、ネタ記事と思ってください。

やったこと

Github等主要リポジトリで公開されているコードも少ないと思われる下記プログラミング言語について、主要なLLMでコーディングさせてみました。

書かせた言語

  • なでしこ
    • 日本語プログラミング言語としては本流中の本流
    • ただ、日本語プログラミング言語自体が業務領域においてはマイナーです(開発者の方、利用者の方々すみません💦)
  • WhiteSpace
    • いわゆる難読プログラム言語です
  • アセンブラ
    • この中では最も主流になりますし、今でも十分使われますが、高級言語ほどのシェアは流石にありません
    • x64アーキテクチャ向けのAT&T記法です

※なお私は上記いずれの言語についても詳しくありません。もし本記事中に当該言語についての誤りがあった場合、それは私の無知に起因します。コメント欄でご指摘、ご教示いただけますと幸いです。

使ったLLM

コーディングに用いたLLMは下記の通りです

  • ChatGPT 4o, 一部、o3-mini-high
  • Gemini 2.0 Flash
  • Mercury Coder
    • inceptionが2/28に発表した拡散モデルを取り入れたdLLM(diffusion large language model)
    • https://www.inceptionlabs.ai/news
    • Diffusion EffectをOnにすると、アニメーションが楽しい

ザクっと結果だけ書く

マイナー言語が書けるか

LLM なでしこ WhiteSpace
ChatGPT ⚪︎ ⚪︎
Gemini ⚪︎ ×
Mercury Coder × ×

アセンブラコーディング能力

ビルド アルゴリズム 速度
C言語最適化なし バブルソート 211.209msec
C言語O2 バブルソート 98.178msec
アセンブラ バブルソート 102.476msec
C言語標準(qsort) クイックソート 1.308msec
アセンブラ クイックソート 1.769msec

※アセンブラコーディングはChatGPTのみ

なでしこを書かせてみた

書かせたもの

ダイクストラのアルゴリズム

なお私はなでしこの実行環境を持っていないので動作未検証です。

ChatGPT

; ダイクストラのアルゴリズム実装 (隣接行列を使用)
●ダイクストラ(始点, グラフ)とは
  各ノード数=グラフの要素数
  無限=999999
  距離=配列作成(各ノード数, 無限) ; 最短距離を格納する配列
  訪問済み=配列作成(各ノード数, 偽) ; ノードの訪問状態
  距離[始点]=0

  ここから各ノード数回繰り返す
    現在ノード=-1
    最小距離=無限

    ; 最小距離のノードを見つける
    ここから各ノード数回繰り返す
      もし「(訪問済み[対象回数]が偽)かつ(距離[対象回数]<最小距離)」ならば
        最小距離=距離[対象回数]
        現在ノード=対象回数
      ここまで

    ; もし、全てのノードを訪問済みなら終了
    もし「現在ノード=-1」ならば
      「全てのノードを訪問しました。」と表示
      抜ける
    ここまで

    ; 現在ノードを訪問済みにする
    訪問済み[現在ノード]=真

    ; 隣接ノードを確認し、最短距離を更新
    ここから各ノード数回繰り返す
      経路長=グラフ[現在ノード][対象回数]
      もし「経路長>0」ならば
        新距離=距離[現在ノード]+経路長
        もし「新距離<距離[対象回数]」ならば
          距離[対象回数]=新距離
        ここまで
      ここまで
    ここまで
  ここまで

  ; 最短距離を表示
  「最短距離:」と表示
  ここから各ノード数回繰り返す
    「ノード{対象回数}までの距離は{距離[対象回数]}です。」と表示
  ここまで
ここまで

; 使用するグラフ (隣接行列形式)
グラフ=[
  [0, 2, 5, 0, 0],
  [2, 0, 4, 6, 0],
  [5, 4, 0, 2, 8],
  [0, 6, 2, 0, 3],
  [0, 0, 8, 3, 0]
]

; 始点ノードを設定
始点=0

; アルゴリズムを実行
ダイクストラ(始点, グラフ)

Genini

// ダイクストラ法
ダイクストラ(グラフ, 開始ノード)とは
  距離リスト=[:]
  確定リスト=[:]
  優先度キュー=[開始ノード]
  距離リスト[開始ノード]=0

  優先度キューが空でない間、繰り返す
    現在ノード=優先度キューから最小距離のノードを取得(距離リスト)
    確定リスト[現在ノード]=真

    もし、グラフ[現在ノード]があれば
      グラフ[現在ノード]の各隣接ノードと距離について繰り返す
        もし、確定リスト[隣接ノード]が真なら、継続
        新しい距離=距離リスト[現在ノード]+距離
        もし、距離リスト[隣接ノード]がないか、距離リスト[隣接ノード]>新しい距離なら
          距離リスト[隣接ノード]=新しい距離
          優先度キューに隣接ノードを追加
        終わり
      終わり
    終わり
  終わり
  戻る 距離リスト

// 優先度キューから最小距離のノードを取得
優先度キューから最小距離のノードを取得(距離リスト)とは
  最小距離=無限大
  最小ノード=なし
  優先度キューの各ノードについて繰り返す
    もし、距離リスト[ノード]があれば
      もし、距離リスト[ノード]<最小距離なら
        最小距離=距離リスト[ノード]
        最小ノード=ノード
      終わり
    終わり
  終わり
  もし、最小ノードがあれば
    優先度キューから最小ノードを削除
  終わり
  戻る 最小ノード

// サンプルグラフ
グラフ=[:]
グラフ["A"]=[["B", 2], ["C", 4]]
グラフ["B"]=[["A", 2], ["C", 1], ["D", 5]]
グラフ["C"]=[["A", 4], ["B", 1], ["D", 8], ["E", 10]]
グラフ["D"]=[["B", 5], ["C", 8], ["E", 2], ["F", 6]]
グラフ["E"]=[["C", 10], ["D", 2], ["F", 3]]
グラフ["F"]=[["D", 6], ["E", 3]]

// 開始ノード
開始ノード="A"

// ダイクストラ法を実行
結果=ダイクストラ(グラフ, 開始ノード)

// 結果を表示
結果を「結果:」で表示する

Mercury Coder

import heapq

def dijkstra(graph, start):
    # 始点から各ノードへの最短距離を無限大で初期化
    distances = {node: float('infinity') for node in graph}
    distances[start] = 0
    
    # プライオリティキュー(最小ヒープ)を用意
    priority_queue = [(0, start)]
    
    while priority_queue:
        # 現在の距離が最も小さいノードを取り出す
        current_distance, current_node = heapq.heappop(priority_queue)
        
        # 現在のノードの距離が既に計算された距離よりも大きい場合、スキップ
        if current_distance > distances[current_node]:
            continue
        
        # 隣接ノードを処理
        for neighbor, weight in graph[current_node].items():
            distance = current_distance + weight
            
            # 新しい距離が既存の距離よりも短い場合、更新
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(priority_queue, (distance, neighbor))
    
    return distances

# グラフの定義
graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}

# 始点を指定
start_node = 'A'

# ダイクストラのアルゴリズムを実行
shortest_distances = dijkstra(graph, start_node)

# 結果を表示
print(shortest_distances)

Pythonである…

WhiteSpaceを書かせてみた

書かせたもの

下記のFizzBuzz

  • 1-100を数える
  • 3の倍数、または3がつく場合は「Three!」と表示
  • それ以外の場合は、その数字を表示

なお私はWhiteSpaceの実行環境を持っていないので動作未検証です。

ChatGPT

        


   		 
   	   

		 
   		 
   	   
	
	
	
		 
   		 
   		 
   	   

	
	
	
		 
   		 
   	   
   	   
	
   		 
   		 
   	   
	

		 
		 
   
		 



	
   		 
   	   

	
	
	
		 
   		 
   		 
   	   
	

   		 
   		 
   		 
   	   
	
   		 
   		 
   	   
	

   		 
   		 
   	   
   		 
   		 
   	   



   		 
   		 
   	   
   	   

		 
   		 
   		 
   	   
	

   		 
   		 
   	   

	
	
	
		 
   		 
   		 
   	   

   		 
   		 
   	   
   		 
   		 
   	   



   		 
   		 
   	   
   	   

		 
   		 
   		 
   	   
	


   		 
   		 
   	   

	
	
	
		 
   		 
   		 
   	   

   		 
   		 
   	   
   		 
   		 
   	   



   		 
   		 
   	   
   	   

		 
   		 
   		 
   	   
	


        
   		 
		 
	
		 
			

書けた。
当初は、スペースを[S]、タブを[T]、改行を[L]としたまだしも眼にみえるコードを出してくれたが、散々説得してちゃんとWhiteSpaceにしてもらいました。手こずらせやがって…。

Gemini

書いてくれず。

可読性が低い、実用的でないなど色々言っていました。

Mercury Coder

  (Push 1 onto the stack)
\t (Push 100 onto the stack)
\n (Define a label for the loop start)

  (Duplicate the top of the stack)
  (Push 100 onto the stack)
  (Compare the top two elements of the stack)
  (If less than, jump to the end of the loop)
  (Jump to the label defined earlier)

  (Duplicate the top of the stack)
  (Convert to string)
  (Push "Three!" onto the stack)
  (Output the top of the stack as a string)
  (Pop the top of the stack)

  (Duplicate the top of the stack)
  (Push 3 onto the stack)
  (Modulo operation)
  (Push 0 onto the stack)
  (Compare the top two elements of the stack)
  (If not equal, jump to the next condition)
  (Jump to the label defined earlier)

  (Duplicate the top of the stack)
  (Convert to string)
  (Output the top of the stack as a string)
  (Pop the top of the stack)

  (Increment the top of the stack)
  (Jump back to the loop start)

  (End of the program)

書こうとしてくれた努力は見えます。
が、それはWhiteSpaceではない…

アセンブラを書かせてみた

極めた人が書くと超高速だというアセンブラをChatGPTに書かせて、他のビルド方法と比較してみました。

ちょっと苦労話

書かせるのはすんなり行きました。
が、コンパイルが通らない、コンパイルが通っても想定通りに動かない…

ChatGPT 4oに書かせて、Geminiに書かせてうまくいかず、最終的にChatGPT o3-mini highの書いたコードがうまく動きました。

なのでアセンブラの実証は、ChatGPTのみです。

バブルソート

コード

sort_int.s
    .text
    .globl sort_int
    .type sort_int, @function
sort_int:
    pushq   %rbp
    movq    %rsp, %rbp
    pushq   %rbx
    pushq   %r12
    pushq   %r13
    pushq   %r14

    # r12 = num (配列の要素数)
    movq    %rsi, %r12
    cmpq    $1, %r12
    jle     sort_end       # 要素数が1以下なら何もせず終了

    xorl    %ebx, %ebx    # i = 0 を rbx にセット

outer_loop:
    # 外側ループ終了条件: if (i >= num - 1) exit
    movq    %r12, %rax    # rax = num
    decq    %rax          # rax = num - 1
    cmpq    %rax, %rbx    # compare i and (num - 1): if (rbx >= rax)
    jge     sort_end

    xorl    %r13d, %r13d  # j = 0 を r13 にセット

inner_loop:
    # 内側ループ終了条件: if (j >= num - i - 1) break
    movq    %r12, %rax    # rax = num
    subq    %rbx, %rax    # rax = num - i
    decq    %rax          # rax = num - i - 1
    cmpq    %rax, %r13    # compare j and (num - i - 1): if (r13 >= rax)
    jge     next_outer

    # array[j] を %eax、array[j+1] を %edx にロード
    movl    (%rdi, %r13, 4), %eax    # %eax = array[j]
    movl    4(%rdi, %r13, 4), %edx    # %edx = array[j+1]
    cmpl    %edx, %eax               # if (array[j] <= array[j+1]) は %eax - %edx <= 0
    jle     no_swap

    # swap: array[j] と array[j+1] を交換
    movl    %edx, (%rdi, %r13, 4)
    movl    %eax, 4(%rdi, %r13, 4)

no_swap:
    incl    %r13d         # j++
    jmp     inner_loop

next_outer:
    incq    %rbx          # i++
    jmp     outer_loop

sort_end:
    popq    %r14
    popq    %r13
    popq    %r12
    popq    %rbx
    popq    %rbp
    ret

比較対象コード

sort_int.c
#include "sort_int.h"

void sort_int(int *array, int num) {
    int temp;
    // バブルソートの実装
    for (int i = 0; i < num - 1; i++) {
        for (int j = 0; j < num - i - 1; j++) {
            if (array[j] > array[j+1]) {
                // 隣接する要素を入れ替え
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
}

比較対象のコードもChatGPTに実装させました。

参考:ヘッダ、mainのソース

なお、参考までにヘッダとmain、コンパイルコマンドも書いておきます。

sort_int.h
#ifndef SORT_INT_H
#define SORT_INT_H

// 与えられたint配列をバブルソートで並び替える関数の宣言
void sort_int(int *array, int num);

#endif /* SORT_INT_H */
main.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "sort_int.h"  // sort_int の宣言が含まれているヘッダファイル

int main(void) {
    FILE *fp = fopen("int.txt", "r");
    if (fp == NULL) {
        perror("int.txt のオープンに失敗しました");
        return EXIT_FAILURE;
    }

    const int num_count = 10000;
    int *array = malloc(sizeof(int) * num_count);
    if (array == NULL) {
        perror("メモリ確保に失敗しました");
        fclose(fp);
        return EXIT_FAILURE;
    }

    // int.txt から 1 万個の整数を読み込む
    for (int i = 0; i < num_count; i++) {
        if (fscanf(fp, "%d", &array[i]) != 1) {
            fprintf(stderr, "インデックス %d での読み込みに失敗しました\n", i);
            free(array);
            fclose(fp);
            return EXIT_FAILURE;
        }
    }
    fclose(fp);

    struct timeval start, end;
    // ソート前の時刻を取得
    if (gettimeofday(&start, NULL) != 0) {
        perror("開始時刻の取得に失敗しました");
        free(array);
        return EXIT_FAILURE;
    }

    // int 配列をソート (sort_int の実装は外部に依存)
    sort_int(array, num_count);

    // ソート後の時刻を取得
    if (gettimeofday(&end, NULL) != 0) {
        perror("終了時刻の取得に失敗しました");
        free(array);
        return EXIT_FAILURE;
    }

    // 経過時間をミリ秒単位で計算
    long seconds = end.tv_sec - start.tv_sec;
    long microseconds = end.tv_usec - start.tv_usec;
    double elapsed_ms = seconds * 1000.0 + microseconds / 1000.0;

    printf("ソート処理時間: %.3f ミリ秒\n", elapsed_ms);

    free(array);
    return 0;
}

ご覧の通り、sort_int()の前後で時刻を取り、その差分から処理時間を計測しています。

コンパイルは次のとおりです。

最適化なし
gcc -o sort_c main.c sort_int.c
最適化O2
gcc -o sort_c -O2 main.c sort_int.c

クイックソート

コード

sort_int.s
    .text
    .globl sort_int
    .type sort_int, @function
# sort_int(array, num)
#   if (num > 1)
#       quicksort_internal(array, 0, num-1)
sort_int:
    pushq   %rbp
    movq    %rsp, %rbp
    cmpq    $1, %rsi           # if (num <= 1)
    jle     .Lsort_end
    movq    %rsi, %rdx         # rdx = num
    decq    %rdx               # rdx = num - 1 (high index)
    movl    $0, %esi           # low index = 0
    call    quicksort_internal
.Lsort_end:
    popq    %rbp
    ret

    .globl quicksort_internal
    .type quicksort_internal, @function
# quicksort_internal(array, low, high)
#   if (low < high) then:
#       pivot = partition(array, low, high)
#       quicksort_internal(array, low, pivot - 1)
#       quicksort_internal(array, pivot + 1, high)
quicksort_internal:
    pushq   %rbp
    movq    %rsp, %rbp
    pushq   %rbx
    pushq   %r12
    pushq   %r13
    pushq   %r14
    # rdi: array, rsi: low, rdx: high

    movl    %esi, %r12d        # r12d = low
    cmpl    %edx, %r12d        # if (low >= high) then return
    jge     .Lqsort_ret

    movl    %edx, %r14d        # r14d = high (保存しておく)

    call    partition          # partition(array, low, high)
    # partition の戻り値(pivot のインデックス)が eax に入る
    movl    %eax, %r13d        # r13d = pivot

    # 左側の再帰呼び出し: quicksort_internal(array, low, pivot - 1)
    # ここで low は r12d に保存済み
    movq    %rdi, %rdi        # array はそのまま
    movl    %r12d, %esi       # low を rsi に
    movl    %r13d, %eax
    subl    $1, %eax          # pivot - 1
    movl    %eax, %edx        # high = pivot - 1
    call    quicksort_internal

    # 右側の再帰呼び出し: quicksort_internal(array, pivot + 1, original high)
    movq    %rdi, %rdi        # array はそのまま
    movl    %r13d, %eax
    addl    $1, %eax          # pivot + 1
    movl    %eax, %esi       # low = pivot + 1
    movl    %r14d, %edx       # high = 保存しておいた original high
    call    quicksort_internal

.Lqsort_ret:
    popq    %r14
    popq    %r13
    popq    %r12
    popq    %rbx
    popq    %rbp
    ret

    .globl partition
    .type partition, @function
# partition(array, low, high)
#   pivot = array[high]
#   i = low - 1
#   for (j = low; j < high; j++) {
#       if (array[j] <= pivot) { i++; swap(array[i], array[j]); }
#   }
#   swap(array[i+1], array[high])
#   return i+1
partition:
    pushq   %rbp
    movq    %rsp, %rbp
    pushq   %rbx
    pushq   %r8
    pushq   %r9
    pushq   %r10
    # rdi: array, rsi: low, rdx: high

    # i = low - 1
    movl    %esi, %r8d       # r8d = low
    decl    %r8d             # r8d = low - 1

    # pivot = array[high]
    movl    (%rdi, %rdx, 4), %r10d  # r10d = pivot

    # j = low
    movl    %esi, %r9d       # r9d = j

.Lpart_loop:
    cmpl    %edx, %r9d       # if (j >= high) → exit loop
    jge     .Lpart_after_loop

    movl    (%rdi, %r9, 4), %ebx   # ebx = array[j]
    cmpl    %r10d, %ebx           # if (array[j] <= pivot)?
    jg      .Lpart_skip           # if array[j] > pivot, skip

    incl    %r8d                # i++
    # swap array[i] and array[j]
    movl    (%rdi, %r8, 4), %ecx   # ecx = array[i]
    movl    %ebx, (%rdi, %r8, 4)    # array[i] = array[j]
    movl    %ecx, (%rdi, %r9, 4)    # array[j] = ecx

.Lpart_skip:
    incl    %r9d                # j++
    jmp     .Lpart_loop

.Lpart_after_loop:
    incl    %r8d                # i++
    # swap array[i] and array[high]
    movl    (%rdi, %r8, 4), %ecx   # ecx = array[i]
    movl    (%rdi, %rdx, 4), %ebx   # ebx = array[high]
    movl    %ebx, (%rdi, %r8, 4)    # array[i] = array[high]
    movl    %ecx, (%rdi, %rdx, 4)    # array[high] = ecx

    movl    %r8d, %eax         # return pivot index = i in eax

    popq    %r10
    popq    %r9
    popq    %r8
    popq    %rbx
    popq    %rbp
    ret

バブルソートを実装させたチャットから続けて、o3-mini highで実装させたせいか、一発で動きました。
なのでo3-mini highがすごいのかどうかはちょっとわからず…

比較対象コード

sort_int.c
#include "sort_int.h"
#include <stdlib.h>

// qsort 用の比較関数(昇順)
static int compare_int(const void *a, const void *b) {
    int ia = *(const int *)a;
    int ib = *(const int *)b;
    if (ia < ib) return -1;
    else if (ia > ib) return 1;
    else return 0;
}

void sort_int(int *array, int num) {
    qsort(array, num, sizeof(int), compare_int);
}

自前で実装させようと思いましたが、C言語のqsort()がほぼクイックソートなのでこれをそのまま使いました。
(厳密にはクイックソートだけではないらしいですね。ソース見たことありませんが…)

ヘッダとmain.cはバブルソートと同じなので省略します。
コンパイルも最適化なしと同じコマンドです。

結果

ビルド アルゴリズム 速度
C言語最適化なし バブルソート 211.209msec
C言語O2 バブルソート 98.178msec
アセンブラ バブルソート 102.476msec
C言語標準(qsort) クイックソート 1.308msec
アセンブラ クイックソート 1.769msec

現在のコンパイラって性能高いんですね…
中間コードは吐き出させてないので、ChatGPTに書かせたアセンブラとの比較はしていません(し、アセンブラほとんど読めないのでできません)。

またクイックソートの方も僅差で標準ライブラリの方が早いです。
相当こなれた実装なのだろうなと思います。

考察

ただのネタ記事で終わっても良かったのですが、Qiitaなのである程度この記事を読んでくれた方に有益な示唆を残せるよう考察をします。

なでしこについて

現在の主要なLLMは日本語文献の割合が少ないです。確か1%とかそんなものだったかと思います。
と言っても、全体の量が莫大なため、割合が少なくても高精度に動くそうです。

なでしこは日本語プログラミング言語としては歴史が長く、文献は相応に存在します。
ただ他言語に比べるとソース量はデータセットの中においても非常に少ないあるいは存在しない可能性もあるかと思います。

言語仕様の文献はデータセットに含まれているとすれば、あとは実装例から学習されたのではなく、LLM自身の「推論」で実装されたのでないかと考えています。

Mercury Coderについては、そもそも「なでしこ」というプログラミング言語自体を知らないかのような挙動でした。おそらくそもそもデータセットになかったのでしょう。

WhiteSpace

こちらも同様でおそらくWhiteSpaceの実際の実装例なんて海外のリポジトリ等をみてもほぼないレベルでしょう。
こちらについても言語仕様(と言ってもほとんどメモリ操作のレベル)からすべき操作を「推論」して、実装したものと思われます。

おそらくChatGPTの方がその推論能力において、Geminiより高かったのかと思います。
(Geminiの他のハイエンドなモデルならあるいは実装できたのかもしれません)

Mercury Coderについては、これはあるいは拡散モデルでの実装の弱点なのかもしれません。
チャットを見ると間違いなく存在は知っており、コーディングを試みた形跡もあります。
しかし、出てきたものは、WhiteSpaceの3文字からなるコードではありませんでした。

WhiteSpaceは言語としてみたときに文法と語彙があまりにも異質です。

ChatGPTやGeminiの基礎になっているTransformerが連続的に文を紡ぐのに対し、Diffusionはノイズから全体を成型していきます。
このとき、スペース・タブ・改行の3文字しかないWhiteSpaceだと、命令語としての空白・タブ・改行と、文を構成する文字としての空白・タブ・改行が異なるものとして判断されづらいのかもしれません。

同じようにアセンブラもまた言語としてみたときに、文法・語彙が異質です。
しかし、Mercury Coderでもアセンブラは実装できました(動作未確認)。これはWhiteSpaceに比べ、使用する語彙がはるかに多いこと、学習したソース量が多く文法を推論しやすいからかもしれません。

アセンブラ

どのLLMでも実装できるだろうなと思っていましたが、やはり文法として異質かつソースの学習量からか、他の言語に比べるとうまく動かすのに苦労しました。

しかし、ChatGPTの推論過程を見ると、「きちんと文法」と「語彙の意味」を理解し、「思考」を重ねて実装、ソースを修正していったのがわかりました。

AIにプログラムさせるのは、私も日常的にやっていますが、それでも現在のLLMの推論能力は高いレベルにあるなと感じました。

最後に

実装させたChatGPTのチャットを共有しておきます。

チャットログ(ChatGPT, なでしこ、WhiteSpace)

チャットログ(ChatGPT, アセンブラ)

またこれはおまけでプログラミングするAIが出始めの頃に遊んだときの記事です。

よろしければこちらもご覧ください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?