「技術」カテゴリーアーカイブ

AVXとはなんぞや?という話

エージェントから案件の紹介を頂きまして、

ほぼ即答で「やります」と回答したのですが、

お仕事の内容が映像系ソフトウェアということで、

Direct2DやAVXのスキル必須とのことでした。

AVXとは??

ChatGTPに質問したら、

x86アーキテクチャのCPUには大量のデータを計算する命令セットが搭載されているとのこと。

で、使い方なんですが、

専用命令セットということなので、アセンブラのコードを使用するのかなと思っていたら、

C++にはその命令セットを使用するためのライブラリを使用可能にするヘッダーファイルがあるらしい。

これはChatGTPが教えてくれたサンプルプログラム。

#include <immintrin.h>
#include <iostream>

int main() {
    constexpr int size = 8;
    float a[size] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    float b[size] = { 8, 7, 6, 5, 4, 3, 2, 1 };
    float c[size];

    __m256 a_vec = _mm256_loadu_ps(a);
    __m256 b_vec = _mm256_loadu_ps(b);
    __m256 c_vec = _mm256_add_ps(a_vec, b_vec);
    _mm256_storeu_ps(c, c_vec);

    for (int i = 0; i < size; i++) {
        std::cout << c[i] << " ";
    }
}

immintrin.hというのがAVX拡張命令を使用するためのヘッダーファイルで、

m256とある関数がその命令セットを使用する関数になります。

どんな関数が使えるのはこちらのサイトを参照した方が解りやすい。

https://chryswoods.com/vector_c++/immintrin.html

英語だけど中堅プログラマーなら理解できる内容でしょ。

RUST勉強中、1/17の積み上げ

サブスクリプション処理を実装していきます。

icedではサブスクリプションを利用することによって、非同期処理側からメッセージを送信する事ができるようです。

サブスクリプションを利用するにはレシピを作成しなければなりません。

pub struct Timer {
    duration: Duration,
}

impl Timer {
    fn new(duration: Duration) -> Timer {
        Timer { duration: duration }
    }
}

impl<H, E> iced_native::subscription::Recipe<H, E> for Timer
where
    H: std::hash::Hasher,
{
    type Output = Instant;

    fn hash(&self, state: &mut H) {
        use std::hash::Hash;
        std::any::TypeId::of::<Self>().hash(state);
        self.duration.hash(state);
    }

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, E>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        use futures::stream::StreamExt;
        async_std::stream::interval(self.duration)
            .map(|_| Instant::now())
            .boxed()
    }
}

もうここまで来たら何が何だか解りません。

後でRustの文法見直す。

サブスクリプション処理を作成し、Executorの設定を書き直せばメッセージ送信処理は完成です。

impl Application for GUI {
    type Executor = executor::Default;
    type Message = Message;
    type Flags = ();
    fn subscription(&self) -> Subscription<Message> {
        let timer = Timer::new(Duration::from_millis(MILLISEC / FPS));
        iced::Subscription::from_recipe(timer).map(|_| Message::Update)
    }

あとは受信側を作成。

コードはこうなりました。

use iced::{
    button, executor, Align, Application, Button, Column, Command, Element, Font,
    HorizontalAlignment, Length, Row, Settings, Subscription, Text,
};
use iced_futures::{self, futures};
use std::time::{Duration, Instant};

const FONT: Font = Font::External {
    name: "PixelMplus12-Regular",
    bytes: include_bytes!("../rsc/PixelMplus12-Regular.ttf"),
};

const FPS: u64 = 30;
const MILLISEC: u64 = 1000;
const MINUTE: u64 = 60;
const HOUR: u64 = 60 * MINUTE;

#[derive(Debug, Clone)]
pub enum Message {
    Start,
    Stop,
    Reset,
    Update,
}

pub enum TickState {
    Stopped,
    Ticking,
}

pub struct Timer {
    duration: Duration,
}

impl Timer {
    fn new(duration: Duration) -> Timer {
        Timer { duration: duration }
    }
}

impl<H, E> iced_native::subscription::Recipe<H, E> for Timer
where
    H: std::hash::Hasher,
{
    type Output = Instant;

    fn hash(&self, state: &mut H) {
        use std::hash::Hash;
        std::any::TypeId::of::<Self>().hash(state);
        self.duration.hash(state);
    }

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, E>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        use futures::stream::StreamExt;
        async_std::stream::interval(self.duration)
            .map(|_| Instant::now())
            .boxed()
    }
}

struct GUI {
    last_update: Instant,
    total_duration: Duration,
    tick_state: TickState,
    start_stop_button_state: button::State,
    reset_button_state: button::State,
}

impl Application for GUI {
    type Executor = executor::Default;
    type Message = Message;
    type Flags = ();

    fn new(_flags: ()) -> (GUI, Command<Self::Message>) {
        (
            GUI {
                last_update: Instant::now(),
                total_duration: Duration::default(),
                tick_state: TickState::Stopped,
                start_stop_button_state: button::State::new(),
                reset_button_state: button::State::new(),
            },
            Command::none(),
        )
    }

    fn title(&self) -> String {
        String::from("DEMO")
    }

    fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
        match message {
            Message::Start => {
                self.tick_state = TickState::Ticking;
                self.last_update = Instant::now();
            }
            Message::Stop => {
                self.tick_state = TickState::Stopped;
                self.last_update += Instant::now() - self.last_update;
            }
            Message::Reset => {
                self.last_update = Instant::now();
                self.total_duration = Duration::default();
            }
            Message::Update => match self.tick_state {
                TickState::Ticking => {
                    let now_update = Instant::now();
                    self.total_duration += now_update - self.last_update;
                    self.last_update = now_update;
                }
                _ => {}
            },
        }
        Command::none()
    }

    fn view(&mut self) -> Element<Self::Message> {
        let seconds = self.total_duration.as_secs();
        let duration_text = format!(
            "{:0>2}:{:0>2}:{:0>2}.{:0>2}",
            seconds / HOUR,
            (seconds % HOUR) / MINUTE,
            seconds % MINUTE,
            self.total_duration.subsec_millis() / 10,
        );

        let start_stop_text = match self.tick_state {
            TickState::Stopped => Text::new("Start")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
            TickState::Ticking => Text::new("Stop")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        };

        let start_stop_message = match self.tick_state {
            TickState::Stopped => Message::Start,
            TickState::Ticking => Message::Stop,
        };
        
        let tick_text = Text::new(duration_text).font(FONT).size(60);
        let start_stop_button = Button::new(&mut self.start_stop_button_state, start_stop_text)
            .min_width(80)
            .on_press(start_stop_message);
        let reset_button = Button::new(
            &mut self.reset_button_state,
            Text::new("Reset")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        )
            .min_width(80)
            .on_press(Message::Reset);

        Column::new()
            .push(tick_text)
            .push(
                Row::new()
                    .push(start_stop_button)
                    .push(reset_button)
                    .spacing(10),
            )
            .spacing(10)
            .padding(10)
            .width(Length::Fill)
            .height(Length::Fill)
            .align_items(Align::Center)
            .into()
    }

    fn subscription(&self) -> Subscription<Message> {
        let timer = Timer::new(Duration::from_millis(MILLISEC / FPS));
        iced::Subscription::from_recipe(timer).map(|_| Message::Update)
    }
}

fn main() {
    let mut settings = Settings::default();
    settings.window.size = (400u32, 120u32);
    GUI::run(settings);
}

【数学】【PYTHON】ヘロンの公式

2ヶ月開いてしまった・・・

ぼちぼち再開していきます。

ヘロンの公式は三角形の3辺の長さから面積を求める公式です。

三角形の三辺の長さをそれぞれa,b,cとすると、計算式は以下になります。

import math

x = [1, 3, 6]
y = [5, 1, 4]

a = math.sqrt((x[1] - x[0])**2 + (y[1] - y[0])**2)
b = math.sqrt((x[2] - x[1])**2 + (y[2] - y[1])**2)
c = math.sqrt((x[2] - x[0])**2 + (y[2] - y[0])**2)
s = (a + b + c) / 2

ans = math.sqrt(s * (s - a) * (s - b) * (s - c))

print(ans)
$ python3 heron_area.py 
8.999999999999996

A(1,5),B(3,1),C(6,4)、a=辺AB,b=辺BC,c=辺ACとすると、

面積はおよそ9となります。

【ラズパイ】e-Paperを使ってみる。

今回購入したのはこちら。

e-Paperです。

HATになっているので、GPIOのピンを刺すと、ラズパイゼロの大きさにピッタリはまります。

使用する方法はこちらに書いてあるのですが。

https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_(B)_Manual#Introduction

使用するためには、ラズパイの設定でSPIを有効にする必要があります。

sudo raspi-config

必要なPythonモジュールをインストール

sudo apt-get update
sudo apt-get install python3-pip
sudo apt-get install python3-pil
sudo apt-get install python3-numpy
sudo pip3 install RPi.GPIO
sudo pip3 install spidev

サンプルのダウンロードはGitHubからチェックアウトする方法と、

圧縮ファイルをダウンロードして解凍する方法が記載されていますが、

どちらか一方だけで大丈夫です。

git clone https://github.com/waveshare/e-Paper.git
cd e-Paper/RaspberryPi_JetsonNano/

あとはデモ用のプログラムを実行するだけなのですが、

美味く実行できない事件が発生。

cd python/examples/
python3 epd_2in13b_V4_test.py

おそらくサンプルのバグだと思うのですが、

python3 epd_2in13b_V3_test.py

で上手く実行できました。

次回はサンプルコードの解析を行いたいと思います。

【C#】【アルゴリズム】階段の上り型(動的計画法の例)

以下の様な、「階段の上り方」の問題です。

それぞれの段に行くまでに何通りあるか、というのを考えます。

0段目はスタート地点なので、1通り、

1段目は0段目からでしか行けないので1通り、

2段目は0段目から来るケースと1段目からケースがあるから、0段目と1段目の合計値、

それ以降はi段目はi-1段目とi-2段目の合計値となります。

最終的にN段目の合計値を出力すればOKです。

        public int UpsideStairs(int N)
        {
            int[] dp = new int[45];

            for(int i = 0; i <= N; i++)
            {
                if(i <= 1)
                {
                    dp[i] = 1;
                }
                else
                {
                    dp[i] = dp[i - 1] + dp[i - 2];
                }
            }

            return dp[N];
        }

【数学】【PYTHON】点と直線の距離を計算する

点(x1, y1)と直線ax+by+c=0の距離を求める公式は、

で求められます。

数式をWordで書くのめんどくさ。

点(1,6)から直線y=3/4x-1を計算する処理です。

分数を取り払って3x-4y-1=0に変換してます。

>>> import math
>>> x = 1
>>> y = 6
>>> a = 3
>>> b = -4
>>> c = -4
>>> math.fabs(a*x + b*y + c) / math.sqrt(a**2 + b**2)
5.0

RUST勉強中、11/17の積み上げ

ボタン処理の実装を行っていきます。

ライブラリはicedを使用しています。

use iced::{
    button, executor, Align, Application, Button, Column, Command, Element, Font,
    HorizontalAlignment, Length, Row, Settings, Subscription, Text,
};

const FONT: Font = Font::External {
    name: "PixelMplus12-Regular",
    bytes: include_bytes!("../rsc/PixelMplus12-Regular.ttf"),
};

#[derive(Debug, Clone)]
pub enum Message {
    Start,
    Stop,
    Reset,
}

pub enum TickState {
    Stopped,
    Ticking,
}

struct GUI {
    tick_state: TickState,
    start_stop_button_state: button::State,
    reset_button_state: button::State,
}

impl Application for GUI {
    type Executor = executor::Null;
    type Message = Message;
    type Flags = ();

    fn new(_flags: ()) -> (GUI, Command<Self::Message>) {
        (
            GUI {
                tick_state: TickState::Stopped,
                start_stop_button_state: button::State::new(),
                reset_button_state: button::State::new(),
            },
            Command::none(),
        )
    }

    fn title(&self) -> String {
        String::from("DEMO")
    }

    fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
        match message {
            Message::Start => {
                self.tick_state = TickState::Ticking;
            }
            Message::Stop => {
                self.tick_state = TickState::Stopped;
            }
            Message::Reset => {}
        }
        Command::none()
    }

    fn view(&mut self) -> Element<Self::Message> {
        let duration_text = "00:00:00.00";

        let start_stop_text = match self.tick_state {
            TickState::Stopped => Text::new("Start")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
            TickState::Ticking => Text::new("Stop")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        };

        let start_stop_message = match self.tick_state {
            TickState::Stopped => Message::Start,
            TickState::Ticking => Message::Stop,
        };
        
        let tick_text = Text::new("00:00:00.00").font(FONT).size(60);
        let start_stop_button = Button::new(&mut self.start_stop_button_state, start_stop_text)
            .min_width(80)
            .on_press(start_stop_message);
        let reset_button = Button::new(
            &mut self.reset_button_state,
            Text::new("Reset")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        )
            .min_width(80)
            .on_press(Message::Reset);

        Column::new()
            .push(tick_text)
            .push(
                Row::new()
                    .push(start_stop_button)
                    .push(reset_button)
                    .spacing(10),
            )
            .spacing(10)
            .padding(10)
            .width(Length::Fill)
            .height(Length::Fill)
            .align_items(Align::Center)
            .into()
    }
}

fn main() {
    let mut settings = Settings::default();
    settings.window.size = (400u32, 120u32);
    GUI::run(settings);
}

Messageの定義とTickStateの定義を追加しています。

またアプリケーションの状態として、tick_stateを追加しています。

型はTickStateです。

viewの処理に追加し、tick_stateの状態でボタンに表示するテキストstart_stop_textを決めています。

また、ボタン処理に飛ばすメッセージstart_stop_messageの値も決めています。

そして、ボタン押下時にstart_stop_messageを飛ばし、

それをupdate()で受け取って、tick_stateの値を変えています。

【C#】【アルゴリズム】カエルの移動(動的計画法の例)

カエルの移動というのはこんな感じの問題です。

アルゴリズムのテキストから抜粋しました。

これを計算するのに動的計画法を使用します。

動的計画法とは、数列の漸化式のように問題を小さな問題(一つ前の)計算結果を使用して解くアルゴリズムで、

では漸化式とは?というと、例えばフィボナッチ数列のように、1+1=2、1+2=3、2+3=5、3+5=8のような数列です。

一般化すると、H[i-1]を使用して計算した値と、H[i-2]を使用して計算した値を比較して、適用する値を決定、それを繰り返していく、というやりかたですな。(現時点での理解)

        public int FrogMove(int[] H)
        {
            int[] dp = new int[H.Length];

            for(int i = 0; i < H.Length; i++)
            {
                if(i == 0)
                {
                    dp[i] = 0;
                }
                if(i == 1)
                {
                    dp[i] = Math.Abs(H[i - 1] - H[1]);
                }
                if(i >= 2)
                {
                    int v1 = dp[i - 1] + Math.Abs(H[i - 1] - H[i]);
                    int v2 = dp[i - 2] + Math.Abs(H[i - 2] - H[i]);
                    dp[i] = Math.Min(v1, v2);
                }
            }
            return dp[H.Length - 1];
        }

【数学】【PYTHON】平方根の定理で円を描く

平方根の定理はa^2+b^2=c^2なので、

円の半径rを組み込むと、

y=√r^2-x^2

で求めることができます。

import matplotlib.pyplot as plt
import numpy as np

r = 300
x = np.arange(-r, r + 1)
y = np.sqrt(r**2 - x**2)

#描画
plt.plot(x, y)
plt.axis('equal')
plt.grid(color='0.8')
plt.show()

RUST勉強中、11/3の積み上げ

今回はGUIアプリケーションとして、デジタル時計を作っていきます。

フォントデータはテキストにはURL書かれていなかったのですが、

以下のサイトからダウンロードできます。

use iced::{
    button, executor, Align, Application, Button, Column, Command, Element, Font,
    HorizontalAlignment, Length, Row, Settings, Subscription, Text,
};

const FONT: Font = Font::External {
    name: "PixelMplus12-Regular",
    bytes: include_bytes!("../rsc/PixelMplus12-Regular.ttf"),
};

struct GUI {
    start_stop_button_state: button::State,
    reset_button_state: button::State,
}

impl Application for GUI {
    type Executor = executor::Null;
    type Message = ();
    type Flags = ();

    fn new(_flags: ()) -> (GUI, Command<Self::Message>) {
        (
            GUI {
                start_stop_button_state: button::State::new(),
                reset_button_state: button::State::new(),
            },
            Command::none(),
        )
    }

    fn title(&self) -> String {
        String::from("DEMO")
    }

    fn update(&mut self, _message: Self::Message) -> Command<Self::Message> {
        Command::none()
    }

    fn view(&mut self) -> Element<Self::Message> {
        let tick_text = Text::new("00:00:00.00").font(FONT).size(60);
        let start_stop_button = Button::new(
            &mut self.start_stop_button_state,
            Text::new("Start")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        )
        .min_width(80);
        let reset_button = Button::new(
            &mut self.reset_button_state,
            Text::new("Reset")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        )
        .min_width(80);

        Column::new()
            .push(tick_text)
            .push(
                Row::new()
                    .push(start_stop_button)
                    .push(reset_button)
                    .spacing(10),
            )
            .spacing(10)
            .padding(10)
            .width(Length::Fill)
            .height(Length::Fill)
            .align_items(Align::Center)
            .into()
    }
}

fn main() {
    let mut settings = Settings::default();
    settings.window.size = (400u32, 120u32);
    GUI::run(settings);
}