Python – DECODE https://decode.red/blog data decode, decoder or decoded ... design of code Mon, 15 Dec 2025 06:15:00 +0000 ja hourly 1 https://wordpress.org/?v=4.7.29 Polynomial Regression Model ../../../202504191886/ Sat, 19 Apr 2025 06:03:07 +0000 ../../../?p=1886 3つの変数から導かれる結果について、多項式回帰モデルを使って見える化をしてみました。
target_functionは対象の任意の関数とします。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import animation
from mpl_toolkits.mplot3d import Axes3D
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split

# --- 任意の非線形関数 ---
def target_function(x1, x2, x3):
    #return 2 * x1**2 - 3 * x2 + 1.5 * x3**2 + 4 * x1 * x3 + np.random.normal(0, 2, size=x1.shape)
    return 2 * x1**3 - 3 * x2**3 + 1.5 * x3 + 4 * x1 * x3**2 + 2000*np.random.rand(x1.shape[0]) - 1000

# --- データ生成 ---
np.random.seed(42)
n_samples = 200
x1 = np.random.uniform(0, 10, n_samples)
x2 = np.random.uniform(0, 10, n_samples)
x3 = np.random.uniform(0, 10, n_samples)
y = target_function(x1, x2, x3)


df = pd.DataFrame({'x1': x1, 'x2': x2, 'x3': x3, 'y': y})
X = df[['x1', 'x2', 'x3']]
y = df['y']

# --- 特徴量変換と学習 ---
poly = PolynomialFeatures(degree=3, include_bias=False)
X_poly = poly.fit_transform(X)

X_train, X_test, y_train, y_test = train_test_split(X_poly, y, test_size=0.2, random_state=42)
model = LinearRegression().fit(X_train, y_train)

# --- 評価 ---
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)


print(f"x1の範囲: {x1.min():.2f} 〜 {x1.max():.2f}")
print(f"x1の標準偏差: {x1.std():.2f}")
print(f"x2の範囲: {x2.min():.2f} 〜 {x2.max():.2f}")
print(f"x2の標準偏差: {x2.std():.2f}")
print(f"x3の範囲: {x3.min():.2f} 〜 {x3.max():.2f}")
print(f"x3の標準偏差: {x3.std():.2f}")
print(f"yの範囲: {y.min():.2f} 〜 {y.max():.2f}")
print(f"yの標準偏差: {y.std():.2f}")

print(f"📊 モデル評価")
print(f"  - MSE: {mse:.3f}")
print(f"  - R² : {r2:.3f}")

# --- 3D アニメーション ---
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')

grid_x1, grid_x2 = np.meshgrid(np.linspace(0, 10, 30), np.linspace(0, 10, 30))

def update(frame):
    ax.clear()
    fixed_x3 = frame
    grid_x3 = np.full_like(grid_x1, fixed_x3)

    # グリッド点 → DataFrameに変換(列名つけるのが重要)
    grid_points = np.c_[grid_x1.ravel(), grid_x2.ravel(), grid_x3.ravel()]
    grid_df = pd.DataFrame(grid_points, columns=['x1', 'x2', 'x3'])

    # モデル予測
    grid_poly = poly.transform(grid_df)
    grid_y = model.predict(grid_poly).reshape(grid_x1.shape)

    # 回帰面
    ax.plot_surface(grid_x1, grid_x2, grid_y, color='orange', alpha=0.6)

    # 実データ(x3 ≈ frame)
    mask = np.isclose(df['x3'], fixed_x3, atol=0.5)
    ax.scatter(df.loc[mask, 'x1'], df.loc[mask, 'x2'], df.loc[mask, 'y'],
               color='blue', alpha=0.5)

    # 軸・表示
    ax.set_xlabel('x1')
    ax.set_ylabel('x2')
    ax.set_zlabel('y')
    ax.set_title(f'Polynomial Regression Surface (x3={fixed_x3:.1f})')
    ax.set_zlim(y.min(), y.max())

ani = animation.FuncAnimation(fig, update, frames=np.linspace(0, 9, 10), interval=1000)
plt.show()

3次元では、2つの変数までしか扱えませんので、x3を固定化しますが、アニメーションによりx3を動かしてみました。

PolynomialFeaturesのdegreeを1にした場合

以上、ChatGPTとの対話から作成しました。
まずシンプルな動作できる形をAIで作っておいて、あとは手作業で作り込んでいくという、こういうコーディングの仕方は、本当に便利です。

]]>
Auto Encoder ../../../202405041767/ Sat, 04 May 2024 01:46:02 +0000 ../../../?p=1767 ディープラーニングの手法のひとつであるオートエンコーダについて、下記書籍を参考に自環境で試してみました。

「音楽で身につけるディープラーニング」(北原鉄朗著/オーム社)

環境)Python3 / WSL2 (GeForce)

オートエンコーダというのは、入力と出力に同じデータを与えてネットワークを学習させるもので、中間層には圧縮されたベクトルが得られます。(16次元)
ここでは、3次元についてもテストしていて、3次元は図示できるので再度学習して長調、短調で色分けしています。(とても興味深い結果です)つまりこのベクトルは、データの特徴を表すものとえいます。

from input_midi import *
from add_rest import *
from play_midi import *

from sklearn.model_selection import train_test_split
import tensorflow as tf

# 自感環境用変数
# export PATH=/usr/local/cuda-12.1/bin:$PATH

import glob

dir = "./midi/"

x_all = []       # 入力データ(ソプラノメロディ)を格納する配列
y_all = []       # 出力データ(アルトメロディ)を格納する配列
keymodes = []    # 長調か短調かを格納する配列
files = []       # 読み込んだMIDIファイルのファイル名を格納する配列

for f in glob.glob(dir + "/*.mid"):
  try:
    # MIDIファイルを読み込む
    pr_s,  pr_a, keymode = read_midi(f, True, 64)
    # ピアノロール2値行列に休符要素を追加する
    x = add_rest_nodes(pr_s)
    y = add_rest_nodes(pr_a)
    x_all.append(x)
    y_all.append(y)
    keymodes.append(keymode)
    files.append(f)
  except UnsupportedMidiFileException:
    print("skip")

# NumPy配列に変換する
x_all = np.array(x_all)
y_all = np.array(y_all)

np.save('x_all', x_all)
np.save('y_all', y_all)
# 二回目以降データ作成省略用
#x_all = np.load('x_all.npy')
#y_all = np.load('y_all.npy')


# 学習データとテストデータを分割する
i_train, i_test = train_test_split(range(len(x_all)),
                                  test_size=int(len(x_all)/2),
                                  shuffle=False)
x_train = x_all[i_train]
x_test = x_all[i_test]
y_train = y_all[i_train]
y_test = y_all[i_test]

# エンコーダ部を実装する
seq_length = x_train.shape[1]    # 時系列の長さ(時間方向の要素数)
input_dim = x_train.shape[2]     # 入力の各要素の次元数
encoded_dim = 16    # 何次元ベクトルに圧縮するか
lstm_dim = 1024     # RNN(LSTM)層の隠れノード数

# 空のモデルを作る
encoder = tf.keras.Sequential()
# RMM(LSTM)層を作ってモデルに追加する
encoder.add(tf.keras.layers.LSTM(
    lstm_dim, input_shape=(seq_length, input_dim),
    use_bias=True, activation="tanh", return_sequences=False))
# 出力層(ノード数はencoded_dim)を作ってモデルに追加する
encoder.add(tf.keras.layers.Dense(
    encoded_dim, use_bias=True, activation="linear"))
encoder.summary()

# デコーダ部を実装する
decoder = tf.keras.Sequential()
# 後段のRNN(LSTM)に入力できるように、
# 入力層のベクトルを繰り返して時系列化する
decoder.add(tf.keras.layers.RepeatVector(
    seq_length, input_dim=encoded_dim))
# RNN(LSTM)層を作ってモデルに追加する
decoder.add(tf.keras.layers.LSTM(
    lstm_dim, use_bias=True, activation="tanh",
    return_sequences=True))
# 出力層を作ってモデルに追加する
# (ノード数はエンコーダ部の入力層に合わせる)
decoder.add(tf.keras.layers.Dense(
    input_dim, use_bias=True, activation="softmax"))
decoder.summary()

encoder.save("model_encoder")
decoder.save("model_decoder")
# 二回目以降モデル作成省略用
#encoder = tf.keras.models.load_model("model_encoder")
#decoder = tf.keras.models.load_model("model_decoder")

# エンコーダ部とデコーダ部をドッキングさせる
# 入力:エンコーダ部の入力
# 出力:エンコーダ部の出力をデコーダ部に入力して得られる出力
model = tf.keras.Model(encoder.inputs,
                       decoder(encoder.outputs))
# モデルの最後の設定を行う
model.compile(optimizer="adam",
              loss="categorical_crossentropy",
              metrics="categorical_accuracy")
model.summary()

# モデルを学習する
# x_trainの各要素を入力したら同じものが出力されるようにモデルを学習する
model.fit(x_train, x_train, batch_size=32, epochs=1000) # 1000 original

model.save_weights('my_checkpoint01')
# 二回目以降学習省略用
#model.load_weights('my_checkpoint01')

#  精度を評価する
model.evaluate(x_train, x_train)
model.evaluate(x_test, x_test)

# 学習データに対して圧縮・復元を行う
# x_trainの各要素をエンコーダ部に入力する(16次元ベクトルが得られる)
z = encoder.predict(x_train)
# zの各要素をデコーダ部に入力してメロディを再構築する
x_new = decoder.predict(z)

# 最初のメロディに対して復元結果を確認する
k = 0
print(z[k])
# 入力メロディを聴けるようにする
show_and_play_midi([x_train[k, :, 0:-1]], "input.mid")
# 再構築されたメロディを聴けるようにする
show_and_play_midi([x_new[k, :, 0:-1]], "output.mid")

# テストデータに対して圧縮・復元を行う
# x_testの各要素をエンコーダ部に入力する(16次元ベクトルが得られる)
z = encoder.predict(x_test)
# zの各要素をデコーダ部に入力してメロディを再構築する
x_new = decoder.predict(z)

# 最初のメロディに対して復元結果を確認する
k = 0
print(z[k])
# 入力メロディを聴けるようにする
show_and_play_midi([x_test[k, :, 0:-1]], "input2.mid")
# 再構築されたメロディを聴けるようにする
show_and_play_midi([x_new[k, :, 0:-1]], "output2.mid")

exit()

# 上記 encoded_dim = 3 に変更して実行後、下記実行

# x_trainの各要素を3次元ベクトルに変換する
z = encoder.predict(x_train)

# 得られた3次元ベクトルを長調・短調で色分けして図示する
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 学習データのそれぞれに対して長調か短調かの情報を得る
key_train = np.array(keymodes)[i_train]
# zから長調の楽曲の分だけを抜き出す
z_maj = z[key_train[:, 0] == 0, :]
# zから短調の楽曲の分だけを抜き出す
z_min = z[key_train[:, 0] == 1, :]
# z_majの各要素を赤点で描画する
ax.scatter(z_maj[:, 0], z_maj[:, 1], z_maj[:, 2], c='red')
# z_minの各要素を青点で描画する
ax.scatter(z_min[:, 0], z_min[:, 1], z_min[:, 2], c='blue')
plt.show()

学習データとテストデータの評価結果

I tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:432] Loaded cuDNN version 8907
8/8 [==============================] – 2s 105ms/step – loss: 0.0669 – categorical_accuracy: 0.9905
8/8 [==============================] – 1s 105ms/step – loss: 3.8814 – categorical_accuracy: 0.4664

学習データの圧縮、復元結果

テストデータの圧縮、復元結果

学習データの評価は、そのデータを使って学習していることから復元結果が良く、テストデータはそうでないため結果が良くありません。

長調、短調の色分け

この書籍はオートエンコーダだけでなく、主だったディープラーニングの手法が、具体的なデータを使って解説されてあり、とてもわかりやすいです。音楽としての成果はなかなか難しいところはありますが、音楽データを扱うライブラリがとても充実していてすばらしいです。

関連)
https://decode.red/ed/archives/1600

ライブラリ
input_midi.py

import pretty_midi
import numpy as np

class UnsupportedMidiFileException(Exception):
  "Unsupported MIDI File"

# 与えられたMIDIデータをハ長調またはハ短調に移調
# key_number: 調を表す整数(0--11: 長調、12--23: 短調)
def transpose_to_c(midi, key_number):
  for instr in midi.instruments:
    if not instr.is_drum:
      for note in instr.notes:
        note.pitch -= key_number % 12

# 与えられたMIDIデータからピアノロール2値行列を取得
# nn_from: 音高の下限値(この値を含む)
# nn_thru: 音高の上限値(この値を含まない)
# seqlen: 読み込む長さ(時間軸方向の要素数、八分音符単位)
# tempo: テンポ
def get_pianoroll(midi, nn_from, nn_thru, seqlen, tempo):
  pianoroll = midi.get_piano_roll(fs=2*tempo/60)
  if pianoroll.shape[1] < seqlen:
    raise UnsupportedMidiFileException
  pianoroll = pianoroll[nn_from:nn_thru, 0:seqlen]
  pianoroll = np.heaviside(pianoroll, 0)
  return np.transpose(pianoroll)

# 指定されたMIDIファイルを読み込んでピアノロール2値行列を返却
# filename: 読み込むファイル名
# sop_alto: ソプラノパートとアルトパートを別々に読み込む場合にTrue
# seqlen: 読み込む長さ(時間軸方向の要素数、八分音符単位)
def read_midi(filename, sop_alto, seqlen):
  midi = pretty_midi.PrettyMIDI(filename)
  # 途中で転調がある場合は対象外として例外を投げる
  if len(midi.key_signature_changes) != 1:
    raise UnsupportedMidiFileException
  # ハ長調またはハ短調に移調する
  key_number = midi.key_signature_changes[0].key_number
  transpose_to_c(midi, key_number)
  # 長調(keymode=0)か短調(keynode=1)かを取得する
  keymode = np.array([int(key_number / 12)])
  # 途中でテンポが変わる場合は対象外として例外を投げる
  tempo_time, tempo = midi.get_tempo_changes()
  if len(tempo) != 1:
    raise UnsupportedMidiFileException
  if sop_alto:
    # パート数が2未満の場合は対象外として例外を投げる
    if len(midi.instruments) < 2:
      raise UnsupportedMidiFileException
    # ソプラノ(1パート目)とアルト(2パート目)のそれぞれに対して
    # ピアノロール2値行列を取得する
    pr_s = get_pianoroll(midi.instruments[0], 36, 84,
                         seqlen, tempo[0])
    pr_a = get_pianoroll(midi.instruments[1], 36, 84,
                         seqlen, tempo[0])
    return pr_s, pr_a, keymode
  else:
    # 全パートを1つにしたピアノロールを取得する
    pr = get_pianoroll(midi, 36, 84, seqlen, tempo[0])
    return pr, keymode

add_rest.py

import numpy as np
# ピアノロール2値行列に休符要素を追加する
def add_rest_nodes(pianoroll):
  # ピアノロール2値行列の時刻ごとの各音高ベクトルに対して、
  # 全要素が0のときに1、そうでないときに0を格納したデータ
  # (休符要素系列と呼ぶ)を作る
  rests = 1 - np.sum(pianoroll, axis=1)
  # 休符要素系列に2次元配列化して行列として扱えるようにする
  rests = np.expand_dims(rests, 1)
  # ピアノロール2値行列と休符要素系列をくっつけた行列を作って返す
  return np.concatenate([pianoroll, rests], axis=1)

play_midi.py

from out_midi import *

import matplotlib.pyplot as plt
#import IPython.display as ipd
import pretty_midi
from midi2audio import FluidSynth
import numpy as np

# 与えられたピアノロール2値行列からMIDIデータを作るのに加え、
# ピアノロール2値行列を描画したり、再生できるようにする
def show_and_play_midi(pianorolls, filename):
  # ピアノロール2値行列を描画する
  for pr in pianorolls:
    plt.matshow(np.transpose(pr))
    plt.show()
  # MIDIデータを生成してファイルに保存する
  make_midi(pianorolls, filename)
  # MIDIデータをwavに変換してブラウザ上で聴けるようにする
  #fs = FluidSynth(sound_font="/usr/share/sounds/sf2/FluidR3_GM.sf2")
  #fs.midi_to_audio(filename, "output.wav")
  #ipd.display(ipd.Audio("output.wav"))

]]>
Geographic Information System ../../../202403101754/ Sun, 10 Mar 2024 07:39:56 +0000 ../../../?p=1754 GIS(地理情報システム) : 位置に関する様々な情報を持ったデータを加工/管理したり、地図の作成や高度な分析などを行うシステム技術の総称 (下記URLより)

今回GISに入門してみました。

https://www.mlit.go.jp/kokudoseisaku/gis/guidance/guidance_1.html

GISを扱うために下記、オープンソフトウェアを利用しました。
https://www.qgis.org/ja/site/about/index.html

きっかけは、頻発する自然災害に備える意味でも、住んでいる場所の標高などのデータを知りたかったことからです。
いろいろ調べていくと、予想以上にさまざまなデータがあることに驚きました。気象情報・地震情報など収集して何かできないだろうか、という思いもありまずは使い始めました。

下記は道路地図・標高図の二つの地図を重ねて、Pythonプログラムでそれをレンダリングして出力するものです。

出力したものですが、QGISで見るものと同じ解像度で出力するには、時間がかかりそうです。

from qgis.core import QgsMapSettings, QgsProject
from PyQt5.QtGui import QImage, QColor
from PyQt5.QtCore import QSize

image_location = "/Users/kkk/render02c.png"

layers_to_save = [layer for layer in QgsProject.instance().mapLayers().values()]

settings = QgsMapSettings()
settings.setLayers(layers_to_save)
settings.setBackgroundColor(QColor(255, 255, 255))
settings.setOutputSize(QSize(12000, 12000)) 

extent = layers_to_save[0].extent()
print(layers_to_save[0])
for layer in layers_to_save[1:]: 
    print(layer)
    extent.combineExtentWith(layer.extent())

settings.setExtent(extent)
render = QgsMapRendererParallelJob(settings)

def finished():
    img = render.renderedImage()
    img.save(image_location, "png")

render.finished.connect(finished)
render.start()

print('--end--')

まずは第一歩でした。

参考) 
https://gis-oer.github.io/gitbook/book/materials/python/
https://nlftp.mlit.go.jp/ksj/

]]>
Call Java from Python ../../../202312021728/ Sat, 02 Dec 2023 00:38:37 +0000 ../../../?p=1728 今回はPythonからJavaを呼び出してみます。過去の資産を有効利用するという意味でJavaを呼び出せるメリットは大きいです。
グルーコードのテクニックを知っていると改修すべきプログラムをそのまま利用できることがあります。
以前.NETとJavaの同時呼び出しを記事にしたことがありますが、Javaの資産をJNI->C->C++/CLI->.NETを経由して.NETから利用したことがあり、そのとき一部をメモしたものです。

http://crossframe.iiv.jp/2013021475/

下記、pyjniusというモジュールを使ってJavaクラスを利用してみました。

https://pypi.org/project/pyjnius/
こちらにあるサンプルコードに追加してユーザクラスも試してみました。

環境)Python 3.8, Java 11 / WSL2 / Windows 11

インストール

$ pip3 install pyjnius
Collecting pyjnius
Downloading pyjnius-1.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB)
|████████████████████████████████| 1.6 MB 2.8 MB/s
Installing collected packages: pyjnius
Successfully installed pyjnius-1.6.1

Users.java

class Users{
        private int id;
        private String name;
        public Users(int id, String name){
                this.id = id;
                this.name = name;
        }
        public int getId(){
                return id;
        }
        public String getName(){
                return name;
        }
}

次にJavaVMでうごかすPython、Jythonについても取り上げてみたいと思います。JythonはPython ver3をサポートしていないようですので、あまり使う機会がないかもしれませんが、過去によくみかけた実装で今の環境でも動くのか興味があったので試してみました。

参考) https://qiita.com/ht12345/items/d1de737e3549fca64c1b

まず下記サンプルコードを確認しました。
https://www.jython.org/

import org.python.util.PythonInterpreter;

public class JythonHelloWorld {
  public static void main(String[] args) {
    try(PythonInterpreter pyInterp = new PythonInterpreter()) {
      pyInterp.exec("print('Hello Python World!')");
    }
  }
}

インストール

$ wget https://repo1.maven.org/maven2/org/python/jython-installer/2.7.3/jython-installer-2.7.3.jar
$ java -jar jython-installer-2.7.3.jar –console
Welcome to Jython !
You are about to install Jython version 2.7.3
(at any time, answer c to cancel the installation)
For the installation process, the following languages are available: English, German
Please select your language [E/g] >>>
Do you want to read the license agreement now ? [y/N] >>>
Do you accept the license agreement ? [Y/n] >>>
The following installation types are available:
1. All (everything, including sources)
2. Standard (core, library modules, demos and examples, documentation)
3. Minimum (core)
9. Standalone (a single, executable .jar)
Please select the installation type [ 1 /2/3/9] >>> 9
Please enter the target directory >>> .
Directory /home/k/python/java is not empty – ok to overwrite contents ? [y/N] >>>
Please enter the target directory >>> target
Unable to find directory /home/k/python/java/target, create it ? [Y/n] >>>
Your java version to start Jython is: Ubuntu / 11.0.18
Your operating system version is: Linux / 5.10.16.3-microsoft-standard-WSL2
Summary:
– standalone
Please confirm copying of files to directory /home/k/python/java/target [Y/n] >>>

targetディレクトリに生成されはjarファイルをカレントに持ってきて使用します。
Pythonコードは以下のようにして実行できました。(任意)

$ java -jar jython.jar test.py

JythonHelloWorld.java をコンパイルします。

$ javac JythonHelloWorld.java -cp jython.jar

実行

$ java -classpath .:jython.jar JythonHelloWorld
Hello Python World!

本題のPythonコードの実行で変数がJavaとやりとりされている下記にあるサンプルコードを動かしてみます。
参考) https://qiita.com/ht12345/items/d1de737e3549fca64c1b
ScriptDemo.java

import javax.script.*;
import org.python.core.PyInteger;

public class ScriptDemo{
        public static void main(String[] args) throws ScriptException {
                String script = "from decimal import Decimal\n" +
                                "y = num + Decimal(10)";
                ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("python");
                SimpleBindings bindings = new SimpleBindings();

                PyInteger num = new PyInteger(5);
                bindings.put("num", num);

                scriptEngine.eval(script, bindings);

                Object y = bindings.get("y");
                System.out.println(y);
                System.out.println(y.getClass());
        }
}

コンパイルと実行

$ javac ScriptDemo.java -cp jython.jar
$ java -cp .:jython.jar ScriptDemo
15
class java.math.BigDecimal

無事、私の環境で動作することを確認できました。
コードサンプルでは、環境違いで動かないことや、よくimport文がなかったりビルド方法が明示されていないケースがあったりしますので、実際に動かしてみることで、理解が深まり安心できます。

]]>
InfluxDB & Grafana ../../../202304221613/ Sat, 22 Apr 2023 02:30:22 +0000 ../../../?p=1613 前回Grafanaを使った可視化ツールを試しましたが、今回Pythonプログラムで作成したデータを前回構築したGrafanaでグラフ表示させてみました。Pythonから直接表示させるのではなく、下記で構築したInfluxDBに書き込んだデータを表示させました。

「Foreign Data Wrapper / PostgreSQL」
https://decode.red/net/archives/1417

参考) https://qiita.com/Yokogawa_Ishino/items/c3467efb83e7fa342734

influxdbモジュールのインストール
環境) Ubuntu 22.04

n@n10:~$ python3 -V
Python 3.10.6
n@n10:~$ sudo apt install python3-pip
n@n10:~$ python3 -m pip install influxdb

from influxdb import InfluxDBClient
from datetime import datetime
import time
import random

db = InfluxDBClient(host='localhost', port=8086, database='sample01')

for i in range(10):
    json_body = [
        {
            "measurement": "sample_measurement",
            "time": datetime.utcnow(),
            "fields": {
                "data01": random.randint(0, 100),
                "data02": random.randint(0, 100)
            }
        }
    ]
    print("Write data: {0}".format(json_body))
    db.write_points(json_body)
    time.sleep(1)

(1秒ごとにランダムなデータを書くプログラム)

n@n10:~$ influx
Connected to http://localhost:8086 version 1.6.7~rc0
InfluxDB shell version: 1.6.7~rc0
> use sample01
Using database sample01
> select * from sample_measurement
name: sample_measurement
time data01 data02
—- —— ——
1682121753264329000 31 85
1682121754336419000 8 80
1682121755826517000 31 50
1682121756839369000 15 43
1682121757854193000 24 63
1682121758873117000 84 59
….

Grafanaの接続設定

テスト接続

データ表示

IoTデバイスのデータ取集、表示に使うと便利そうですが、単純にブログラムの出力結果にこういう使い方するのもいい感じです。

]]>
BPF Compiler Collection ../../../202302031560/ Fri, 03 Feb 2023 13:22:40 +0000 ../../../?p=1560 eBPF(extended Berkekey Packet Filter)という機能を利用したカーネルトレースや操作プログラムを作成するためのツールキット、BCCを試してみました。
OSには、通常のプログラミングが動作するユーザモードと特権をもつプログラムを実行するカーネルモードがあり、BCCを使うとBPFの仕組みを使ってカーネルモードのプログラムをカーネルのコードをビルドすることなく実行できるようです。
Pythonコードの中にC言語のコードを書き、それをコンパイルして実行するようですが、printk関数をはさんでデバッグしていたころに比べてかなり便利な設計になったていると感じました。

参考)
https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu—binary
https://github.com/iovisor/bcc/blob/master/examples/tracing/hello_fields.py
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0690

環境)

$ uname -r
4.15.0-202-generic
$ cat /etc/os-release
NAME=”Ubuntu”
VERSION=”18.04.6 LTS (Bionic Beaver)”
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=”Ubuntu 18.04.6 LTS”
VERSION_ID=”18.04″
HOME_URL=”https://www.ubuntu.com/”
SUPPORT_URL=”https://help.ubuntu.com/”
BUG_REPORT_URL=”https://bugs.launchpad.net/ubuntu/”
PRIVACY_POLICY_URL=”https://www.ubuntu.com/legal/terms-and-policies/privacy-policy”
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
$ grep BPF /boot/config-uname -r
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_TEST_BPF=m
$ python -V
Python 2.7.17

インストール)

$ sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys 4052245BD4284CDD
$ echo “deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/iovisor.list
$ sudo apt-get update
$ sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)

hello.py

from bcc import BPF
from bcc.utils import printb
import pprint

# define BPF program
prog = """
#include <linux/sched.h>

int hello(void *ctx) {
    char comm[TASK_COMM_LEN];
    bpf_get_current_comm(&comm, sizeof(comm));
    bpf_trace_printk("Hello!: %s\\n", comm);
    return 0;
}
"""

# load BPF program
b = BPF(text=prog)
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="hello")

pprint.pprint(dir(b))
pprint.pprint(vars(b))

# header
print("%-18s %-16s %-6s %s" % ("TIME(s)", "COMM", "PID", "MESSAGE"))

# format output
while 1:
    try:
        (task, pid, cpu, flags, ts, msg) = b.trace_fields()
    except ValueError:
        continue
    except KeyboardInterrupt:
        exit()
    printb(b"%-18.9f %-16s %-6d %s /%s %d" % (ts, task, pid, msg, flags, cpu))

プロセスがcloneされたときに呼び出される処理が書かれています。オリジナルから、bオブジェクトの情報表示と、明示的なタスク、追加項目の表示を加えています。
また以下、exampleにあるhello_work.pyには、”イベント名__関数名”でカーネル内部の任意の関数をフックできるしくみで書かれていますが、ここではget_syscall_fnname(“clone”)という形でかかれています。

BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print()

プログラムを起動した後、別コンソールでlsコマンド、curlコマンドを実行してみました。

実行結果

$ sudo python hello.py
[‘CGROUP_DEVICE’,
‘CGROUP_SKB’,
‘CGROUP_SOCK’,
‘CGROUP_SOCK_ADDR’,
‘CLOCK_MONOTONIC’,
‘Function’,
‘KPROBE’,
‘LWT_IN’,
‘LWT_OUT’,
‘LWT_XMIT’,
‘PERF_EVENT’,
‘RAW_TRACEPOINT’,
‘SCHED_ACT’,
‘SCHED_CLS’,
‘SK_MSG’,
‘SK_SKB’,
‘SOCKET_FILTER’,
‘SOCK_OPS’,
‘TRACEPOINT’,
‘Table’,
‘XDP’,
‘XDP_ABORTED’,
‘XDP_DROP’,
‘XDP_PASS’,
‘XDP_REDIRECT’,
‘XDP_TX’,
‘__class__’,
‘__delattr__’,
‘__delitem__’,
‘__dict__’,
‘__doc__’,
‘__enter__’,
‘__exit__’,
‘__format__’,
‘__getattribute__’,
‘__getitem__’,
‘__hash__’,
‘__init__’,
‘__iter__’,
‘__len__’,
‘__module__’,
‘__new__’,
‘__reduce__’,
‘__reduce_ex__’,
‘__repr__’,
‘__setattr__’,
‘__setitem__’,
‘__sizeof__’,
‘__str__’,
‘__subclasshook__’,
‘__weakref__’,
‘_add_kprobe_fd’,
‘_add_uprobe_fd’,
‘_attach_perf_event’,
‘_auto_includes’,
‘_bsymcache’,
‘_check_path_symbol’,
‘_check_probe_quota’,
‘_clock_gettime’,
‘_decode_table_type’,
‘_del_kprobe_fd’,
‘_del_uprobe_fd’,
‘_find_file’,
‘_get_uprobe_evname’,
‘_librt’,
‘_probe_repl’,
‘_sym_cache’,
‘_sym_caches’,
‘_syscall_prefixes’,
‘_trace_autoload’,
‘add_module’,
‘attach_kprobe’,
‘attach_kretprobe’,
‘attach_perf_event’,
‘attach_raw_socket’,
‘attach_raw_tracepoint’,
‘attach_tracepoint’,
‘attach_uprobe’,
‘attach_uretprobe’,
‘attach_xdp’,
‘cleanup’,
‘debug’,
‘decode_table’,
‘detach_kprobe’,
‘detach_kprobe_event’,
‘detach_kretprobe’,
‘detach_perf_event’,
‘detach_raw_tracepoint’,
‘detach_tracepoint’,
‘detach_uprobe’,
‘detach_uprobe_event’,
‘detach_uretprobe’,
‘disassemble_func’,
‘donothing’,
‘dump_func’,
‘find_exe’,
‘find_library’,
‘fix_syscall_fnname’,
‘free_bcc_memory’,
‘funcs’,
‘generate_auto_includes’,
‘get_kprobe_functions’,
‘get_syscall_fnname’,
‘get_syscall_prefix’,
‘get_table’,
‘get_tracepoints’,
‘get_user_addresses’,
‘get_user_functions’,
‘get_user_functions_and_addresses’,
‘kprobe_fds’,
‘kprobe_poll’,
‘ksym’,
‘ksymname’,
‘load_func’,
‘load_funcs’,
‘module’,
‘monotonic_time’,
‘num_open_kprobes’,
‘num_open_tracepoints’,
‘num_open_uprobes’,
‘open_perf_events’,
‘perf_buffer_poll’,
‘perf_buffers’,
‘raw_tracepoint_fds’,
‘remove_xdp’,
‘str2ctype’,
‘support_raw_tracepoint’,
‘sym’,
‘tables’,
‘timespec’,
‘trace_fields’,
‘trace_open’,
‘trace_print’,
‘trace_readline’,
‘tracefile’,
‘tracepoint_exists’,
‘tracepoint_fds’,
‘uprobe_fds’]
{‘debug’: 0,
‘funcs’: {‘hello’: },
‘kprobe_fds’: {‘p_sys_clone’: 4},
‘module’: 94590567723712,
‘open_perf_events’: {},
‘perf_buffers’: {},
‘raw_tracepoint_fds’: {},
‘tables’: {},
‘tracefile’: None,
‘tracepoint_fds’: {},
‘uprobe_fds’: {}}
TIME(s) COMM PID MESSAGE
3859.149581000 bash 1827 Hello!: bash /…. 0
3861.768011000 bash 1827 Hello!: bash /…. 0
3861.773422000 curl 3930 Hello!: curl /…. 1
3865.956510000 bash 1827 Hello!: bash /…. 0
3865.962982000 curl 3932 Hello!: curl /…. 1

eBPFは、クラウドサービスでよく使われるコンテナ中通信(CNI:Container Network Interface)を実現するCiliumで使われているようです。
「CNIのCiliumについて調べてみた」
https://blog.framinal.life/entry/2021/02/20/222728
このあたり、また掘り下げて調べたいと思っています。

]]>
Qiskit ../../../202301151549/ Sun, 15 Jan 2023 01:05:02 +0000 ../../../?p=1549 前回の量子のもつれ状態について、QiskitというPythonライブラリを使ってテストしてみまた。
JupyterNotebookを使いますが、可視化ツールがよくできていてモチベーションがあがります。

前回と同じ、アダマールゲートとCNOTを使った回路を作ってみましたが、その前に可視化ツールのテストをしたかったので、回路図とブロッホ球の表示をしてみました。(In/Out[4]まで)
In/Out[5]からは、量子ピットを2にして目的のテストをしています。

参考)
https://qiskit.org/textbook/ja/ch-gates/multiple-qubits-entangled-states.html

環境) Jupyter Notebook 6.0.3 / Python 3.7.6 / Anaconda 1.9.12 / Wndows 10

インストール)
pip install qiskit

00と11しか出現しないことを確認しました。手順は上記URLの参考サイト「複数量子ビットともつれ状態」に詳しく書かれています。また上記動画ではツールのインストール、使用方法などを参考にしました。この動画のシリーズは長時間かけてとてもわかりやすく説明されていますのでおすすめです。
もつれ状態では、ブロッホ球がうまく表示できないことから、最後にQ-sphereを使って可視化しています。
使用したコードを下記をのせました。部分コピペで実行します。

from qiskit import QuantumCircuit, QuantumRegister, Aer,assemble
from qiskit.visualization import plot_bloch_multivector, plot_histogram
from qiskit.visualization import array_to_latex
from qiskit.providers.aer.library import save_statevector
from mpl_toolkits.mplot3d import axes3d, Axes3D 
from qiskit.visualization import plot_state_qsphere

qc = QuantumCircuit()
qr = QuantumRegister(1)
qc.add_register(qr)
qc.x(qr[0])
qc.draw()

sim=Aer.get_backend('statevector_simulator')
res = sim.run(qc).result()
state = res.data()["statevector"]
array_to_latex(state, prefix="\\text{Statevector = }")

print(state)
plot_bloch_multivector(state)


qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0,1)
qc.draw()


svsim = Aer.get_backend('aer_simulator')
qc.save_statevector()
qobj = assemble(qc)
result = svsim.run(qobj).result()
final_state = result.get_statevector()
array_to_latex(final_state, prefix="\\text{Statevector = }")


plot_histogram(result.get_counts())

print(final_state)
plot_bloch_multivector(final_state)

plot_state_qsphere(final_state)

以上、今回は主にツールの使い方を学びました。
これをベースにまた理解を深めたいと思います。

]]>
Hierarchical Deterministic Wallets ../../../202209101492/ Sat, 10 Sep 2022 00:37:48 +0000 ../../../?p=1492 暗号資産の取引をする際に必要な財布を作成するとき、ニーモニックコードというものを使います。
12文字からなる単語の並びで、これをもとにウォレットを表すアドレスを生成します。
下記BitlifeCoinの記事を書いているとき、ウォレットのアドレスが同じニーモニックコードから生成しているにもかかわらずアドレスが一致しなかったことから、Hierarchical Deterministic Pathというものがあることを知りました。
(一つのキーから階層的にアドレスを決定するしくみ)
http://bitlife.me/bc/2022/08/18/

m/44’/60’/0’/0/{account_index}
このような文字列で表せれ、最後のaccount_indexによって複数のアドレスを生成できます。

こちらのサイトにとても詳しく書かれています。
https://techblog.recochoku.jp/8227

このサイトにあるコードで実際にBitlifeCoinの環境のニーモニックから生成されるアドレスが正しいか試してみました。(ニーモニックはカレントディレクトにある.secretファイルに記載)

環境) WSL / Windows 11
インストール

pip install hdwallet

from hdwallet import HDWallet
from hdwallet.symbols import ETH
from pprint import pprint

mnemonic = ''
hd_wallet_account = HDWallet(symbol=ETH).from_mnemonic(mnemonic=mnemonic).from_path(path="m/44'/60'/0'/0/1")

hd_wallet_account_info = hd_wallet_account.dumps()
pprint(hd_wallet_account_info)

PATHは、コードではaccount_indexは1となっています。これを0から順に変えてgoerliの環境の複数のアドレスが正しいか確認したところ一致しました。

あとニーモニックを作成するわかりやすいコードが下記にありましたので、それを動かしてみました。
https://qiita.com/yamaguchi3/items/2c216eee5593ee0f66db

const fs = require('fs');
const crypto = require('crypto');
const words = fs.readFileSync('english.txt').toString().trim().split('\n');
const ent = Buffer.from('7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', 'hex');
const checksum = crypto.createHash('sha256').update(ent).digest().slice(0, ent.length/4);
const data = Buffer.concat([ent, checksum]);
let bin = '';
for(let d of data) {
    bin += ('00000000' + d.toString(2)).slice(-8);
}

let mnemonic = [];
for(var i=0; i<3*ent.length/4; i++) {
    var idx = parseInt(bin.slice(11*i, 11*(i+1)), 2);
    mnemonic.push(words[idx]);
}
console.log(mnemonic.join(' '));

https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt
ここから取得するenglish.txtには、2048の英単語が書かれており、この中からニーモニックにつかわれる単語が選ばれるようです。
最初にウォレットを作ったとき、たった12文字の並び替えだけで衝突しないアドレスが生成できるのか、と思いましたが2048の候補から選んだうえ並び変えているのですね。
ブロックチェーン界隈では、このようないろいろなしくみが考えられていてとても興味深いです。

]]>
Streamlit ../../../202208131482/ Fri, 12 Aug 2022 23:56:59 +0000 ../../../?p=1482 Pythonプログラムを実行するとブラウザを自動的に立ち上げWEB表示してくれるとても便利なフレームワークを試してみました。

参考) https://qiita.com/keisuke-ota/items/a18f158389f1585a9aa0

環境) Python3 / WSL / Windows 11
インストール)

pip3 install streamlit
pip3 install –upgrade jinja2
pip3 install plotly
pip3 install altair vega_datasets
pip3 install scikit-learn

参考にさせていただいたサイトは、例も多くわかりやすい説明がされており、応用例も含めて実行するため上記、多めのライブラリをインストールしています。
streamlitインストール時のエラー解消には下記を参考にしました。
https://github.com/jupyterhub/jupyterhub/issues/408

スライダーの動きで値を変化させたものがリアクティブに更新されるかを試したかったので、コードを組み合わせて実行しました。

import streamlit as st
import plotly.graph_objs as go

values = st.slider('Rage values', 0.0, 100.0, (25.0, 75.0))
st.write('Values:', values)

items = ['range start', 'range end', 'max']
value3 = [values[0], values[1], 100]

fig = go.Figure(data=[go.Bar(x=items, y=value3)])

fig.update_layout(
    xaxis = dict(tickangle = 0, title_text = "Items", title_font = {"size": 20}, title_standoff = 25),
    yaxis = dict(title_text = "Values", title_standoff = 25),
    title ='Reactive Test'
)

st.plotly_chart(fig, use_container_width=True)

スライダーの値を変えると、リアクティブに棒グラフが更新されます。(素晴らしい!)

こういうツールを知っておくと、いざというときにいろいろと役に立つことがあります。
I/FをWebにまかせられるので、ロジックに集中できてとても便利です。

]]>
Proof of Work ../../../202201041398/ Tue, 04 Jan 2022 10:03:25 +0000 ../../../?p=1398 ブロックチェーンにはネットワークを安定に維持するしくみが多くあり、技術的にとても興味深い題材ばかりです。

過去に書いた、ビットコイン論文ついての記事

Block Chain

その中でマイニングと呼ばれるしくみはとても秀逸にできています。

参考書籍) 「ビットコインとブロックチェーン(Mastering Bitcoin)」(NTT出版)

ここではProof-of-Workとよばれるハッシュ計算を実際に動かしてみました。
マイナーが多数いようと少数だろうと約10分で新しいブロックが作り出せるように、計算にかかる難易度をコントロールしています。
Difficulty Targetと呼ばれる値よりも小さいハッシュ値がでるようにnonceを変えながらトライし、見つけたら正解という単純なものですが、このTarget値が1bit変わるだけで、劇的に計算量が変化します。
これをPythonで実装されたサンプルを出力を見やすくして実行してみました。

オリジナル) https://github.com/bitcoinbook/bitcoinbook/blob/develop/code/proof-of-work-example.py

#!/usr/bin/env python
# example of proof-of-work algorithm

import hashlib
import time

try:
    long        # Python 2
    xrange
except NameError:
    long = int  # Python 3
    xrange = range

max_nonce = 2 ** 32  # 4 billion

def proof_of_work(header, difficulty_bits):
    target = 2 ** (256 - difficulty_bits)

    for nonce in xrange(max_nonce):
        hash_result = hashlib.sha256((str(header) + str(nonce)).encode()).hexdigest()

        # check if this is a valid result, equal to or below the target
        if long(hash_result, 16) <= target:
            print("Nonce:  %d" % nonce)
            print("Hash:   %s" % hash_result)
            print("Target: {:064X}".format(target))
            return (hash_result, nonce)

    print("Failed after %d (max_nonce) tries" % nonce)
    return nonce


if __name__ == '__main__':
    nonce = 0
    hash_result = ''

    # difficulty from 0 to 31 bits
    for difficulty_bits in xrange(32):
        print("Difficulty: %d bits" % difficulty_bits)

        # checkpoint the current time
        start_time = time.time()

        # make a new block which includes the hash from the previous block
        # we fake a block of transactions - just a string
        new_block = 'test block with transactions' + hash_result

        # find a valid nonce for the new block
        (hash_result, nonce) = proof_of_work(new_block, difficulty_bits)

        # checkpoint how long it took to find a result
        end_time = time.time()

        elapsed_time = end_time - start_time
        print("Elapsed Time:  %.4f seconds" % elapsed_time)

        if elapsed_time > 0:
            # estimate the hashes per second
            hash_power = float(long(nonce) / elapsed_time)
            print("Hashing Power: %ld hashes per second" % hash_power)

        print("")

% python proof-of-work-example.py
Difficulty: 0 bits
Nonce:  0
Hash:   ff8253ed10b5f719d52a709a66af8cd5e2054f702e675af4ca0cae70f0988634
Target: 10000000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0005 seconds
Hashing Power: 0 hashes per second

Difficulty: 1 bits
Nonce:  0
Hash:   22c608547e239faf5c353e7ebd204042760b93891d1d0be9ab488d36c73c077b
Target: 8000000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0000 seconds
Hashing Power: 0 hashes per second

Difficulty: 2 bits
Nonce:  2
Hash:   0635f41cdb98c6e73516f84fc88da19a13a3bac6298dbfc0df5170bac93ba4dd
Target: 4000000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0000 seconds
Hashing Power: 95325 hashes per second

Difficulty: 3 bits
Nonce:  9
Hash:   1c1c105e65b47142f028a8f93ddf3dabb9260491bc64474738133ce5256cb3c1
Target: 2000000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0000 seconds
Hashing Power: 224694 hashes per second

Difficulty: 4 bits
Nonce:  25
Hash:   0f7becfd3bcd1a82e06663c97176add89e7cae0268de46f94e7e11bc3863e148
Target: 1000000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0001 seconds
Hashing Power: 284166 hashes per second

Difficulty: 5 bits
Nonce:  36
Hash:   029ae6e5004302a120630adcbb808452346ab1cf0b94c5189ba8bac1d47e7903
Target: 0800000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0001 seconds
Hashing Power: 294912 hashes per second

Difficulty: 6 bits
Nonce:  0
Hash:   0083214fa878cea749bd07bd77e92b311be876dd72f3d4924d5ae4ead54febe5
Target: 0400000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0000 seconds
Hashing Power: 0 hashes per second

Difficulty: 7 bits
Nonce:  26
Hash:   00f7abab177613afc42270e3f5f79ffddd694093030663b32fe26ce2a377a993
Target: 0200000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0001 seconds
Hashing Power: 286225 hashes per second

Difficulty: 8 bits
Nonce:  33
Hash:   0055c56d412e6ab765048f1b8e7fce3b2553435c765c2899ee1bd3124d056098
Target: 0100000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0001 seconds
Hashing Power: 234199 hashes per second

Difficulty: 9 bits
Nonce:  2
Hash:   0025a3e3e764ad05f7945eb65d2a21445eded2209a2cd0e26fa8571bd886b0da
Target: 0080000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0000 seconds
Hashing Power: 104857 hashes per second

Difficulty: 10 bits
Nonce:  1514
Hash:   002a67dc2d861c93843e6dfdb0402f4fed2e87c8c30408f016ac83521e8f091b
Target: 0040000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0046 seconds
Hashing Power: 330566 hashes per second

Difficulty: 11 bits
Nonce:  856
Hash:   0014739d631bf69324d51dfa4ebcd28b03d09e6285d76fc9dc8b7c1e8ad1bf47
Target: 0020000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0026 seconds
Hashing Power: 329236 hashes per second

Difficulty: 12 bits
Nonce:  2933
Hash:   00034d0888fb1cc74a4ee823eae4b71d8949e453da89f24caf3088b557f241c2
Target: 0010000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0091 seconds
Hashing Power: 321988 hashes per second

Difficulty: 13 bits
Nonce:  2142
Hash:   00014006170118b30d97b81e4a824357d416866b469dfc56d16db31e5486f5a0
Target: 0008000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0066 seconds
Hashing Power: 325090 hashes per second

Difficulty: 14 bits
Nonce:  8955
Hash:   0003295d9c3908df0275e074cd820af49a3e5975c487014a23fd7ba5fb98635b
Target: 0004000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0313 seconds
Hashing Power: 286101 hashes per second

Difficulty: 15 bits
Nonce:  32930
Hash:   00009a09fa6f72af0861650e655cf8901b33cf37614ddc0fcfa230294ee22988
Target: 0002000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.1012 seconds
Hashing Power: 325253 hashes per second

Difficulty: 16 bits
Nonce:  285299
Hash:   00009d85ce6e17b625bc50caafc7a42eab41d108a177cbfce39c4045bee69fd8
Target: 0001000000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.8588 seconds
Hashing Power: 332214 hashes per second

Difficulty: 17 bits
Nonce:  10460
Hash:   000012726c26b999bb05e81322379a9ed9ecf08bd85347c752a913ec5e6942e6
Target: 0000800000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0309 seconds
Hashing Power: 338817 hashes per second

Difficulty: 18 bits
Nonce:  11980
Hash:   000020b111acbfe28ac4e68aa267154b12cb224bbf49f2c56db346f039b21395
Target: 0000400000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.0389 seconds
Hashing Power: 307621 hashes per second

Difficulty: 19 bits
Nonce:  573192
Hash:   00001cce66856179a3feed94420d126a9dbddfa8830fc41b7fc5d36fdbf03ba0
Target: 0000200000000000000000000000000000000000000000000000000000000000
Elapsed Time:  1.7196 seconds
Hashing Power: 333336 hashes per second

Difficulty: 20 bits
Nonce:  237723
Hash:   000005720acd8c7207cbf495e85733f196feb1e3692405bea0ee864104039350
Target: 0000100000000000000000000000000000000000000000000000000000000000
Elapsed Time:  0.7161 seconds
Hashing Power: 331977 hashes per second

Difficulty: 21 bits
Nonce:  687438
Hash:   000003a6eeee97491a9183e4c57458172edb6f9466377bf44afbd74e410f6eef
Target: 0000080000000000000000000000000000000000000000000000000000000000
Elapsed Time:  2.0783 seconds
Hashing Power: 330763 hashes per second

Difficulty: 22 bits
Nonce:  1759164
Hash:   0000008bb8f0e731f0496b8e530da984e85fb3cd2bd81882fe8ba3610b6cefc3
Target: 0000040000000000000000000000000000000000000000000000000000000000
Elapsed Time:  5.2847 seconds
Hashing Power: 332877 hashes per second

Difficulty: 23 bits
Nonce:  14214729
Hash:   000001408cf12dbd20fcba6372a223e098d58786c6ff93488a9f74f5df4df0a3
Target: 0000020000000000000000000000000000000000000000000000000000000000
Elapsed Time:  42.8228 seconds
Hashing Power: 331942 hashes per second

Difficulty: 24 bits
Nonce:  24586379
Hash:   0000002c3d6b370fccd699708d1b7cb4a94388595171366b944d68b2acce8b95
Target: 0000010000000000000000000000000000000000000000000000000000000000
Elapsed Time:  73.9447 seconds
Hashing Power: 332496 hashes per second

Difficulty: 25 bits
Nonce:  8570323
Hash:   00000009ecccb8289d6f94b3e861804e41c4530b0f879534597ff4d09aaa446d
Target: 0000008000000000000000000000000000000000000000000000000000000000
Elapsed Time:  25.7419 seconds
Hashing Power: 332932 hashes per second

Difficulty: 26 bits
Nonce:  84561291
Hash:   0000001f0ea21e676b6dde5ad429b9d131a9f2b000802ab2f169cbca22b1e21a
Target: 0000004000000000000000000000000000000000000000000000000000000000
Elapsed Time:  254.2355 seconds
Hashing Power: 332610 hashes per second

Difficulty: 27 bits
Nonce:  10256713
Hash:   00000006dc70d218bafb37c31f3166e49b1b0d28f3fea500431ecb22e954c99e
Target: 0000002000000000000000000000000000000000000000000000000000000000
Elapsed Time:  30.8556 seconds
Hashing Power: 332409 hashes per second

Difficulty: 28 bits
Nonce:  139905000
Hash:   0000000e4da88b53f70b2c5fc142500f0633e6407a4793462c54e6e704a687f3
Target: 0000001000000000000000000000000000000000000000000000000000000000
Elapsed Time:  420.3545 seconds
Hashing Power: 332826 hashes per second

Difficulty: 29 bits
Nonce:  61508685
Hash:   0000000135c4a4e6c78c12e956ea970e5c6b2f586bedcde2cf8507e2b08b87eb
Target: 0000000800000000000000000000000000000000000000000000000000000000
Elapsed Time:  184.9352 seconds
Hashing Power: 332595 hashes per second

Difficulty: 30 bits
Nonce:  590689799
Hash:   0000000339323dfd8e68d9460ba4311efa5da8393aa986ff2c00e7f4a54e9761
Target: 0000000400000000000000000000000000000000000000000000000000000000
Elapsed Time:  1950.6458 seconds
Hashing Power: 302817 hashes per second

Targetの数が小さくなると急激にハッシュを見つけ出す時間がかかるようになります。
下記は過去からの実際のBitcoinのハッシュレートと難易度の変化を表したグラフです。
170m TH/sということは、THのmはメガ? 170 EH/s ってすごい計算量ということがわかります。
(上記は、古いPCで約30万/s)

TH/s(テラハッシュ) 1秒間に1,000,000,000,000(1兆)回
PH/s(ペタハッシュ) 1秒間に1,000,000,000,000,000(1000兆)回
EH/s(エクサハッシュ) 1秒間に1,000,000,000,000,000,000(100京)回

https://www.blockchain.com/charts/hash-rate より

https://www.blockchain.com/charts/difficulty より

ハッシュレートと難易度が同じ動きをしていることがわかります。このように動的に計算負荷をコントールしているのですね。
昔は、PCのCPUでマイニングし、次にGPU、そしてFPGAにASICとハードウェアも変遷しているようですが、マイニングがいかにコストがかかるよく表しています。
それにしても何もかもオープンなんだと、あらためて感じました。

ブロックチェーンはBitcoinに限らす社会に影響を大きく与える技術だけに、そのしくみを知りたいという気持ちが強くなってきました。上記参考書籍はとても詳しくわかりやすく書かれており、おすすめです。
今年はブロックチェーンテクノロジーの探求に力を入れていきたいと思います。

専用ブログ開始しました!

http://bitlife.me/bc/

]]>