coLinux日記

coLinuxはフリーソフトを種として、よろずのシステムとぞなれりける。

Python 3.13.1 で、試しに Cython を使って見る。

2025-01-07 15:40:40 | Python
以前の記事、
https://blog.goo.ne.jp/espiya/e/cf058105a1d29877e483a3bd007b4039

では、インストールした Python 3.13 に Cython をインストールしておきました。Papsberry Pi は遅いので Cython の様な高速化は魅力的です。

Welcome to Cython's Developmentation
https://cython.readthedocs.io/en/stable/index.html

そこで、年末年始の隙間時間を利用して、前回インストールした Cython を使って見ます。
全く使ったことがないので、とりあえず次のものに出ていたプログラムを使います。

Faster code via static typing
https://cython.readthedocs.io/en/latest/src/quickstart/cythonize.html

このページでは、Pure Python と Cython の変更点がわかるようになっています。Pythonは変数の値の型が決まっていないので型変換に時間がかかるという考えから、Cython では型定義をするのが重要な変更点みたいです。

さて、この中の、integrate.py を Cython プログラムに変形したものが integrate_cy.pyx です。
関数の引数はそのまま型定義ができて、内部変数は cdef で定義するのですね。それ以外は変更していません。

$ cat integrate.py
def f(x):
   return x ** 2 - x

def integrate_f(a, b, N):
   s = 0
   dx = (b - a) / N
   for i in range(N):
     s += f(a + i * dx)
   return s * dx
$

$ cat integrate_cy.pyx
def f(double x):
   return x ** 2 - x

def integrate_f(double a, double b, int N):
   cdef int i
   cdef double s
   cdef double dx

   s = 0
   dx = (b - a) / N
   for i in range(N):
     s += f(a + i * dx)
   return s * dx
$


次にコンパイル?するために、setup.py を作ります。色々な所を参考にして適当に作りました。

$ cat setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize

ext = Extension("integrate", sources=["integrate_cy.pyx"], include_dirs=['.'])
setup(name="integrate", ext_modules=cythonize([ext]))

$

コンパイルします。
$ python3 setup.py build_ext --inplace
省略
$

これによって、

./build/
integrate.cpython-313-aarch64-linux-gnu.so
integrate_cy.c


が作成されました。ディレクトリ build の中身は以下の通りです。

$ ls -R build
build:
lib.linux-aarch64-cpython-313 temp.linux-aarch64-cpython-313

build/lib.linux-aarch64-cpython-313:
integrate.cpython-313-aarch64-linux-gnu.so

build/temp.linux-aarch64-cpython-313:
integrate_cy.o

$

Cython で作成されたライブラリ integrate を使って、以下のプログラム test001.py を動かすことができます。

$ cat test001.py
from integrate import f, integrate_f

if __name__ == "__main__":
   result = integrate_f(0.0, 2.0, 2000000)
   print(result)
$


比較用に、Pythonのプログラム test002.py も用意します。integrate.py の2つの関数を陽に定義しておきました。

$ cat test002.py
def f(x):
   return x ** 2 - x

def integrate_f(a, b, N):
   s = 0
   dx = (b - a) / N
   for i in range(N):
     s += f(a + i * dx)
   return s * dx

result = integrate_f(0.0, 2.0, 2000000)
print(result)
$

2つを実行して速度を比較します。

$ time python3 test001.py
0.6666656666670076

real 0m0.556s
user 0m0.543s
sys 0m0.012s

$ time python3 test002.py
0.6666656666670076

real 0m1.136s
user 0m1.128s
sys 0m0.009s
$


実際に2倍少し早くなっていますね。

今回とりあえず Cython を使ってみました。
必要な修正もあまりないので有用そうなので今後ももう少し調べてみたいと思います。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

スパムメールの傾向をまとめて見る。

2024-12-30 09:30:10 | その他
sendmail を扱っていると、メールのヘッダーが気になります。そんな中で、今スパムメールがどうなっているか気になりました。

年末なので、スパムメールの傾向をまとめてみました。2024-12-28 に、個人的なメールアドレスに来た91通です。

ここに出てくる固有名詞は誘導目的なので実際のものとは何の関係もありません。

スパムメールなので内容はどうでもよく、「ヘッダーFrom」を中心に集めてみました。

スパムメールなので、ヘッダーFromに差出人メールアドレスのドメイン名以外に差出人を表す名前でまとめます。メールアドレスの仕組みが分からないと引っかけるために名前の方が重要ですね。
Subject: の文面抜粋も追記してみます。

改めて分かったのは、次の点です。

・ ヘッダーFrom に改行文字を入れるものもある。
・ ヘッダーDate で +0900 以外のものがほとんど。 特に +0800 が多い。

ヘッダーDate を替えるのは難しいみたいですね。話題になった nintendo.com も多数あり、 +0900 になっています。

以下は、From の名前、メールアドレスのドメイン名、Subject の抜粋、Date 情報、になっています。例によって、空白文字が1文字になるので見にくいのはご容赦ください。

ETC利用紹介サービス accounts.nintendo.com 解約予告のお知らせ Sat. 28 Dec 2024 00:xx:xx +0900
PayPay classi.jp 最大50,000円分のポイントをプレゼント Fri. 27 Dec 2024 23:xx:xx +0800
Amazon guoc.com 支払い方法の承認が必要 Sat. 28 Dec 2024 00:xx:xx +0800
Amazon jojo.net 支払い方法の承認が必要 Sat. 28 Dec 2024 00:xx:xx +0800
PayPya gilt.jp 2025年新年福袋キャンペーン! Sat, 28 Dec 2024 00:xx:xx +0800
佐川急便株式会社 cugs.com 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 01:xx:xx +0800
佐川急便株式会社 xhki.com 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 01:xx:xx +0800
Amazon.co.jp rkpzz.com Amazonから情報を更新 Sat. 28 Dec 2024 01:xx:xx +0800
PayPay creema.jp 最大18万円分のポイント Sat, 28 Dec 2024 01:xx:xx +0800
自動配信 ildl.com ETC利用照会サービスの重要なお知らせ Dec, 28 Dec 2024 02:xx:xx +0800
Amazon bcef.net 支払い方法の承認が必要 Sat. 28 Dec 2024 02:xx:xx +0800
Amazon ab.em-net.ne.jp Amazon重要情報についての通知 Fri, 27 Dec 2024 19:xx:xx GMT
PayPya costcojapan.jp (文字化け) Sat, 28 Dec 2024 03:xx:xx +0800
PayPay classi.jp PayPayで最大100,000円 Sat, 28 Dec 2024 03:xx:xx +0800
エスポカード accounts.nintendo.com 5,000エポスポイント Sat, 28 Dec 2024 04:xx:xx +0900
????? accounts.nintendo.com 口座取引制限のご案内 Sat, 28 Dec 2024 05:xx:xx +0900
????? accounts.nintendo.com 口座取引制限のご案内 Sat, 28 Dec 2024 05:xx:xx +0900
Amazon ab.em-net.ne.jp お支払方法に問題があり Fri, 27 Dec 2024 21:xx:xx GMT
PayPya hyumanet.jp PayPayで最大100,000円 Sat, 28 Dec 2024 06:xx:xx +0800
Amazon za.cyperhome.ne.jp Аmazonアカウントの情報更新 Fri, 27 Dec 2024 22:xx:xx GMT
Amazon cvgrp.com 支払い方法の承認が必要 Sat, 28 Dec 2024 06:xx:xx +0800
えきねっと mhwi.com えきねっとアカウントの自動退会処理 Sat, 28 Dec 2024 06:xx:xx +0800
Amazon ptoi.com 支払い方法の承認が必要 Sat, 28 Dec 2024 06:xx:xx +0800
Amazon wcrap.com 支払い方法の承認が必要 Sat, 28 Dec 2024 06:xx:xx +0800
Amazon udho.com 支払い方法の承認が必要 Sat, 28 Dec 2024 06:xx:xx +0800
Amazon jmeg.com 支払い方法の承認が必要 Sat, 28 Dec 2024 06:xx:xx +0800
PayPay costcojapan.jp 10,000円分のポイント Sat, 28 Dec 2024 06:xx:xx +0800
Amazon grdi.com 支払い方法の承認が必要 Sat, 28 Dec 2024 07:xx:xx +0800
自動配信 equo.com ETC利用照会サービスの重要なお知らせ Dec, 28 Dec 2024 07:xx:xx +0800
ヤマト運輸株式会社 xnow.net お荷物お届けのお知らせ Sat, 28 Dec 2024 07:xx:xx +0800
Amazon za.cyberhome.ne.jp あなたのAmazonアカウントはセキュリティ Fri, 27 Dec 2024 23:xx:xx GMT
PayPay sosekikan.co.jp 最大10,000円分のPayPayポイントバック Sat, 28 Dec 2024 07:xx:xx +0800
ヤマト運輸株式会社 chtah.net お荷物お届けのお知らせ Sat, 28 Dec 2024 07:xx:xx +0800
えきねっと dtie.com えきねっとアカウントの自動退会処理 Sat, 28 Dec 2024 07:xx:xx +0800
国税庁 onjq.com e-Tax税務署からの【未払い税金 Sat, 28 Dec 2024 07:xx:xx +0800
????? accounts.nintendo.com 口座取引制限のお知らせ Sat, 28 Dec 2024 09:xx:xx +0900
????? accounts.nintendo.com Vpass情報更新のご案内: Sat, 28 Dec 2024 09:xx:xx +0900
Amazon zyro.net 支払い方法の承認が必要 Sat, 28 Dec 2024 08:xx:xx +0800
佐川急便株式会社 rrpn.com 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 08:xx:xx +0800
Amazon fyrn.com 支払い方法の承認が必要 Sat, 28 Dec 2024 08:xx:xx +0800
Amazon.ne.jp enil.com 支払い方法の承認が必要 Sat, 28 Dec 2024 08:xx:xx +0800
ユーシーカード株式会社 xiykici.com 年終キャッシュバックのお知らせ Sat, 28 Dec 2024 10:xx:xx +0900
PayPay glaq.com (文字化け) Sat, 28 Dec 2024 09:xx:xx +0800
Amazon.co.jp krtt.net Amazonプライム会費のお支払い方法に問題 Sat, 28 Dec 2024 09:xx:xx +0800
東京電力エナジーパートナー appl.net 未払いの電気料金についてご連絡 Sat, 28 Dec 2024 09:xx:xx +0800
PayPay hyumannet.jp (文字化け) Sat, 28 Dec 2024 09:xx:xx +0800
東京電力エナジーパートナー wvht.net 未払いの電気料金についてご連絡 Sat, 28 Dec 2024 09:xx:xx +0800
株式会社NTTドコモ ewngy.cn ご請求金額確定のご案内 Sat, 28 Dec 2024 09:xx:xx +0800
TS CUBIC CARD service.vrglj.cn お支払い予定金額のご案内 ENEOSカード Sat, 28 Dec 2024 10:xx:xx +0900
Amazon ndix.net 支払い方法の承認が必要 Sat, 28 Dec 2024 10:xx:xx +0800
Apple iwpy.com Appleサポートセンターより、重要な Sat, 28 Dec 2024 10:xx:xx +0800
Amazon qfcl.com 支払い方法の承認が必要 Sat, 28 Dec 2024 10:xx:xx +0800
PayPay hyumanet.jp 最大30,000円分のPayPayポイント Sat, 28 Dec 2024 10:xx:xx +0800
Amazon ycmc.com 支払い方法の承認が必要 Sat, 28 Dec 2024 11:xx:xx +0800
Amazon.co.jp jjce.net 支払い方法の承認が必要 Sat, 28 Dec 2024 11:xx:xx +0800
Amazon glata.net 支払い方法の承認が必要 Sat, 28 Dec 2024 11:xx:xx +0800
Amazon jrbj.com 支払い方法の承認が必要 Sat, 28 Dec 2024 11:xx:xx +0800
PayPay creema.jp 最大100,000円分のポイントをゲット Sat, 28 Dec 2024 11:xx:xx +0800
三井住友カード株式会社 accounts.nintendo.com 口座取引制限のお知らせ: Sat, 28 Dec 2024 13:xx:xx +0900
ヤマト運輸株式会社 blbd.com お荷物お届けのお知らせ Sat, 28 Dec 2024 12:xx:xx +0800
マスター カード zumi.net マスター カード認証通知 Sat, 28 Dec 2024 12:xx:xx +0800
Amazon fundsle.com 支払い方法の承認が必要 Sat, 28 Dec 2024 12:xx:xx +0800
PayPay cbel.com (文字化け) Sat, 28 Dec 2024 12:xx:xx +0800
セゾンカード ntt-finance.co.jp Netアンサーのアカウント確認 Sat, 28 Dec 2024 13:xx:xx +0900
PayPay creema.jp (文字化け) Sat, 28 Dec 2024 13:xx:xx +0800
佐川急便株式会社 xhba.com 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 13:xx:xx +0800
Amazon.co.jp fahn.com ご利用の Amazon アカウントを一時保留 Sat. 28 Dec 2024 14:xx:xx +0800
佐川急便株式会社 voeed.com 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 14:xx:xx +0800
マスター カード hbng.com マスター カード認証通知 Sat, 28 Dec 2024 14:xx:xx +0800
佐川急便株式会社 vgeo.net 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 14:xx:xx +0800
Amazon.co.jp creema.jp Amazonプライム会員のお支払い方法 Sat, 28 Dec 2024 14:xx:xx +0800
Amazon lkok.com 支払い方法の承認が必要 Sat, 28 Dec 2024 14:xx:xx +0800
PayPay costocojapan.jp (文字化け) Sat, 28 Dec 2024 14:xx:xx +0800
Amazon sanc.com 支払い方法の承認が必要 Sat, 28 Dec 2024 14:xx:xx +0800
PayPay glaq.com (文字化け) Sat, 28 Dec 2024 15:xx:xx +0800
ETC利用照会サービス accounts.nintendo.com 解約予告のお知らせ Sat, 28 Dec 2024 16:xx:xx +0900
Amazon poma.com 支払い方法の承認が必要 Sat, 28 Dec 2024 15:xx:xx +0800
Apple pchw.net Appleサポートセンターより、重要な Sat, 28 Dec 2024 16:xx:xx +0800
セゾンカード saisoncard.co.jp セゾンカード ご利用確認のお願い Sat, 28 Dec 2024 17:xx:xx +0800
Amazon ipdl.com 支払い方法の承認が必要 Sat, 28 Dec 2024 18:xx:xx +0800
佐川急便株式会社 avfd.net 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 19:xx:xx +0800
..@docomo.ne.jp docomo.ne.jp 交通系IC suica・高速道路ETC Sat, 28 Dec 2024 05:xx:xx -0700
Amazon wmtw.com 支払い方法の承認が必要 Sat, 28 Dec 2024 20:xx:xx +0800
佐川急便株式会社 apjv.net 【重要】お荷物の配達について重要なお知らせ Sat. 28 Dec 2024 20:xx:xx +0800
ETC利用照会サービス accounts.nintendo.com 解約予告のお知らせ Sat, 28 Dec 2024 22:xx:xx +0900
Amazon wyex.com 支払い方法の承認が必要 Sat, 28 Dec 2024 21:xx:xx +0800
ヤマト運輸株式会社 dftr.com お荷物お届けのお知らせ Sat, 28 Dec 2024 22:xx:xx +0800
Amazon bdry.net 支払い方法の承認が必要 Sat, 28 Dec 2024 22:xx:xx +0800
Amazon glmi.net 支払い方法の承認が必要 Sat, 28 Dec 2024 22:xx:xx +0800
えきねっと igta.net えきねっとアカウントの自動退会処理 Sat, 28 Dec 2024 22:xx:xx +0800
PayPay glaq.com PayPay 新年開運キャンペーン Sat, 28 Dec 2024 23:xx:xx +0800

気になる .jp で Authentication-Results ヘッダーを見ると dmarc=fail でした。

また、期待していた SPF: Sender Policy Framework で送信元アドレスの偽証を検証する Received-SPF ヘッダーは、 SOFTFAIL が多くてもう少し時間がかかりそうな気がしました。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Raspberry Pi に Python 3.13.1 をインストールする。

2024-12-05 18:46:25 | Python
Python 3.13.1 がリリースされました。早速アップデートします。これで、Python 3.13 もメンテナンスリリースモードになりました。定期的にアップデートされていくと思います。

https://www.python.org/downloads/release/python-3131/ の冒頭は、以下のようです。

Python 3.13 は Python プログラミング言語の最新メジャー リリースであり、Python 3.12 と比較して多くの新機能と最適化が含まれています。 3.13.1 は最新のメンテナンス リリースで、3.13.0 以降の約 400 のバグ修正、ビルドの改善、ドキュメントの変更が含まれています。

早速ソースをダウンロードしましょう。

$ wget https://www.python.org/ftp/python/3.13.1/Python-3.13.1.tar.xz
$

$ md5sum Python-3.13.1.tar.xz;echo 80c16badb94ffe235280d4d9a099b8bc
80c16badb94ffe235280d4d9a099b8bc Python-3.13.1.tar.xz
80c16badb94ffe235280d4d9a099b8bc
$

$ wget https://www.python.org/ftp/python/3.13.1/Python-3.13.1.tar.xz.asc

$ gpg --verify Python-3.13.1.tar.xz.asc
gpg: assuming signed data in 'Python-3.13.1.tar.xz'
gpg: Signature made Tue 03 Dec 2024 19:06:34 GMT
gpg: using RSA key 7169605F62C751356D054A26A821E680E5FA6305
gpg: Good signature from "Thomas Wouters <thomas@python.org>" [unknown]
gpg: aka "Thomas Wouters <thomas@xs4all.nl>" [unknown]
gpg: aka "Thomas Wouters <twouters@google.com>" [unknown]
gpg: aka "Thomas Wouters <thomas.wouters.prive@gmail.com>" [unknown]
gpg: aka "Thomas Wouters <thomaswout@gmail.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 7169 605F 62C7 5135 6D05 4A26 A821 E680 E5FA 6305
$


12月3日にサインされています。3.13.0 の時と同じように make します。今回は time コマンドで時間を計ってみました。

$ tar xvf Python-3.13.1.tar.xz
$ cd Python-3.13.1/
$ ./configure --prefix=/usr/local/python --with-readline --enable-shared --enable-optimizations
..............................
configure: creating ./config.status
config.status: creating Makefile.pre
config.status: creating Misc/python.pc
config.status: creating Misc/python-embed.pc
config.status: creating Misc/python-config.sh
config.status: creating Modules/Setup.bootstrap
config.status: creating Modules/Setup.stdlib
config.status: creating Modules/ld_so_aix
config.status: creating pyconfig.h
configure: creating Modules/Setup.local
configure: creating Makefile
$
$ time make
........The necessary bits to build these optional modules were not found:
_dbm
To find the necessary bits, look in configure.ac and config.log.

Checked 112 modules (33 built-in, 77 shared, 1 n/a on linux-aarch64, 0 disabled, 1 missing, 0 failed on import)
make[1]: Leaving directory '/home/espiya/src/Python-3.13.1'

real 51m52.210s
user 49m17.303s
sys 1m36.002s
$


やはり、このRaspberry Pi では、52分くらいかかりますね。
一応、テストも行っておきます。

$ make test
........
21 tests skipped:
test.test_asyncio.test_windows_events
test.test_asyncio.test_windows_utils test.test_gdb.test_backtrace
test.test_gdb.test_cfunction test.test_gdb.test_cfunction_full
test.test_gdb.test_misc test.test_gdb.test_pretty_print
test_android test_dbm_ndbm test_devpoll test_free_threading
test_ioctl test_kqueue test_launcher test_msvcrt test_startfile

4 tests skipped (resource denied): test_winapi test_winconsoleio test_winreg test_winsound test_wmi

test_peg_generator test_tkinter test_ttk test_zipfile64

2 re-run tests:
test_trace test_zipfile

2 tests failed:
test_trace test_zipfile

451 tests OK.

Total duration: 13 min 28 sec
Total tests: run=44,581 failures=2 skipped=1,991
Total test files: run=476/478 failed=2 skipped=21 resource_denied=4 rerun=2
Result: FAILURE then FAILURE
make: *** [Makefile:2194: test] Error 2
$


test_zipfile の部分がエラーになっているところみたいです。
ほとんど問題なさそうなので、そのままインストールします。

$ make install

$
$ python3 --version
Python 3.13.1
$


通常の使い方では、これでよさそうです。
今までの経緯から推測して、おそらく2か月に一度くらいのアップデートがあって、現在テスト中の 3.14 を待つことになるようです。今後は 3.13.1 を使用します。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Raspberry Pi に、llvm の lld をインストールする。Cython も入れてみる。

2024-11-28 22:05:12 | インストールと設定
前回インストールした llvm , clang に続いて、lld もインストールしてみました。

https://lld.llvm.org/

によれば、(DeepL で翻訳)

LLDはLLVMプロジェクトのリンカーで、システム・リンカーのドロップイン・リプレースメントであり、システム・リンカーよりもはるかに高速に動作する。また、ツールチェーン開発者にとって便利な機能も提供する。

ですね。

lld 単独で build しようとすると、うまくいきませんでした。llvm は基本的に llvm-project の中のものと密接に関連しているようで、
ここでも llvm-project-19.1.0.src/ の下で行う必要があるようです。しかも、新しい build 用ディレクトリを作成して build すると、llvm 関連も再び make しているようにみえたので、最初にbuildするときに使った build-proj ディレクトリを使うのがよさそうです。前回作成した build-proj ディレクトリを使います。

$ cd build-proj
$ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local/python ../llvm
............
-- Configuring done (18.2s)
-- Generating done (39.1s)
-- Build files have been written to: /home/espiya/src/llvm-project-19.1.0.src/build-proj
$

$ make
.....................................
[100%] Built target yaml2obj
[100%] Built target ExampleIRTransforms
[100%] Built target Bye
[100%] Built target InlineAdvisorPlugin
[100%] Built target InlineOrderPlugin
[100%] Built target TestPlugin
[100%] Built target DoublerPlugin
[100%] Built target DynamicLibraryLib
[100%] Built target PipSqueak
[100%] Built target SecondLib
[100%] Built target benchmark
[100%] Built target benchmark_main
[100%] Built target llvm-locstats
$

# make install
......
-- Up-to-date: /usr/local/python/include/llvm/TargetParser/ARMTargetParserDef.inc
-- Up-to-date: /usr/local/python/include/llvm/TargetParser/AArch64TargetParserDef.inc
-- Up-to-date: /usr/local/python/include/llvm/TargetParser/RISCVTargetParserDef.inc
-- Installing: /usr/local/python/lib/cmake/llvm/LLVMConfigExtensions.cmake
#

$ which lld
/usr/local/python/bin/lld
$
$ lld --version
lld is a generic driver.
Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld (WebAssembly) instead
$ ld.lld --version
LLD 19.1.0 (compatible with GNU linkers)
$


ここまででインストールできた、llvm を使って、Python 3.13.0 の --enable-experimental-jit オプション付きで build してみましが、やはりうまくいきませんでした。

しかたがないので、別の Python 高速化ツールを考えました。 Cython にしました。(以下は、 Firefox で翻訳しました。)

https://pypi.org/project/Cython/

Cython 言語を使用すると、Python 自体と同じくらい簡単に、Python 言語用の C 拡張機能を作成できます。 Cython は Pyrex をベースにしたソース コード トランスレータですが、より最先端の機能と最適化をサポートしています。

Cython 言語は Python 言語のスーパーセットです (ほぼすべての Python コードも有効な Cython コードです)。ただし、Cython はオプションの静的型付けをサポートしており、C 関数をネイティブに呼び出し、C++ クラスで操作し、変数とクラス属性で高速な C 型を宣言します。これにより、コンパイラーは Cython コードから非常に効率的な C コードを生成できます。

このため、Cython は、外部 C/C++ ライブラリ用のグルー コードや、Python コードの実行を高速化する高速 C モジュールを作成するのに理想的な言語になります。

ワンタイムビルドの場合には注意してください。 CI/テストの場合、PyPI で提供されるホイール パッケージのいずれかでカバーされておらず、当社が提供する純粋な Python ホイールが使用されていないプラットフォームでは、コンパイルされていない (遅い) バージョンの完全なソース ビルドよりも大幅に高速です。


こちらのインストールは pip3 が使えるので簡単です。本当に使えるかどうかはまだ分かりません。

$ pip3 install Cython
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting Cython
Downloading Cython-3.0.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.metadata (3.2 kB)
Downloading Cython-3.0.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.3 MB)
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq 3.3/3.3 MB 14.8 MB/s eta 0:00:00
Installing collected packages: Cython
Successfully installed Cython-3.0.11
$ which cython
/home/espiya/.local/bin/cython
$ cython --version
Cython version 3.0.11
$


使い方は以下を参考にして、今後機会があれば試してみたいと思います。

https://cython.readthedocs.io/en/latest/src/tutorial/
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Raspberry Pi に LLVM + Clang 19.1.0 をインストールする。

2024-11-15 23:07:37 | コンピュータ言語
Python3 のインストールでも分かるように、clang と llvm もこれからは必要そうです。
そこで、今使っている Raspberry Pi に llvm と clang をインストールしてみます。
最新のものは 19.1.0 でした。

先に、関連ありそうなパッケージを入れておきます。

# apt install cmake
# apt install ninja-buil
# apt install llvm llvm-dev
# apt install clang

$ /usr/bin/cmake --version
cmake version 3.25.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).
$
$ /usr/bin/clang --version
Debian clang version 14.0.6
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$

ですね。

念のために、最初に cmake を最新にしておきます。
環境設定は例によって、python3.sh というファイル使います。

$ source ~/python3.sh

$ wget https://github.com/Kitware/CMake/releases/doload/v3.31.0/cmake-3.31.0.tar.gz
$ tar xvf cmake-3.31.0.tar.gz
$ cd cmake-3.31.0

$ ./configure --prefix=/usr/local/python
......
-- Configuring done (126.3s)
-- Generating done (2.9s)
-- Build files have been written to: /home/espiya/src/cmake/cmake-3.31.0
---------------------------------------------
CMake has bootstrapped. Now run gmake.
$


make でなくて gmake と言っていますが、

$ which gmake
/usr/bin/gmake
$ ls -l /usr/bin/gmake
lrwxrwxrwx 1 root root 4 Apr 10 2021 /usr/bin/gmake -> make
$

make コマンドです。 make して、インストールします。

$ gmake

# gmake install


確認します。

$ cmake --version
cmake version 3.31.0

CMake suite maintained and supported by Kitware (kitware.com/cmake).
$


これで、cmake は最新になりました。

これを使って、llvm と clang をインストールしてみます。実は、Raspberry Pi でこれは非常に大変で、色々ためしてみたのですが、中々うまくいかないので苦労しました。最終的には、

https://clang.llvm.org/get_started.html

を参考にしました。

$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/llvm-project-19.1.0.src.tar.xz
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/llvm-project-19.1.0.src.tar.xz.sig
$
$ gpg --verify llvm-project-19.1.0.src.tar.xz.sig
gpg: assuming signed data in 'llvm-project-19.1.0.src.tar.xz'
gpg: Signature made Tue 17 Sep 2024 12:42:39 BST
gpg:      using RSA key D574BD5D1D0E98895E3BF90044F2485E45D59042
gpg: Good signature from "Tobias Hieta '<tobias@hieta.se>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:      There is no indication that the signature belongs to the owner.
Primary key fingerprint: D574 BD5D 1D0E 9889 5E3B F900 44F2 485E 45D5 9042
$


$ tar xvf llvm-project-19.1.0.src.tar.xz
$
$ cd llvm-project-19.1.0.src
$ mkdir build-proj
$ cd build-proj


$ cmake -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/python -G "Unix Makefiles" ../llvm
...........
-- Configuring done (52.2s)
-- Generating done (27.7s)
-- Build files have been written to: /home/espiya/src/llvm-project-19.1.0.src/build-proj
$


$ make
.............
[100%] Linking CXX static library ../../../lib/libbenchmark.a
[100%] Built target benchmark
[100%] Building CXX object third-party/benchmark/src/CMakeFiles/benchmark_main.ir/benchmark_main.cc.o
[100%] Linking CXX static library ../../../lib/libbenchmark_main.a
[100%] Built target benchmark_main
[100%] Copying llvm-locstats into /home/espiya/src/llvm-project-19.1.0.src/buil-proj/./bin
[100%] Built target llvm-locstats
$


このマシンでは、1日以上かかりました。 〇〇% と表示されるので一応目安になります。テストもできます。

$ make check-clang
...........
[100%] Running the Clang regression tests
llvm-lit: /home/espiya/src/llvm-project-19.1.0.src/llvm/utils/lit/lit/llvm/config.py:508: note: using clang: /home/espiya/src/llvm-project-19.1.0.src/build-proj/bin/clang

Testing Time: 3883.81s

Total Discovered Tests: 37989
Skipped : 10 (0.03%)
Unsupported : 150 (0.39%)
Passed : 37802 (99.51%)
Expectedly Failed: 27 (0.07%)
[100%] Built target check-clang
$

こちらも 1時間以上かかりました。

/usr/local/python へのインストール方法は書いていないのですが、普通に make で良さそうです。

# make install
......
-- Up-to-date: /usr/local/python/include/llvm/CodeGen
-- Installing: /usr/local/python/include/llvm/CodeGen/GenVT.inc
-- Up-to-date: /usr/local/python/include/llvm/TargetParser
-- Installing: /usr/local/python/include/llvm/TargetParser/ARMTargetParserDef.inc
-- Installing: /usr/local/python/include/llvm/TargetParser/AArch64TargetParserDef.inc
-- Installing: /usr/local/python/include/llvm/TargetParser/RISCVTargetParserDef.inc
-- Installing: /usr/local/python/lib/cmake/llvm/LLVMConfigExtensions.cmake
#

$ clang --version
clang version 19.1.0
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/python/bin
$


これで、clang 19.1.0 が使えるようになりました。時間はかかりましたが、Raspberry Pi でもビルドできたのが良かったです。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

入門者が、Python プログラミングにおいて、生成AI(Copilot)を使ってコメントとdocstring を付ける。

2024-10-30 18:11:29 | Python
以前紹介した、
PyFlo The beginners guide to becoming a Python programmer
https://pyflo.net/
の中で、「Guided Project 1」をクリックすると、
Flag Creater
https://pyflo.net/flag/
というものがありました。

文化の日も近いので、日の丸を文字で作るプログラムを作ってみました。
Wikipedia で日章旗を調べると、
縦を2とすると横が3、その中央にある円の直径が縦の 3/5 となっています。
縦を 2.0 とすると、横は 3.0 となり、 中央の円の半径は 2 * (3/5) / 2 = 0.6 となります。
半角文字の大きさの比率がだいたい縦:横 2:1 となるので、1行の文字数は旗の左下隅を X-Y平面の原点においたとして、
その座標は、
左上 (0,20) 、 右上 (60,20) 、 
左下 (0,0) 、 右下 (60,0)
としました。変換してそれぞれ、(0.0 , 2.0) 、(3.0 , 2.0)、 (0.0 , 0.0)、(3.0 , 0.0)になります。

これでプログラムを作ってみます。関数も使わない単純なものですが、このプログラムにコメントや docstring を入れるために、 Microsoft Copilot を使いました。

まず、docstring 生成を次のプロンプトで依頼しました。そのとき、プログラムがどのようなものかを簡単に説明する文を陽に入れてみました。

「次のPython プログラムの docstring を生成して下さい。
これは、日章旗を文字で生成するためのプログラムです。
日章旗は、縦の長さを2、幅の長さを3、中央の日の丸の半径を 0.6 になるように作成します。

w = 60
h = 20
a0 = '+' + '-'*(w-1) + '+'
a20 = '+' + '-'*(w-1) + '+'
a = '|' + ' '*(w-1) + '|'

print(a0)
for i in range(1,h):
   y = (h - i) / (h / 2)

   b = a[0]
   for j in range(1,w):
      x = j / (w / 3)

      if ( (x-1.5)**2 + (y-1.0)**2 < 0.36 ) :
         b += '*'
      else:
         b += a[j]
   b += a[-1]

   print(b)

print(a20) 」


Copilot の回答は以下の通りでした。

ここから======
もちろん、こちらがあなたのプログラムのためのdocstringです:

def draw_nisshoki():
   """
   This function prints the Japanese national flag (Nisshoki) using ASCII characters.

   The flag's proportions are a height to width ratio of 2:3, with a red circle (the sun)
   in the center. The circle's radius is 0.6, scaled appropriately to fit within the grid.

   The border of the grid is made up of '+' and '-' characters for the top and bottom,
   and '|' characters for the sides. The sun is drawn using '*' characters inside the grid.

   Variables:
   w (int): The width of the grid.
   h (int): The height of the grid.
   a0 (str): The top border of the grid.
   a20 (str): The bottom border of the grid.
   a (str): The side borders of the grid.

   The function uses nested loops to calculate the positions of the '*' characters
   that form the sun based on the coordinates (x, y) within the grid.
   The equation `( (x-1.5)**2 + (y-1.0)**2 < 0.36 )` is used to determine whether
   a particular point should be part of the sun shape or not.
   """
   w = 60
      .................
      (プロンプトで入力したプログラムなので途中省略)
      .................
   print(a20)

======ここまで


関数にされてしまいました。しかもなぜか英語でした。これは、docstring は、関数やクラスの中で使うかららしいです。 一応 DeepL で翻訳(少し修正あり)しておきます。

この関数は、日本の国旗(日章旗)をASCII文字で印刷します。

 国旗の縦横比は2:3で、中央に赤い円(太陽)がある。円の半径は0.6で、グリッドに収まるように適切に拡大縮小されています。

 グリッドの境界線は、上下に'+'と'-'、左右に'|'で構成されている。太陽はグリッドの内側に'*'文字を使って描かれます。

 変数

 w (int): グリッドの幅。
 h (int): グリッドの高さ。
 a0 (str): グリッドの上辺。
 a20 (str): グリッドの下端。
 a (str): グリッドのサイドボーダー。

 この関数は,ネストされたループを使用して,グリッド内の座標 (x, y) に基づいて太陽を形成する '*' 文字の位置を計算します.

 方程式 `( (x-1.5)**2 + (y-1.0)**2 < 0.36 )` は、特定の点が太陽の形に含まれるかどうかを決定するために使用されます。

プログラムの内容を、ほぼ正確に表してくれていますね。

そこで、今度はこのプロンプトの docstring を コメント にして再び Copilot にたずねました。

「次のPython プログラムを説明するための分かりやすいコメントをプログラムに追加して下さい。
これは、日章旗を文字で生成するためのプログラムです。
日章旗は、縦の長さを2、幅の長さを3、中央の日の丸の半径を 0.6 になるように作成します。
(この後のプログラムは同じなので省略)」


Copilot の回答は以下の通りでした。

ここから======
以下に、プログラムにコメントを追加しました。これで、各部分の動作がわかりやすくなると思います。

```python
# 幅と高さを設定
w = 60
h = 20

# 上部と下部の枠線を作成
a0 = '+' + '-'*(w-1) + '+'
a20 = '+' + '-'*(w-1) + '+'
# 空白の行を作成
a = '|' + ' '*(w-1) + '|'

# 上部の枠線を表示
print(a0)

# 高さ分のループを開始
for i in range(1, h):
   # y座標を計算(中心を基準にした相対位置)
   y = (h - i) / (h / 2)

   # 行の開始文字を設定
   b = a[0]
   # 幅分のループを開始
   for j in range(1, w):
      # x座標を計算(中心を基準にした相対位置)
      x = j / (w / 3)

      # 中心からの距離が半径0.6以内なら '*' を追加、それ以外は空白を追加
      if ( (x-1.5)**2 + (y-1.0)**2 < 0.36 ):
         b += '*'
      else:
         b += a[j]
   # 行の終了文字を追加
   b += a[-1]

   # 行を表示
   print(b)

# 下部の枠線を表示
print(a20)
```

このコメントが、プログラムの理解に役立つことを願っています!他に質問があれば教えてくださいね。

======ここまで


一言も伝えていないのに、プログラムだけから、

上枠(a0)、下枠(a20)と解釈したり、
「中心を基準にした相対位置」と解釈したり、
if 文で陽に 0.36 としか書いていないのにプロンプトから?「半径0.6」と解釈したりと、

しっかりとコメントしてくれています。これは良いですね。

以上、簡単なプログラムを作成して Copilot でコメントやdocstring を付けてもらいましたが、満足できるものでした。

ということは、Python 入門者は生成AIを活用して自分がプログラミングしたプログラムに対してコメントや docstring を付けてもらい、それを参考にしてさらに知識を得ることが、かなり有用であると言えそうです。

最後にプログラムを動作させたときの画像を表示しておきます。作成したプログラムは flag.py というファイルです。


docstring は、Python の有用な機能なのは、SimplePrograms で学ぶうちに理解しました。そうであるなら、初心者は生成AIを積極的に活用して docstring を使うという流れになるかもしれませんね。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Raspberry Pi に Python 3.13.0 をインストールする

2024-10-13 07:54:13 | Python
PEP719 で告知されたとおり、Python 3.13.0 が 2024-10-07 にリリースされました。

当ブログの以前の記事の通りの方法で、早速 Raspberry Pi にインストールしてみます。

まずは、ダウンロードして、チェックします。(例によって空白文字は適当です。)

$ wget http://www.python.org/ftp/python/3.13.0/Python-3.13.0.tar.xz

$ md5sum Python-3.13.0.tar.xz;echo 726e5b829fcf352326874c1ae599abaa
726e5b829fcf352326874c1ae599abaa Python-3.13.0.tar.xz
726e5b829fcf352326874c1ae599abaa
$

$ wget http://www.python.org/ftp/python/3.13.0/Python-3.13.0.tar.xz.asc

$ gpg --verify Python-3.13.0.tar.xz.asc
gpg: assuming signed data in 'Python-3.13.0.tar.xz'
gpg: Signature made Mon 07 Oct 2024 08:30:45 BST
gpg:       using RSA key 7169605F62C751356D054A26A821E680E5FA6305
gpg: Good signature from "Thomas Wouters <thomas@python.org>" [unknown]
gpg:        aka "Thomas Wouters <thomas@xs4all.nl>" [unknown]
gpg:        aka "Thomas Wouters <twouters@google.com>" [unknown]
gpg:        aka "Thomas Wouters <thomas.wouters.prive@gmail.com>" [unknown]
gpg:        aka "Thomas Wouters <thomaswout@gmail.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:       There is no indication that the signature belongs to the owner.
Primary key fingerprint: 7169 605F 62C7 5135 6D05 4A26 A821 E680 E5FA 6305

$


10月7日にサインされていますね。
3.12.6 の時と同じように make してみます。

$ tar xvf Python-3.13.0.tar.xz
$ cd Python-3.13.0
$ ./configure --prefix=/usr/local/python --enable-optimizations --with-readline --enable-shared

$ make    (52分かかりました。)
・・・・・・
Total duration: 6 min 52 sec
Total tests: run=9,361 skipped=201
Total test files: run=44/44
Result: SUCCESS
true
・・・・・・
The necessary bits to build these optional modules were not found:
_dbm
To find the necessary bits, look in configure.ac and config.log.

Checked 112 modules (33 built-in, 77 shared, 1 n/a on linux-aarch64, 0 disabled, 1 missing, 0 failed on import)
make[1]: Leaving directory '〇〇〇〇〇〇/Python-3.13.0'
$

$ make test (今回はテストも行ってみました。)
・・・・・・
21 tests skipped:
   test.test_asyncio.test_windows_events
   test.test_asyncio.test_windows_utils test.test_gdb.test_backtrace
   test.test_gdb.test_cfunction test.test_gdb.test_cfunction_full
   test.test_gdb.test_misc test.test_gdb.test_pretty_print
   test_android test_dbm_ndbm test_devpoll test_free_threading
   test_ioctl test_kqueue test_launcher test_msvcrt test_startfile
   test_winapi test_winconsoleio test_winreg test_winsound test_wmi

4 tests skipped (resource denied):
   test_peg_generator test_tkinter test_ttk test_zipfile64

453 tests OK.

Total duration: 13 min 45 sec
Total tests: run=44,312 skipped=1,693
Total test files: run=474/478 skipped=21 resource_denied=4
Result: SUCCESS
$

# make install

/usr/local/python にインストールされているので、環境変数を設定するのも前回通りです。

$ cat python3.sh
export PATH=/usr/local/python/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/python/lib
$
$ source python3.sh

$ python3 --version
Python 3.13.0
$


これで、Python 3.13.0 のインストールは一応完了です。

https://www.python.org/downloads/release/python-3130/
の中で、(Google Chrome による翻訳)
New features
・ PyPyをベースとした、新しく改良された対話型インタプリタです。複数行の編集や色のサポート、色付きの例外トレースバックが特徴です。


となっていたので、試してみました。

$ python3
Python 3.13.0 (main, Oct 8 2024, 02:36:16) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
(プロンプトやエラーメッセージの一部などがピンク色になった。)
>>> for num in [1,2,3,4]:
...        print(nim)
...
Traceback (most recent call last):
File "<python-input-0>", line 2, in <module>
    print(nim)
    ^^^
NameError: name 'nim' is not defined. Did you mean: 'num'?
>>> for num in [1,2,3,4]:
...        print(nim)
(上矢印キーでいっぺんに表示される。修正も可能!)

>>> for num in [1,2,3,4]:
...        print(num)
...
1
2
3
4
>>>

これは、便利ですね。

さて、New featuresのもう一つ、
・ 予備的、実験的なJITであり、大幅なパフォーマンス向上のための土台となる。

ですが、これは Just In Time コンパイラのことらしいです。これを実現するには、configure のオプション、

--enable-experimental-jit
    build the experimental just-in-time compiler (default is no)


を加える必要があります。試しにこれを加えてmake すると、

$ ./configure --prefix=/usr/local/python --enable-optimizations  --with-readline --enable-shared --enable-experimental-jit
$ make
・・・・
    | raise RuntimeError(f"Can't find {tool}-{_LLVM_VERSION}!")
    | RuntimeError: Can't find clang-18!
   +---------------- ... ----------------
    | and 219 more exceptions
   +------------------------------------
make[2]: *** [Makefile:3029: jit_stencils.h] Error 1
make[2]: Leaving directory '/home/espiya/src/Python-3.13.0-jit'
make[1]: *** [Makefile:889: profile-gen-stamp] Error 2
make[1]: Leaving directory '/home/espiya/src/Python-3.13.0-jit'
make: *** [Makefile:901: profile-run-stamp] Error 2
$

この Raspberry pi ではうまく行きませんでした。残念。
clang はシステムのものでも Ver.16 なので、自分でインストールする必要があります。しかも、clang は LLVM なので、ちょっと大変そうです。
Python って、GCC でなくて、LLVM 推しなのですね。 そのうち試して見たいと思います。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

入門者が生成AIも利用して Python プログラミングを行う。 その4

2024-10-06 16:10:01 | Python
前回までにすべての関数が作成できました。 後は、これらを集めてプログラミングするだけです。

Raspberry Pi が遅いので、最初に考えた検索のループで毎回 fill_list()を使って行リストを作るのは効率が悪そうです。1回だけ実行して、
f_R1,f_R2,f_R3,f_R4,f_R5,f_R6,f_R7,f_R8,f_R9
に代入することにしました。

更に、3行ずつブロックの検査をして、最後に検索するリスト数を減らしてから、列の検査をすることにしました。

プログラムはこんな感じです。

関数定義の部分は省略しました。

print('Question: ')
print_answer(R1,R2,R3,R4,R5,R6,R7,R8,R9)

# 条件を検査して、結果を出力する。
# fill_list()を使うので行の検査は終了している。

f_R1 = fill_list(R1)
f_R2 = fill_list(R2)
f_R3 = fill_list(R3)
f_R4 = fill_list(R4)
f_R5 = fill_list(R5)
f_R6 = fill_list(R6)
f_R7 = fill_list(R7)
f_R8 = fill_list(R8)
f_R9 = fill_list(R9)

right_b1 = []
for row1 in f_R1:
   for row2 in f_R2:
      for row3 in f_R3:
         if chk_block(row1,row2,row3) == False:
            continue
         right_b1.append([row1,row2,row3])
         print(row1)
         print(row2)
         print(row3)
         print('-'*28)
print(' 1-3 blocks')

right_b2 = []
for row4 in f_R4:
   for row5 in f_R5:
      for row6 in f_R6:
         if chk_block(row4,row5,row6) == False:
            continue
         right_b2.append([row4,row5,row6])
         print(row4)
         print(row5)
         print(row6)
         print('-'*28)
print(' 4-6 blocks')

right_b3 = []
for row7 in f_R7:
   for row8 in f_R8:
      for row9 in f_R9:
         if chk_block(row7,row8,row9) == False:
            continue
         right_b3.append([row7,row8,row9])
         print(row7)
         print(row8)
         print(row9)
         print('-'*28)
print(' 7-9 blocks')

print('Answer: ')
for bk1 in right_b1:
   for bk2 in right_b2:
      for bk3 in right_b3:
         if chk_col(bk1[0],bk1[1],bk1[2],bk2[0],bk2[1],bk2[2],bk3[0],bk3[1],bk3[2]) == False:
            continue

         # 答えを出力。複数の答えも想定する。
         print_answer(bk1[0],bk1[1],bk1[2],bk2[0],bk2[1],bk2[2],bk3[0],bk3[1],bk3[2])
         print(' ')

print('=== END ===')

メモリがあふれるかもと思いましたが、それは大丈夫でした。しかし、それでも遅い、最初の答えがでるまで半日、他に答えがないことを調べるため全部の検査にさらに1日くらいかかりました。遅いのでちゃんと動いているか不安になり、3つのブロック検査の途中経過も出力してあります。特に2段目(4-6 blocks) の処理が長かったです。

python3 sudoku.py
Question:
0 9 8 | 0 0 6 | 0 0 4
1 0 4 | 0 0 2 | 0 3 0
3 6 7 | 0 0 1 | 0 0 0
------+-------+-------
0 0 0 | 1 0 0 | 4 9 7
0 0 0 | 0 3 0 | 0 0 0
7 4 2 | 0 0 8 | 0 0 0
------+-------+-------
0 0 0 | 2 0 0 | 9 7 6
0 7 0 | 6 0 0 | 5 0 8
6 0 0 | 5 0 0 | 3 4 0
(途中省略)
[6, 9, 1, 5, 7, 8, 3, 4, 2]
----------------------------
[8, 5, 4, 2, 3, 1, 9, 7, 6]
[3, 7, 2, 6, 9, 4, 5, 1, 8]
[6, 9, 1, 5, 8, 7, 3, 4, 2]
----------------------------
7-9 blocks
Answer:
2 9 8 | 3 5 6 | 7 1 4
1 5 4 | 8 7 2 | 6 3 9
3 6 7 | 4 9 1 | 2 8 5
------+-------+-------
8 3 6 | 1 2 5 | 4 9 7
9 1 5 | 7 3 4 | 8 6 2
7 4 2 | 9 6 8 | 1 5 3
------+-------+-------
5 8 1 | 2 4 3 | 9 7 6
4 7 3 | 6 1 9 | 5 2 8
6 2 9 | 5 8 7 | 3 4 1

=== END ===
$

入門なので、自分で作る関数作成はなるべく単純にしてみました。そんなわけで同じ事を3回も繰り返したりして無駄に長くなっているかもしれませんが、後で分かりやすい事を優先しました。

生成AIも要所で使うことにして、2つの関数生成に使う事ができました。どれを生成AIに任せてどれを自分で作るかは色々と試す必要がありそうです。生成AIの回答の関数は入門者には勉強になる部分も多かったので、ちょっと関数を作るときに気になる事があるなら使って良いのかもしれませんね。途中怪しげなプログラムを提示されました、そこは、回答の通りテストする必要があるわけです。Google Gemini の場合は説明が良いですね。docstring 作成に使った方が良いような気がするのは以前書いた通りでした。

プロンプトに一言も入れていないのに「数独でしょ」と言ってどこかから持ってきた関数を提示するのも面白かったです。

入門者には、生成AIを関数生成とかclass定義とかで活用して、得られたものをテストしたり、その中で知らない機能を使っていたら調べたりする事が経験値を上げるには役立ちそうです。今後生成AIが「この関数はこっちの方が良いですよ。」と言ってくる事は当然ありそうなので、活用したいところです。

Raspberry Pi なので、遅いからスピードアップのために改良するという試行錯誤ができるので、Python入門時には何かと役立ちそうです。
コメント (1)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

入門者が生成AIも利用して Python プログラミングを行う。 その3

2024-10-05 14:31:04 | Python
前回の Gemini へのプロンプトで最初の「Python で」が抜けていました。

さて、「数独」の3つめ条件、縦9列が1~9までのすべての数字を重複無く含んでいる、を調べる関数
chk_col(c1, c2, c3, c4, c5, c6, c7, c8, c9 ) を定義してみます。
単純に9つの行リストを引数に与えます。
(こちらも gemini は、docstring生成のみに使いました。その中で、Args: Returns: のみ使います。)

def chk_col(c1, c2, c3, c4, c5, c6, c7, c8, c9):
   """
   9つのリストからなる9x9の行列の各列に対して、`check_list()` 関数を適用します。
   全ての列で `check_list()` が `True` を返す場合にのみ、`True` を返します。
   Args:
      c1, c2, ..., c9 (list): 要素数9のリスト。それぞれが9x9行列の1つの列に対応します。
   Returns:
   bool: 全ての列が `check_list()` の条件を満たす場合にTrue、そうでない場合にFalse
   """

   for i in range(0,9):
      column=[c1[i],c2[i],c3[i],c4[i],c5[i],c6[i],c7[i],c8[i],c9[i]]
      if check_list(column) == False:
         return False
   return True

さて、各行の空白の要素を埋めるための関数fill_list()を Google Gemini に作成してもらおうとたところ中々うまく行きませんでした。 記録しなかったので詳しくは書けませんがrandom を使ったり、再帰関数にしたりして答えが正しくない関数を提案されました。

問題は、要素の値が0のインデックスを探して、まだ使っていない数値を求めて、値を埋めていくので、順列ということで、SimplePrograms で出てきた itertools ライブラリを使ってみるのも良さそうだと考えて、次のようなプロンプトにしました。

「Python で、要素数9のリストを A とします。A の各要素の値は1から9までの整数でかつ値が重複できないという条件があります。
今、A のいつかの要素に値が設定されており、まだ値が設定されていない要素の値は 0 になっているとします。この A を引数にして、A の値が0 の所に数値をいれて条件を満たすすべてのリストを求め、それぞれのリストを要素とするリストを返却するような関数fill_list(A) を作成してください。必要なら itertools ライブラリを使ってください。」

Gemini の回答は、以下の様にねらいどおりでした。(それが良いかどうかは別の話)

ここから======
## Pythonでリストを完成させる関数fill_list()の実装

### 問題の理解とアプローチ

* **問題:** 要素数9のリストAがあり、一部の要素に値が設定されている。残りの要素に1から9までの重複のない数値を全てのパターンで割り当て、全ての組み合わせのリストを作成する。
* **アプローチ:**
1. **未設定要素のインデックス:** まず、Aの中で値が0の要素のインデックスをリストで取得する。
2. **順列の生成:** itertools.permutations()を用いて、未設定要素に割り当てる数値の全ての順列を生成する。
3. **リストの生成:** 各順列に対して、元のリストAのコピーを作成し、未設定要素のインデックスに順列の値を順に代入していく。
4. **全ての組み合わせのリスト:** 生成された全てのリストを要素とするリストを返す。

### コードの実装

```python
import itertools

def fill_list(A):
   """
   Aの値が0の所に数値をいれて条件を満たすすべてのリストを返す関数
   Args:
      A: 要素数9のリスト。一部の要素に1から9までの値が設定されている。
   Returns:
      list: 条件を満たす全てのリストのリスト
   """
   # 未設定要素のインデックスを取得
   unset_indices = [i for i, x in enumerate(A) if x == 0]
   # 未設定要素に割り当てる数値の候補
   numbers = [i for i in range(1, 10) if i not in A]
   # 全ての順列を生成
   permutations_list = list(itertools.permutations(numbers))
   # 全ての組み合わせのリストを作成
   result = []
   for perm in permutations_list:
      new_list = A.copy()
      for i, num in zip(unset_indices, perm):
         new_list[i] = num
   result.append(new_list)

   return result
```

### コードの説明

* `unset_indices`: Aの中で値が0の要素のインデックスをリストで取得します。
* `numbers`: Aにまだ含まれていない1から9までの数値をリストで取得します。
* `permutations_list`: itertools.permutations()を用いて、numbersの全ての順列を生成し、リストに変換します。
* `result`: 最終的に返却する、全ての組み合わせのリストを格納する空のリストです。
* `new_list`: Aのコピーを作成し、ここに順列の値を代入していきます。
* `zip(unset_indices, perm)`: unset_indicesとpermの要素を同時に取り出すためにzip関数を使用しています。

### 使用例

```python
A = [1, 0, 3, 0, 5, 6, 0, 8, 9]
result = fill_list(A)
print(result)
```

このコードを実行すると、Aの0の要素に可能な全ての組み合わせで数値を代入したリストのリストが得られます。

### 注意点

* リストの長さが9であるという前提で実装されています。
* 0以外の数値が重複して含まれている場合は、意図した結果にならない可能性があります。
* リストの要素数が大きくなると、生成される組み合わせの数が膨大になり、計算時間が長くなる可能性があります。

このコードは、与えられた条件のもとで、Aの全ての組み合わせを効率的に生成することができます。

======ここまで


念のため、prog04.py というファイルを作って、テストします。最初に fill_list()を回答の通り定義して、テスト部分は、

A = [6, 2, 0, 5, 0, 7, 3, 4, 0]
print(A)
print('-'*28)

result = fill_list(A)

for l in result:
print(l)

です。

$ python3 prog04.py
[6, 2, 0, 5, 0, 7, 3, 4, 0]
----------------------------
[6, 2, 1, 5, 8, 7, 3, 4, 9]
[6, 2, 1, 5, 9, 7, 3, 4, 8]
[6, 2, 8, 5, 1, 7, 3, 4, 9]
[6, 2, 8, 5, 9, 7, 3, 4, 1]
[6, 2, 9, 5, 1, 7, 3, 4, 8]
[6, 2, 9, 5, 8, 7, 3, 4, 1]
$

正しい答えが得られるようになりました。
この回答の中では、SimplePrograms で学んだ enumerate()、リスト内包表記、docstring が使われています。
出てこなかった、リストデータ型のメソッド append() と組み込み関数 zip() を調べて見ました。
https://docs.python.org/ja/3/tutorial/datastructures.html

list.append(x)

   リストの末尾に要素を一つ追加します。a[len(a):] = [x] と等価です。


https://docs.python.org/ja/3/library/functions.html#zip

zip(*iterables, strict=False)

   複数のイテラブルを並行に反復処理し、各イテラブルの要素からなるタプルを生成します。

   以下はプログラム例です:
   >>>

for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
   print(item)

(1, 'sugar')
(2, 'spice')
(3, 'everything nice')

より正式な定義: zip() は、 i 番目のタプルが 引数に与えた各イテラブルの i 番目の要素を含むような、タプルのイテレータを返します。


itertoolsライブラリでは、permutations()を使っています。
https://docs.python.org/ja/3/library/itertools.html#itertools.permutations

itertools.permutations(iterable, r=None)

   Return successive r length permutations of elements from the iterable.

   r が指定されない場合や None の場合、r はデフォルトで iterable の長さとなり、可能な最長の順列の全てが生成されます。


この問題にぴったりの組合せイテレータですね。

最後にを出力するときにちょっと数独ぽくしたいので、すべての条件を満たした答えを出力する関数print_answer() を作成します。これは問題の出力にも使えますね。(docstring は Gemini によります。)

def print_answer(a,b,c,d,e,f,g,h,i):
   """Prints a 9x9 Sudoku puzzle in a formatted manner.
   Args:
      a, b, c, d, e, f, g, h, i: Lists representing the rows of the Sudoku puzzle.
   """

   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]))
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8]))
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8]))
   print('------+-------+-------')
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8]))
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8]))
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8]))
   print('------+-------+-------')
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(g[0],g[1],g[2],g[3],g[4],g[5],g[6],g[7],g[8]))
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(h[0],h[1],h[2],h[3],h[4],h[5],h[6],h[7],h[8]))
   print('{0} {1} {2} | {3} {4} {5} | {6} {7} {8}'.format(i[0],i[1],i[2],i[3],i[4],i[5],i[6],i[7],i[8]))

何故、Gemini の回答である docstring が英文になったのでしょうか?
これは、Gemini が次のようにこの関数の修正案を提示したからです。入門者にとって衝撃の答えでした。

ここから======(空行は省略)
I'd be glad to provide a response that combines the strengths of both Response A and Response B, addressing their potential shortcomings and incorporating insights from the ratings:

**Improved Response:**
```python
def print_answer(a, b, c, d, e, f, g, h, i):
   """Prints a 9x9 Sudoku puzzle in a formatted manner.
   Args:
      a, b, c, d, e, f, g, h, i: Lists representing the rows of the Sudoku puzzle.
   """
   # Define a separator string for better readability
   separator = "------+-------+-------"
   # Print the puzzle rows with appropriate formatting
   for row in [a, b, c, d, e, f, g, h, i]:
      print(" ".join(row))
      print(separator)
   # Print the final row without the separator
   print(" ".join(i))
```
**Explanation:**
- **Clear Function Definition:** The function is defined with a clear name (`print_answer`) and a docstring that explains its purpose and parameters.
- **Concise and Efficient:** The code is concise and efficient, using a loop to iterate over the rows and a list comprehension to join row elements with spaces.
- **Readability:** The use of a separator string improves readability by visually separating the rows and columns.
- **Flexibility:** The code can be easily adapted to print different puzzle sizes by modifying the separator string and the loop iteration.
- **Correctness:** The code accurately prints the Sudoku puzzle in the desired format.
**Key Improvements:**
- **Combined Strengths:** The response incorporates the best aspects of Response A (conciseness, efficiency) and Response B (clear function definition, docstring).
- **Enhanced Readability:** The separator string enhances visual clarity.
- **Flexibility:** The code is adaptable to different puzzle sizes.

I believe this improved response effectively addresses the prompt and provides a valuable solution.
======ここまで


Gemini は、この関数を数独パズルのためと評価して、その出力ならこの関数をと言うわけですね。
Gemini でこの回答を日本語に訳したものも記録しておきます。(空行は省略)

ここから======
**日本語訳:**
```
def print_answer(a, b, c, d, e, f, g, h, i):
   """9x9の数のパズル (数独) をきれいに表示する関数です。
   引数:
      a, b, c, d, e, f, g, h, i: 数独のパズルの各行を表すリストです。
   """
   # 行と行の間の区切り線として使う文字列
   separator = "------+-------+-------"
# パズルの各行をきれいに表示
   for row in [a, b, c, d, e, f, g, h, i]:
      print(" ".join(row)) # リストの要素をスペースで繋いで表示
      print(separator) # 区切り線を表示
   # 最後の行は区切り線を表示せずに表示
   print(" ".join(i))
```
**コードの説明:**
* **関数 `print_answer`:** 数独のパズルをきれいに表示するための関数です。
* **引数:**
   * `a`, `b`, `c`, ... , `i`: 数独のパズルの各行を表すリストです。それぞれのリストの要素は、その行の数字に対応します。
* **`separator`:** 行と行の間の区切り線として使う文字列です。
* **`for` ループ:** パズルの各行 (`a`, `b`, ... , `i`) を順番に処理します。
* **`print(" ".join(row))`:** リスト `row` の要素をスペースで繋いで一つの文字列にし、それを表示します。これにより、一行の数字が綺麗に表示されます。
* **`print(separator)`:** 区切り線を表示します。
* **最後の `print(" ".join(i))`:** 最後の行は区切り線を表示せずに表示します。
**このコードは、与えられた9つのリスト (各リストが数独の一行を表す) を使って、数独のパズルをコンソール上に綺麗に表示します。**
### より詳しい説明
* **数独:** 9×9のマス目に1から9までの数字を重複なく入れるパズルです。各行、各列、および3×3のブロック内に同じ数字が重複してはいけません。
* **リスト:** Pythonで複数の要素を順番に格納するデータ構造です。このコードでは、各リストが数独の一行に対応しています。
* **`join` メソッド:** リストの要素を指定された文字列で繋いで一つの文字列にするメソッドです。このコードでは、スペースで繋いでいます。
**このコードのポイント:**
* **可読性:** 変数名やコメントによって、コードの意味が分かりやすくなっています。
* **効率性:** `for` ループを使って簡潔に記述されています。
* **汎用性:** 数独のサイズを変更したり、区切り線の文字を変更したりするなど、少し変更するだけで他のパズルにも適用できます。

**もし、数独のパズルを解くプログラムを作りたい場合は、このコードをベースに、数字の配置のルールや解法アルゴリズムを実装する必要があります。**
======ここまで


生成AIを利用したプログラミングは、なかなか興味深いですね。
Gemini の回答に驚いて非常に長くなったので、続きは次回に投稿します。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

入門者が生成AIも利用して Python プログラミングを行う。 その2

2024-10-04 20:49:43 | Python
前回の続きで、具体的なプログラミングを行ってみます。

まず、Google Gemini を使って9要素のリストが1~9のすべての数字を含んでいるかどうかを調べる関数check_list()を作ります。

Gemini へのプロンプトは、以下の通りです。

「要素数9のリスト b を引数として、
リストの各要素が重複しないで1から9の値になっているかどうかを調べて、この条件を満たすときは真、満たさない場合は偽を返すような関数 check_list(b)を作成してください。」

Gemini の回答: (抜粋)
## リストの要素が重複なく1から9まで含まれているか判定する関数

def check_list(b):
   """
   リストbの要素が重複なく1から9まで含まれているかを判定する関数
   Args:
      b: 判定対象のリスト
   Returns:
      bool: 条件を満たす場合はTrue、満たさない場合はFalse
   """

   # 要素数が9でない場合、Falseを返す
   if len(b) != 9:
      return False

   # 要素が1から9の範囲に含まれていないか、重複があるかを確認
   return set(b) == set(range(1, 10))

### コード解説

1. **関数定義:**
   * `check_list(b)`: リスト `b` を引数にとる関数。
2. **要素数チェック:**
   * `if len(b) != 9:`: リストの長さが9でない場合、条件を満たさないためFalseを返す。
3. **重複と範囲チェック:**
   * `return set(b) == set(range(1, 10))`:
      * `set(b)`: リスト `b` を集合に変換することで、重複を自動的に除去する。
      * `set(range(1, 10))`: 1から9までの数値の集合を作成する。
      * `==`: 両方の集合が等しいか(要素が完全に一致するか)を比較する。
      * 集合が等しい場合、リスト `b` の要素が重複なく1から9まで含まれていることを意味するため、Trueを返す。

### 動作原理

* **集合の利用:** 集合は重複した要素を持たないため、リストを集合に変換することで、要素の重複を簡単に検出できる。
* **範囲の比較:** `range(1, 10)` で生成した集合と、リスト `b` から作成した集合を比較することで、要素が1から9までの範囲に含まれているか、かつ重複がないかを同時に確認できる。

=====ここまで


docstring 付きですね。数字が順番に並んでいないので、set()を使ってリストを集合に替えて判定するのですね。
解説も分かりやすく、そのまま利用できます。

次に、「数独」の9個のブロックが1から9の数値を重複無く含んでいるかを調べるために、
3行毎に3回に分けて調べるようにします。一つでも False になると直ぐに終了して次に行くのと、長くなりそうなのでこうしてみました。

そのために、3つの行を引数にして条件を調べる chk_block(a,b,c) という関数を作ってみます。
これは、生成AIを使わないで、単純に次のようにしました。
(Gemini は、docstring作成にのみ使いました。Raises:とExamples:は省略)

def chk_block(a,b,c):
   """
   3つのリストを9要素ずつに分割し、各ブロックに対して `check_list` 関数を適用します。
   全てのブロックで `check_list` が `True` を返す場合にのみ、`True` を返します。
   Args:
      a (list): 要素数9のリスト
      b (list): 要素数9のリスト
      c (list): 要素数9のリスト
   Returns:
      bool: 全てのブロックが `check_list` の条件を満たす場合にTrue、そうでない場合にFalse
   """


   block1 = a[0:3] + b[0:3] + c[0:3]
   block2 = a[3:6] + b[3:6] + c[3:6]
   block3 = a[6:] + b[6:] + c[6:]

   if check_list(block1) == False:
      return False
   if check_list(block2) == False:
      return False
   if check_list(block3) == False:
      return False
   return True

この2つの関数をテストします。
ファイル prog-01.py で、2つの関数を定義して、その下に以下のテストプログラムを挿入して実行します。

row1 = [1, 2, 3, 4, 5, 6, 7, 8, 9 ]
row2 = [4, 5, 6, 7, 8, 9, 1, 2, 3 ]
row3 = [7, 8, 9, 1, 2, 3, 4, 5, 6 ]

if chk_block(row1, row2, row3):
print("OK")
else:
print("NG")

row1 = [1, 2, 3, 4, 5, 6, 7, 8, 9 ]
row2 = [4, 5, 6, 7, 8, 9, 1, 7, 3 ]
row3 = [7, 8, 9, 1, 2, 3, 4, 5, 6 ]

if chk_block(row1, row2, row3):
print("OK")
else:
print("NG")

row1 = [1, 2, 3, 4, 5, 6, 7, 8, 9 ]
row2 = [4, 5, 6, 7, 2, 9, 1, 2, 3 ]
row3 = [7, 8, 9, 1, 2, 3, 4, 5, 6 ]

if chk_block(row1, row2, row3):
print("OK")
else:
print("NG")

row1 = [1, 2, 3, 4, 5, 6, 7, 8, 9 ]
row2 = [4, 5, 6, 7, 8, 9, 1, 2, 3 ]
row3 = [7, 8, 1, 1, 2, 3, 4, 5, 6 ]

if chk_block(row1, row2, row3):
print("OK")
else:
print("NG")

$ python3 prog01.py
OK
NG
NG
NG
$

テストで問題ないことが分かりました。
長くなりましたので、続きはまた後で投稿します。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする