2022/09,江端さんの忘備録

先日、証明写真機(スピード写真)で、写真を取ってきました。

The other day, I took a photo from a photo machine (speed photo).

人生で初めて、『メガネ(老眼鏡)』をかけて写真撮影をしました。

For the first time in my life, I wore "glasses (reading glasses)" to take pictures.

―― メガネをつけると、目付きの悪さが緩和される

"Wearing glasses eases my unpleasant look"

という、事実を発見したからです。

I noticed that.

以前、パスポート更新用にとった写真を見て、ぞっとしました。

I was horrified when I saw the photo for my passport renewal.

もし、私が事故や事件に巻き込まれた時、この写真がニュースに出たら、ニュースの内容を確認されないまま、「加害者」「犯人」であると決めつけられる、と思いました。

I thought that if I were involved in an accident or incident and this photo appeared on the news, I would be assumed to be the "perpetrator" or "culprit" without having the news story confirmed.

-----

「国葬」の日、私は、終日、自宅に閉じ籠って仕事していました。

On the day of the "State Funeral," I spent the entire day confined to my home and worked.

―― 私、結構な頻度で、『職務質問』されるんですけど、良い対策方法ってありますか?

2022/09,江端さんの忘備録

先日、

The other day, I was asked from my reader,

『江端さんの記事って有料になったのですか』

"Did you start charging for your articles?"

との質問を受けて、ビックリしました。

and I was really surprised.

そういえば、スマホは、EE Times Japanへのユーザ登録が、ワンアクション入るようになっていたなぁ、と思い出しました。

I remembered that for smartphone, user registration to EE Times Japan has been needed as one-action process.

パソコンのブラウザでは、このようなアクションは不要なようです。

However, you don't need to register from the web browser of PC

いずれにしても、江端の記事は今も無料で読めるようです ―― というか、私は、この件に関してコントロールできません。

Anyway, reading my columns are free of charge even now. I mean, I have no control over this.

あしからずご了承下さい。

I apologize for any inconvenience.

-----

最近、この手のユーザ登録の要請が多くなったような気がします。

I think that there are more requests for this type of user registration recently.

私も、こういうのが、どうにも苦手で、「登録」よりも「購読断念」を選んでしまいます。

I am not good at the actions like this either. so I happen to sto

これは、日経XXのポータルサイトに多いのですが、この登録後に必要となるアンケートシートに「うんざり」するからです。

This cases are apt to happen on Nikkei-XXX site. This is because I am "fed up" with the survey sheets that are required after this registration.

年収とか、家族構成とか、職位とか、既婚や未婚など ―― これらのプライバシーを書かされる『不快』さを、日経XXのサイト運営者は理解すべきです。

The Nikkei XX website operators should understand the "discomfort" of being asked to write these privacy details -- income, family structure, job title, marital status, unmarried status, etc.

原則、私は10項目以上あるアンケートには、答えないことにしています。面倒くさいからです。

As a general rule, I do not answer surveys that have more than 10 items. It is because it is too much trouble.

-----

先日、筋トレを目的としたスポーツジムの見学に行ってきたのですが、その前に記載されるアンケート用紙(両面ビッシリと、細かい文字で記載されている)を見た瞬間、

The other day, I went to visit a gym for muscle training, and the moment I saw the questionnaire form (double-sided, with super small characters) that I had to fill out before the visit, I said

『あ、もういいです』

"Sorry, I give up"

とだけ行って、そのまま立ち去りました。

and left the gym.

私は、ジムの設備を見学したかっただけなので、このアンケートに応えるコストに見合わない、と判断しました。

I decided that it was not worth the cost of responding to this survey, as I only wanted to tour the gym facilities.

-----

で、多分、多くの施設やポータルサイトは、ユーザの『不快』や『面倒』で、私のような潜在顧客を見逃しているハズです。

And maybe many facilities and portals are missing out on potential customers like me because of the 'discomfort' and 'hassle' of users.

それに気がついていないなら「バカだなぁ」と思うし、

If they don't realize that, I think that they are "stupid."

それに気がついているなら、「救い難いバカだなぁ」と思います。

If they realize that, I think that they are "unhelpful stupid."

2022/09,江端さんの技術メモ

以前、pgr_dijkstra()で、ダイクストラの順番が壊れる という内容で悩んでいて、最終的に、

utsu_tram_db3=# SELECT seq, source, edge, x1, y1 FROM pgr_dijkstra('SELECT gid as id, source, target, cost, reverse_cost FROM ways', 2, 59, directed:=false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;

で、順列を壊さないで、ダイクストラの表示ができる、ということを書きました。

pgr_dijkstra()で算出したノードの座標を得る方法

ところが、まだ、これでも問題が発生することが分かりました。

ノード1799からノード3342のルート計算を以下のようにやってみました。

kitaya_db=# SELECT seq, source, target, x1, y1,x2,y2, agg_cost FROM pgr_dijkstra('SELECT gid as id, source, target, length_m as cost cost, reverse_cost FROM ways', 3342, 1799, directed:=false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;

まあ、こんな感じで、sourceとx1,x2を追っていって、ラストのtargetとx2,y2を拾えば、いいと分かりましたので、これで大丈夫だろう、と思ってコーディングしていました。

ところが、このノード1799からノード3342を逆転させて、ノード3342からノード1799のルート計算を以下のようにやってみました。

kitaya_db=# SELECT seq, source, target, x1, y1,x2,y2, agg_cost FROM pgr_dijkstra('SELECT gid as id, source, target, length_m as cost  cost, reverse_cost FROM ways', 1799, 3342, directed:=false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;

と、こんな感じで、sourceが出発点にならずに、targetの方が正しい並びとなってしまっています。つまり、こんな感じ。

で、これがどっちで出てくるのか分からないので、以下のようにしました。

(1)最初のノードがsourceに出てきたら、sourceベースで読み出し、
(2)最初のノードがtargetに出てきたら、targetベースで読み出す

実装はこんな感じにしました。

type LocInfo struct {
	Lon    float64
	Lat    float64
	Source int
}

 

// 江端修正版
func getDijkstraPath(dbMap *sql.DB, locInfoStart, locInfoGoal ldarp.LocInfo) ([]ldarp.LocInfo, float64) {
	log.Println("getDijkstraPath", locInfoStart, locInfoGoal)

	var path []ldarp.LocInfo // 経路 (返り値の一つ目)
	var totalDistanceKm float64

	rowsDijkstra, errDijkstra := dbMap.Query(
		"SELECT seq,source, target, x1, y1, x2, y2, agg_cost FROM pgr_dijkstra('SELECT gid as id, source, target, length_m as cost FROM ways', $1::bigint , $2::bigint , directed:=false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq",
		locInfoStart.Source,
		locInfoGoal.Source)

	if errDijkstra != nil {
		log.Fatal(errDijkstra)
	}
	defer rowsDijkstra.Close()

	var agg_cost float64

	isFirstCheck := true
	isSourceCheck := true

	for rowsDijkstra.Next() {

		var x1, y1, x2, y2 float64

		var seq int
		var target int

		// まずnodeを読む
		if err := rowsDijkstra.Scan(&seq, &source, &target, &x1, &y1, &x2, &y2, &agg_cost); err != nil {
			fmt.Println(err)
		}

		// 最初の1回だけ入る
		if isFirstCheck {
			if source == locInfoStart.Source {
				isSourceCheck = true
			} else {
				isSourceCheck = false
			}
			isFirstCheck = false
		}

		var loc ldarp.LocInfo

		if isSourceCheck {
			loc.Source = source
			loc.Lon = x1
			loc.Lat = y1
		} else {
			loc.Source = target
			loc.Lon = x2
			loc.Lat = y2
		}

		loc.Source = target

		path = append(path, loc)
	}

	// ラストノードだけは手入力
	path = append(path, locInfoGoal)

	totalDistanceKm = agg_cost / 1000.0
	return path, totalDistanceKm
}

もっとクールな方法があるかもしれませんが、面倒なので、戦うのはやめました。

バグを発見したので、main()を含めた再修正版をアップしておきまます。

package main

import (
	"database/sql"
	"fmt"
	"log"
	"m/src/ldarp"

	_ "github.com/lib/pq"
)

func main() {
	db, err := sql.Open("postgres",
		"user=postgres password=password host=192.168.0.23 port=15432 dbname=tomioka_db_c sslmode=disable")
	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer db.Close()

	var a_Point, b_Point ldarp.LocInfo
	a_Point.Source = 20
	b_Point.Source = 1
	path, dist := getDijkstraPath(db, a_Point, b_Point)

	fmt.Println("path:", path)
	fmt.Println("dist:", dist)

}

// 江端再修正版
func getDijkstraPath(dbMap *sql.DB, locInfoStart, locInfoGoal ldarp.LocInfo) ([]ldarp.LocInfo, float64) {
	log.Println("getDijkstraPath", locInfoStart, locInfoGoal)

	var path []ldarp.LocInfo // 経路 (返り値の一つ目)
	var totalDistanceKm float64

	rowsDijkstra, errDijkstra := dbMap.Query(
		"SELECT seq,source, target, x1, y1, x2, y2, agg_cost FROM pgr_dijkstra('SELECT gid as id, source, target, length_m as cost cost, reverse_cost FROM ways', $1::bigint , $2::bigint , directed:=false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq",
		locInfoStart.Source,
		locInfoGoal.Source)

	if errDijkstra != nil {
		log.Fatal(errDijkstra)
	}
	defer rowsDijkstra.Close()

	var agg_cost float64

	var loc ldarp.LocInfo
	var x1, y1, x2, y2 float64
	var seq int
	var target int
	var source int

	isFirstCheck := true
	isSourceCheck := true

	for rowsDijkstra.Next() {

		// まずnodeを読む
		if err := rowsDijkstra.Scan(&seq, &source, &target, &x1, &y1, &x2, &y2, &agg_cost); err != nil {
			fmt.Println(err)
		}

		// 最初の1回だけチェックのために入る これについては、https://wp.kobore.net/江端さんの技術メモ/post-7668/を参照のこと
		// もし rowsDijkstra.Scanで最初のsource値を読みとり、locInfoStart.Source の値と同じであれば、x1,y1をベースとして、異なる値であれば、x2,y2をベースとする

		if isFirstCheck {
			if source == locInfoStart.Source {
				isSourceCheck = true // x1, y1をベースとする処理になる
			} else {
				isSourceCheck = false // x2,y2をベースとする処理になる
			}
			isFirstCheck = false // 最初の1回をチェックすることで、2回目はこのループには入らなくなる
		}

		//var loc ldarp.LocInfo

		if isSourceCheck { // x1, y1をベースとする処理
			loc.Source = source
			loc.Lon = x1
			loc.Lat = y1
		} else { // x2,y2をベースとする処理
			loc.Source = target
			loc.Lon = x2
			loc.Lat = y2
		}
		path = append(path, loc)
	}

	// ラストノードだけは手入力 (ここは引っくり返す)
	if isSourceCheck { // x1, y1をベースとする処理
		loc.Source = target
		loc.Lon = x2
		loc.Lat = y2
	} else { // x2,y2をベースとする処理
		loc.Source = source
		loc.Lon = x1
		loc.Lat = y1
	}

	path = append(path, loc)

	totalDistanceKm = agg_cost / 1000.0
	return path, totalDistanceKm
}

で、色々問題が出てきたので、各種ケースに対応できるように追加したもの

/*
	c:\users\ebata\tomioka3b\src\others\main49.go

	このプログラムは、PostgreSQLデータベース内の地理情報を使用して最短経路を計算するためのものです。
	
	このプログラムは、以下の機能を持ちます。

	(1)main 関数内で、PostgreSQLデータベースへの接続情報を設定し、sql.Open を使用してデータベースに接続します。
	(2)getDijkstraPath 関数は、指定された始点から終点までの最短経路を計算するための関数です。この関数は、Dijkstraアルゴリズムを使用して最短経路を計算します。
	(3)LocInfo 構造体は、地理座標とノードの情報を表現します。
	(4)main 関数内で getDijkstraPath 関数を呼び出し、最短経路とその距離を計算します。異常ノードや隣接ノード、同一ノード、2つ離れたノードなど、さまざまなケースでの最短経路をテストするために、複数の呼び出しをコメントアウトしています。
	(5)getDijkstraPath 関数内では、まず指定された始点と終点に対応する地理座標を取得します。始点と終点が同一の場合は、指定されたノードの地理座標を取得します。
	(6)次に、pgr_dijkstra 関数を使用して最短経路を計算し、結果を取得します。結果は、各ノードの地理座標と距離が含まれる配列として返されます。
	(7)最後に、最短経路の全体距離を計算し、その結果を返します。


*/

package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "github.com/lib/pq"
)

type LocInfo struct {
	Lon    float64
	Lat    float64
	Source int
}

func main() {
	// PostgreSQLへの接続情報

	// Agent_od書き込み用テーブルの初期化
	db_agent_od, err := sql.Open("postgres",
		"user=postgres password=password host=192.168.0.23 port=15432 dbname=tomioka_db_e sslmode=disable") // トミオカート地図でテスト

	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer db_agent_od.Close()

	route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 432}, LocInfo{Source: 1070}) // 異常ノード
	//route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 856}, LocInfo{Source: 688}) // 異常ノード

	//route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 723}, LocInfo{Source: 853}) // 隣接ノード
	//route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 536}, LocInfo{Source: 171}) // 隣接ノード

	//route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 536}, LocInfo{Source: 536}) // 同一ノード
	//route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 138}, LocInfo{Source: 139}) // 同一ノード
	//route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 173}, LocInfo{Source: 853}) // 2つ離れたノード
	fmt.Println("route", route, "dis", dis)

}

// テスト中
// 1行のみの場合、ヌルになるという問題と、同一ノードに対応するため
func getDijkstraPath(dbMap *sql.DB, locInfoStart, locInfoGoal LocInfo) ([]LocInfo, float64) {

	var path []LocInfo // 経路 (返り値の一つ目)
	var totalDistanceKm float64

	// 例外処理 locInfoStart.source == locInfoGoal.source の場合
	if locInfoStart.Source == locInfoGoal.Source {
		source := locInfoStart.Source

		// SQLクエリの作成
		query := fmt.Sprintf(`
		SELECT x1, y1
		FROM ways
		WHERE source = %d;
	`, source)

		// SQLクエリの実行
		var x1, y1 float64
		err := dbMap.QueryRow(query).Scan(&x1, &y1)
		if err != nil {
			log.Fatal(err)
		}

		var loc LocInfo
		loc.Source = source
		loc.Lon = x1
		loc.Lat = y1

		path = append(path, loc)

		totalDistanceKm = 0.0
		return path, totalDistanceKm
	}

	query := `
	SELECT seq, source, target, x1, y1, x2, y2, agg_cost 
	FROM pgr_dijkstra(
		'SELECT gid as id, source, target, length_m as cost FROM ways', 
		$1::bigint, 
		$2::bigint, 
		directed:=false
	) a 
	INNER JOIN ways b ON (a.edge = b.gid) 
	ORDER BY seq
	`
	//log.Println("getDijkstraPath", locInfoStart.Source, locInfoGoal.Source)

	rowsDijkstra, errDijkstra := dbMap.Query(query, locInfoStart.Source, locInfoGoal.Source)
	if errDijkstra != nil {
		log.Fatal(errDijkstra)
		os.Exit(1)
	}
	defer rowsDijkstra.Close()

	var agg_cost float64

	var loc LocInfo
	var x1, y1, x2, y2 float64
	var seq int
	var target int
	var source int

	isFirstCheck := true
	isSourceCheck := true

	count := 0

	for rowsDijkstra.Next() {
		// まずnodeを読む
		if err := rowsDijkstra.Scan(&seq, &source, &target, &x1, &y1, &x2, &y2, &agg_cost); err != nil {
			fmt.Println(err)
		}

		// 最初の1回だけチェックのために入る これについては、https://wp.kobore.net/江端さんの技術メモ/post-7668/を参照のこと
		// もし rowsDijkstra.Scanで最初のsource値を読みとり、locInfoStart.Source の値と同じであれば、x1,y1をベースとして、異なる値であれば、x2,y2をベースとする

		if isFirstCheck {
			if source == locInfoStart.Source {
				isSourceCheck = true // x1, y1をベースとする処理になる
			} else {
				isSourceCheck = false // x2,y2をベースとする処理になる
			}
			isFirstCheck = false // 最初の1回をチェックすることで、2回目はこのループには入らなくなる
		}

		//var loc LocInfo

		if isSourceCheck { // x1, y1をベースとする処理
			loc.Source = source
			loc.Lon = x1
			loc.Lat = y1
		} else { // x2,y2をベースとする処理
			loc.Source = target
			loc.Lon = x2
			loc.Lat = y2
		}
		path = append(path, loc)

		count++
	}

	// ラストノードだけは手入力 (ここは引っくり返す)
	if isSourceCheck { // x1, y1をベースとする処理
		loc.Source = target
		loc.Lon = x2
		loc.Lat = y2
	} else { // x2,y2をベースとする処理
		loc.Source = source
		loc.Lon = x1
		loc.Lat = y1
	}

	fmt.Println("count", count)

	if count == 0 { // 1行のみの場合、ヌルになるという問題に対応するため、
		loc.Source = locInfoGoal.Source
		loc.Lon = locInfoGoal.Lon
		loc.Lat = locInfoGoal.Lat

		// 入力値の指定
		source := locInfoStart.Source
		target := locInfoGoal.Source

		// SQLクエリの作成
		query := fmt.Sprintf(`
		SELECT length_m, x1, y1, x2, y2
		FROM ways
		WHERE source = %d AND target = %d;
	`, source, target)

		// SQLクエリの実行
		var length float64
		var x1, y1, x2, y2 float64
		err := dbMap.QueryRow(query).Scan(&length, &x1, &y1, &x2, &y2)
		if err != nil {
			log.Println("First attempt failed. Retrying with swapped source and target.")
			// 入れ替えたsourceとtargetの値でクエリを再実行
			query = fmt.Sprintf(`
			SELECT length_m, x1, y1, x2, y2
			FROM ways
			WHERE source = %d AND target = %d;
		`, target, source)
			err = dbMap.QueryRow(query).Scan(&length, &x1, &y1, &x2, &y2)
			if err != nil {
				log.Fatal(err)
			}
		}

		// 結果の出力
		fmt.Printf("length_m: %f\n", length)
		fmt.Printf("source: %d\n", source)
		fmt.Printf("target: %d\n", target)
		fmt.Printf("x1: %f\n", x1)
		fmt.Printf("y1: %f\n", y1)
		fmt.Printf("x2: %f\n", x2)
		fmt.Printf("y2: %f\n", y2)

		if source == locInfoGoal.Source {
			loc.Lon = x1
			loc.Lat = y1
		} else {
			loc.Lon = x2
			loc.Lat = y2
		}

		agg_cost = length

		fmt.Println("loc", loc)
	}

	path = append(path, loc)

	totalDistanceKm = agg_cost / 1000.0
	return path, totalDistanceKm
}

 

2022/09,江端さんの忘備録

社内のチームメンバに、この資料を使って、エージェントシミュレーションの概要を説明していました。

I used this document to provide an overview of the agent simulation to our internal team members.

メンバA:「ところで、このイラストは、江端さんが描いているのですか?」

Member A: "By the way, are these illustrations by Ebata-san?"

江端:「私が"作って"います。特許発明と同じです。『構成要件1と構成要件2と構成要件3からなることを特徴とする本イラスト』です」

Ebata: "I "make" them. It is the same as a patented invention. It is "this illustration characterized by the composition 1, composition 2, and composition 3.

メンバA:「・・・分かりました」

Member A: "... I understand."

-----

メンバB:「コンセプトは、"SG"ですね?」

Member B: "The concept is "SG," right?"

江端:「もちろん、"SG"です。"SG"以外は、ありえません」

Ebata: "Of course, "SG". Nothing but "SG" is possible."

メンバC:「あの、江端さん。"SG"って何ですか?」

Member C: "Um, Ebata-san. May I ask you about "SG?""

江端:「"SG"とは、当然、"シュタインズ・ゲート"のことです・・・え、ご存知ない?本当に??」

Ebata: "'SG' is, of course, 'Steins;Gate'... Oh, you don't know? Really?

-----

―― 弊社のエンジニアが、シュタインズ・ゲートを知らないというのは、由々しき事態だ

"It is a serious matter that our engineers do not know Steins;Gate""

―― シュタインズ・ゲートは、他の人はさておき、エンジニアと研究員の必修科目だ

"Stein's Gate, aside from others, is a required course for engineers and researchers"

―― シュタインズ・ゲートを見ずして、未来の街を設計する仕事をするなど、信じられないことだ

"It would be incredible to work designing the city of the future without seeing Steins;Gate"

―― 当然、『ゼロ』まで完遂しなければならない

"Of course, we must complete to 'Zero'"

と、長々と、まくしたててしまいました。

I've made them a mess for a long time.

-----

チームメンバには、『ドン引き』されていたようですが ―― 構いません。

The team members were put off by what he said, however I don't care of it.

2022/09,江端さんの忘備録

To 日本国総理大臣殿

To Mr. Prime Minister of Japan

私、新人の時に、先輩から

When I was a rookie, I was told by a senior, and scoled

「江端! 『丁寧な説明』っていうのは、『同じ内容を、ゆっくりとしゃべり直すこと』じゃねえぞ!!」

"Ebata! "Careful explanation" does not mean "to talk about the same thing over again slowly!"

と、叱られたことがあります。

御参考まで。

For your information.

2022/09,江端さんの忘備録

私が入社したころは、コンピュータのリソース不足が慢性的な悩みでした。

When I joined the company, the lack of computer resources was a chronic problem.

3桁の2次元配列を作るだけで、プログラムが実行できなくなり、メモリの効率的な利用が、最大の課題でした。

Efficient use of memory was the biggest challenge, as creating a three-digit two-dimensional array alone would not allow the program to run.

職場で、ワークステーションの奪い合いなどもやっていました。

At work, I was fighting for workstations.

しかし、PCが潤沢なリソースを持つようになり、このような問題に直面することはなくなりました。

However, PCs no longer face this problem as they now have ample resources.

並行処理に強いプログラム言語(Go言語等)の登場により、100万オーダのオブジェクトも普通に扱えるようになりました。

With the advent of programming languages (such as Go) that are strong in concurrency processing, objects of the order of one million can now be handled as usual.

ですが、無茶したら駄目ですね。

However, I should not be reckless.

"pq: sorry, too many clients already"

pq: sorry, too many clients already

このようなデータベースの悲鳴に対して、各種の対応を試してきたのですが、リソースマネージャーをみたら、ディスク(書き込み)使用率99%越え、という状況が発生していました。

I have tried various responses to the database screams, but when I checked the resource manager, I found that the disk (write) usage was over 99%.

まあ、dockerの中に作ったDBに、1秒間に30回も100人分のエージェント情報の書き込みをやったら、そりゃ、データベースも悲鳴を上げるだろうなぁ、と、思いました。

Well, I thought, writing 100 agents' information 30 times per second to a database created in docker, the database would scream.

ここ十何年も、リソース不足問題と無縁で生きてきましたので、自分の無茶に気がつなかったようです。

I have been living without resource shortage problems for more than a decade, so I guess I did not realize how reckless I was.

-----

そういえば、嫁さんと会話していた時、

I was having a conversation with my wife.

江端:「データベースがダウンしちゃって・・・」

Ebata: "My database went down..."

嫁さん:「え! それ大変じゃん!! 大丈夫なの?」

Wife: "What! That's an accident! Are you okay?"

と、『何言ってんの?』という感じで、お互いに首をかしげることになりました。

We were both nodding our heads like 'What are you talking about?'

一般の人が「データベース」という言葉から一般の人が連想するのは、行政管理システムとか、電力配送システムとか、アマゾンなどのようなEコマースシステムでしょう。

What the general public associates with the word "database" would be an administrative management system, an electricity delivery system, or an e-commerce system such as Amazon.

その手のデータベースがダウンしたら、社会生活に甚大な影響が出ます。

If that type of database were to go down, it would have an enormous impact on social life.

嫁さんの中では、『私が自分のプログラムの為だけにローカルに作った実験用の小規模データベース』は、データベースに含まれていないようです ――

In my wife's mind, 'a small experimental database that I created locally just for my own programs' is not included in the database.

それが、一般人の感覚である、というのは、私にも分かります。

I think that is the feeling of ordinal persons.

2022/09,江端さんの忘備録

コラムの執筆に時間がかかるのは当然なのですが、最近、最近はイラスト作成にも時間がかかっています。

It is natrual that I pay for time to write my column, however, I have to waste time to make a illustration.

漫画を見ながら、「これ、どうやったら書けるんだろう?」と思いながら、自分なりに、その絵をマネる方法を試行錯誤しています。

Watching manga-books, I woder "how can I draw this", and I try to figure out how to imitate the drawing in my own way,

神の啓示を描いてみた件

毎度同じことを言っていますが、

I say same things again,

―― 絵を描く能力がある人って、やっぱり凄い

"People who have the ability to draw are still great"

と、本当に尊敬してしまいます。

The drawing make me respect them.

2022/09,江端さんの技術メモ

パワポで、バックグランド黒、白い線を複数コピペを繰り返す

SAIで、エラブラシで発光を付ける

線をぼかして、完成

2022/09,江端さんの技術メモ

信者獲得&洗脳シミュレーションプログラム

package main

import (
	"fmt"
	"math/rand"
)

type person struct {
	number             int     // 番号
	mental_strength    float64 // 勧誘に屈しない強さ
	religious_devotion float64 // 信仰力
	church             int     //教会フラグ
}

var p_array []*person // personの配列2
var (
	p_num = 0
)

func person_create() *person {
	p := new(person)
	p.number = p_num
	p_num++                            // 生成された順番に番号を付けていく
	p.mental_strength = rand.Float64() // 勧誘を断わる強さ
	p.religious_devotion = 0           // 信仰力最初は"0"
	p.church = 0                       // 教会フラグ
	p_array = append(p_array, p)       // 配列に放り込む

	return p
}

func (p *person) person_destroy() {
	for index, v := range p_array {
		if v == p {
			p_array = append(p_array[:index], p_array[index+1:]...)
			break
		}
	}
	p = nil //これでいいのかな? ガーベージコレクションが消してくれる、と聞いているが
}

type agent struct {
	number           int     // 番号
	invitation_power float64 // 勧誘力
}

var a_array []*agent // agentの配列
var (
	a_num = 0
)

func agent_create() *agent {
	a := new(agent)
	a.number = a_num
	a_num++                                       // 生成された順番に番号を付けていく
	a.invitation_power = 0.3 + 0.7*rand.Float64() // 勧誘力
	a_array = append(a_array, a)                  // 配列に放り込む
	return a
}

func (a *agent) agent_destroy() {
	for index, v := range a_array {
		if v == a {
			a_array = append(a_array[:index], a_array[index+1:]...)
			break
		}
	}
	a = nil //これでいいのかな? ガーベージコレクションが消してくれる、と聞いているが
}

func (p *person) meet_agent(a *agent) {
	if p.mental_strength < a.invitation_power {
		p.religious_devotion += a.invitation_power * 0.1 // エージェントの説得によって信仰心が微増
		p.mental_strength -= a.invitation_power * 0.1    // エージェントの説得によって心理障壁が微減
		if p.religious_devotion > 1.0 {
			p.religious_devotion = 1.0
		}
		if p.mental_strength < 0.0 {
			p.mental_strength = 0.0
		}

	}

}

func main() {
	for i := 0; i < 1000; i++ {
		person_create()
	}

	fmt.Println("======p_array=========")

	for _, p := range p_array {
		fmt.Println(p.number, ",", p.mental_strength, ",", p.religious_devotion)
	}

	for i := 0; i < 5; i++ {
		agent_create()
	}

	fmt.Println("======a_array=========")

	for _, a := range a_array {
		fmt.Println(a.number, ",", a.invitation_power)
	}

	for i := 0; i < 365; i++ { // 1年間の勧誘
		for _, p := range p_array {
			//fmt.Println(index, ":", v, v.number, v.mental_strength)
			for _, a := range a_array {
				if rand.Float64() < 0.001 {
					p.meet_agent(a)
				}
			}
		}
	}

	fmt.Println("=====p_array after 365days==========")

	for _, p := range p_array {
		fmt.Println(p.number, ",", p.mental_strength, ",", p.religious_devotion)
	}

	fmt.Println("====count2===========")
	count := 0
	for _, p := range p_array {
		if p.religious_devotion > 0.2 {
			p.church = 1 //教会フラグを"1"に変項
			count++
			fmt.Println(p.religious_devotion)
		}
	}
	fmt.Println(count)

	for i := 0; i < 365; i++ { // 2年目の勧誘
		for _, p := range p_array {
			//fmt.Println(index, ":", v, v.number, v.mental_strength)
			for _, a := range a_array {
				if p.church == 1 && rand.Float64() < 0.005 {
					p.meet_agent(a)
				}
			}
		}
	}

	fmt.Println("=====p_array after 365days x 2==========")

	for _, p := range p_array {
		if p.church == 1 {
			fmt.Println(p.number, ",", p.mental_strength, ",", p.religious_devotion)
		}
	}

}

出力結果(エクセルファイル)  → cult.xlsx

2022/09,江端さんの忘備録

現在のロシア(の大統領)が何を考えているか分からない ―― という人がいますが、

I don't understand what the current Russian (president) is thinking -- some people say that, however I want to ask them,

『本当に分からない?』

"You really don't understand?""

と尋ねたいです。

私には、ロシアの考え方が、手に取るように分かります。

To me, the Russian mindset is palpable.

そのユースケースは、1930~1945年あたりの我が国、日本です。

The use case is our country, Japan, around 1930-1945.

-----

■ウクライナ南部の傀儡の新ロ政権の樹立 ---> 中国東北部に暴走した軍部によって作られた大日本帝国の傀儡国家

- Establishment of puppet neo-Russian government in southern Ukraine ---> Puppet state of Empire of Japan (Manchukuo) created by runaway military in northeastern China

■国際連合参加各国からの「ロシアの力による国境変項」への非難決議 ---> 国際連盟の各国からの「日本の力による傀儡国家の樹立」への非難決議(*)

- Resolution of Condemnation of "Border Transformation by the Power of Russia" from the Countries of the United Nations ---> Resolution of Condemnation of "Establishment of a Puppet State by the Power of Japan" from the Countries of the League of Nations (*)

(*)しかも、日本は国際連盟の常任理事国の立場を捨てて(もったいない)、連盟脱退する

(*) Moreover, Japan is leaving the League of Nations, abandoning its position as a permanent member of the League of Nations (what a waste).

■ロシアと中国とイランとの経済連携 ---> ドイツとイタリアと日本の日独伊三国同盟

- Economic partnership between Russia, China, and Iran ---> Tripartite Pact between Germany, Italy, and Japan

■国の領土保全又は政治的独立に対する武力による威嚇又は武力の行使を禁止の禁止(国連憲章第2条4項)の違反 ---> 日ソ不可侵条約の一方的破棄

- Violation of the prohibition against the threat or use of force against the territorial integrity or political independence of a country (Article 2, Paragraph 4 of the UN Charter) ---> Unilateral abrogation of the Soviet-Japanese Nonaggression Pact

ロシアは今回の先導を「自国の自衛権の為」である、と言っていましたが、当時の日本も、満州国建国、南方進出(侵略)も、「我が国の自衛権の為」である、と主張していました。

Russia said that it was taking the lead this time "for its own self-defense," but Japan at that time also claimed that it was "for our self-defense" in establishing Manchukuo and expanding southward (invasion).

ちなみに、当時の日本国民の圧倒的多数が、この「我が国の自衛権」を圧倒的に支持していました。

Incidentally, the overwhelming majority of the Japanese people at that time overwhelmingly supported this "right of self-defense of our country.

私には、今のロシアと、当時の日本、さしたる違いはないように思えます。

To me, there does not seem to be much difference between Russia today and Japan back then.

-----

ちなみに、二国間であれ、多国間であれ、条約は、一方的に、破ることができます。

Incidentally, treaties, whether bilateral or multilateral, can be broken unilaterally.

しかも、ペナルティもありません。実効性のある罰則を実施できる主体がないからです。

Moreover, there is no penalty. This is because there is no entity that can enforce effective penalties.

嫁さん:「じゃあ、何のために条約があるの?」

Wife: "So what's the treaty for?"

江端:「"気休め"くらいかな。もちろん、条約を破った国は国際的信用を失うし、関税を上げるとかの報復手段も取りえるけど、それだけのことだ」

Ebata: "I would say it's only a 'comforting' measure. Of course, countries that break treaties lose international credibility, and they can retaliate by raising tariffs or other measures, but that's about it.

-----

もちろん、ロシアのウクライナ侵攻(侵略)擁護する必要は1mm足りともありません。

Of course, there is no need to defend Russia's invasion of Ukraine, not even a millimeter.

我が国(日本)は、西側諸国の一員として、ロシア非難が心情的な正義であり、かつ、国家としての利益でもあります。

As a member of the Western world, our country (Japan) feels that condemnation of Russia is both an emotional justice and a national interest.

しかし、だからといって、『ロシアの"行動原理"が全く理解できない』と公言する人を、私は理解できません。

But that doesn't mean I don't understand those who profess that they don't understand Russia's "behavioral principles" at all.

近代世界史(の"帝国主義")を、通り一遍り勉強すれば、こんなことは明らかなことです。

A cursory study of modern world history ("imperialism") will make this obvious.

-----

歴史が示すことは、

History has shown us that

―― 自国の安全保障の為であれは、他国の利益など躊躇なく踏み躙る

"For the sake of its own security, any nation will not hesitate to overstep the interests of other nations"

であり、私が知る限り、その例外は一つもない、ということです。

and that, as far as I know, there is not a single exception to that rule.