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
}

 

2024,江端さんの技術メモ

ロングランで、pgr_dijkstra()の挙動の振舞が変であることを発見したので、ChatGPTに相談してみました
User
You
直結する2つのノードの場合、最短距離は当然一意に決定します。postGISのpgr_dijkstra()は、この直結する2つのノードを指定すると、値を返さないようですが、これは正しい仕様でしょうか
ChatGPT
ChatGPT

直結する2つのノードの場合、最短経路は確かに一意に決定します。そのため、pgRoutingのpgr_dijkstra()関数が直結する2つのノード間で値を返さない場合、これは通常は仕様としては誤っています。

pgRoutingのpgr_dijkstra()関数は、通常、始点と終点が異なるノード間の最短経路を見つけるために使用されます。この場合、始点と終点が同じノードである直結する2つのノード間の最短経路を求める必要はないため、関数が値を返さない可能性があります。

しかしながら、直結する2つのノード間の最短経路を求める必要がある場合、通常はpgr_dijkstra()ではなく、pgr_dijkstraCost()やpgr_dijkstraVia()などの関数が使用されます。これらの関数は、エッジ間のコスト(重み)を考慮して最短経路を見つけるため、直結する2つのノード間の最短経路を正しく返すことが期待されます。

したがって、直結する2つのノード間の最短経路を求める場合、適切な関数を使用し、正しい結果が得られるようにすることが重要です。

 

pgr_dijkstra()で、ダイクストラの順番を壊さずにルートの座標を得る方法(getDijkstraPath())

を改造する必要が出てきました。


User

You
postGISのpgr_dijkstraVia()は何をしてくれるAPIですか
ChatGPT
ChatGPT

PostGISのpgr_dijkstraVia()は、指定された複数の経由地を通過する最短経路を見つけるためのAPIです。これはpgRoutingの一部であり、Dijkstraアルゴリズムを使用して経路を計算します。

このAPIを使用すると、始点と終点の間に複数の経由地が与えられ、それらの経由地を通過する最短経路を見つけることができます。つまり、指定された始点から終点までの最短経路を見つける際に、特定の地点(経由地)を経由しなければならない場合に役立ちます。

pgr_dijkstraVia()関数の基本的な使い方は次のとおりです:

sql

SELECT * FROM pgr_dijkstraVia(
'edge_table', -- エッジテーブル
ARRAY[start_node, end_node], -- 始点と終点のノードIDの配列
ARRAY[via_node1, via_node2, ...], -- 経由地のノードIDの配列
directed := true/false, -- エッジが有向か無向かを指定
has_reverse_cost := true/false -- エッジに逆コストがあるかどうかを指定
);

この関数は、指定されたエッジテーブル内のエッジを使用して最短経路を見つけます。始点と終点のノードIDの配列と、経由地のノードIDの配列が指定されます。また、エッジが有向か無向か、およびエッジに逆コストがあるかどうかを指定することもできます。

このようにして、pgr_dijkstraVia()は指定された経由地を通過する最短経路を見つけることができます。

You
pgr_dijkstraCost()は、どういうAPIですか
ChatGPT
ChatGPT

pgr_dijkstraCost()は、PostGISのpgRoutingエクステンションで提供されるAPIの一つで、指定された始点と終点間の最短経路を見つけるために使用されます。しかし、pgr_dijkstra()とは異なり、この関数は経路を探す際にエッジのコスト(距離、時間、または任意の重み付け)を考慮します

この関数は、始点と終点のノードIDを指定し、エッジのコストを計算するための重みのカラムを指定します。その後、指定された始点から終点までの最短経路を見つけます。

基本的な使い方は次のとおりです:

sql

SELECT * FROM pgr_dijkstraCost(
'edge_table', -- エッジテーブル
ARRAY[start_node], -- 始点のノードIDの配列
ARRAY[end_node], -- 終点のノードIDの配列
cost_column := 'cost', -- エッジのコストを示すカラム名
directed := true/false -- エッジが有向か無向かを指定
);

この関数は、指定されたエッジテーブル内のエッジを使用して、始点から終点までの最短経路を見つけます。エッジのコストは、指定されたカラムに基づいて計算されます。また、エッジが有向か無向かを指定することもできます。

これにより、指定された始点から終点までの最短経路とその経路の合計コストが返されます。

2024,江端さんの忘備録

米国元大統領(現大統領も含む)は、原則として「謝罪をしない」なぁ、と思います。

I think that former presidents of the United States (including the current president) "do not apologize" as a rule.

『謝罪したら負け』という感じです。

It's like, 'If I apologize, I lose.

実際に、『謝罪したら負け』で『認めたら負け』という、そういう立ち位置の人だから、とも言えます。

They are such a stand-up guy that 'if I apologize, I lose' and 'if I admit it, I lose.

そして、これは米国に根付く国民性である、のようにも見えます。

This situation is a national trait that has taken root in the United States.

しかし、私の所感は違います。

However, my feeling is different.

------

私、20年前で、それもたった2年間の米国滞在でしたけど、『謝罪は負け』というような文化を感じたことはありません。

I was in the U.S. for only two years, 20 years ago, but I have never felt a culture that says 'apology is a loss.

仕事が遅延したり、作っているもの(プログラム等)に問題(バグ)が出れば、普通に『ごめんなさい』と言っていたと思います。

They would usually say "I'm sorry" to me when they delayed their work or if there was a problem (bug) with what they were making (programs, etc.).

もっとも、そういう場面が「なかった」ということだけかもしれませんが。

I may not have encountered such a situation.

ただ、ちょっと違う点があるとすると、私たち日本人チームは、仕事の遅延やバグが出たとき、『相手を責める』という態度で接することはしなかった、ということです。

The only difference is that our Japanese team did not take a "blame the other party" attitude when there were delays or bugs in the work.

『江端(またはチーム)が困っている』(実際に困っていた)という風に接して、「私(たち)を助けて欲しい」という形で接していた点、違うとは思っています。

I think it was different in that I treated them as if they were 'Ebata (or the team) is in trouble' (they were actually in trouble), and I treated them in a way that said, "I want you to help me (us)."

つまり、謝罪をする/しないの違いは、"文化"というより、"立ち位置"または"コミュニケーション"の違いで発生するものではないかなぁ、と思っています ―― 仮説の域を出ませんが。

In other words, I think that the difference between apologizing and not apologizing is not a matter of "culture" but rather a matter of "position" or "communication" - though this is only a hypothesis.

だれか検証してくれるか、あるいは、既往研究を紹介してくれると、私は嬉しいです。

I would be happy if someone could verify this or refer me to a previous study.

-----

比して、日本では、政権与党の党首が、金と政治の問題で、毎日のようにメディアで謝罪しまくっています。

In contrast, in Japan, the leader of the ruling party constantly apologizes in the media for money and politics.

これは、前述とは真逆で『謝罪したら勝ち』という感じです。

This situation is the opposite of those above: 'If I apologize, I win.

で、実際に、我が国では『謝罪したら勝ち』で、『立ち去ったら許される』という文化のようです。

In fact, in our country, the culture seems to be that 'if I apologize, I win' and 'if I walk away, I am forgiven. '

「これは、これで、どうなのかなぁ」という気がしています。

I wonder whether this is correct.

場当たり対応、という形で「謝罪」が使われることが多いような気がするからです。

I feel that "apology" is often used as a superficial response.

-----

例えば ――

For example--

今、メディアで論客をしている人で、過去に服役の経験があった人は、出所当時は「人が変ったかのように、謙虚だった」ように見えたのですが、今は、その姿は影も形もなく、完全に「服役前に戻った」という感じです。

The man who is now a pundit in the media and who had served prison sentences in the past seemed "humble as if a person had changed" after release from prison, but now, there is no shadow of that person, and they are entirely "back to when they were before" they were in jail.

国内裁判で多額の賠償命令をされて、フランスに居所を移した(逃亡?)方は、法律の属地主義を利用して、その賠償を逃れて、今も元気に論客して、お金も稼いでいるようです。

Another man who was ordered to pay a large amount of compensation by a domestic court and moved his residence to France (fled?) seems to have escaped the compensation by taking advantage of the legal territoriality principle and is still active as a public speaker and making money.

(そういえば、米国元大統領は、これまで自分の事業を"5回"倒産させて、多額の負債から逃げたそうです)。

(By the way, a former U.S. president has bankrupted his business "five times" to escape massive debt.)

ちなみに、私、「正義」や「モラル」に対しての感度は低いのですが、「金」に関しては過剰反応します。

Incidentally, I have low sensitivity to "justice" and "morals", but I overreact when it comes to "money".

新党の名称は、やはりこれで決まりでしょう ―― 「新党"脱税"」または「新党"裏金"」

総じて言えることは、「謝罪」は有効な「場当り」対応ではあるのですが、その持続時間は恐しく「短い」ということです。

In general, I can say that "apology" is an effective "on-the-spot" response, but its duration is terribly "short.

-----

私も、自分で何かを主張をする時、基本的に「正義」や「モラル」を出発点としますが、その主張の論拠は「ロジック」と「計算」です。

When I make an argument for something on my own, I take "justice" or "morality" as my starting point, but the argument for that argument is "logic" and "calculation."

もちろん、バックグラウンドには「怒り」や「不愉快」があるのですが、それは前面には出さずに、「ロジック」と「計算」という皮(あるいはインタフェース)を被せて語ります。

Of course, "anger" and "displeasure" are in the background, but I don't put them at the forefront. I argue under the skin (or interface) of "logic" and "calculation.

なぜ、このような迂遠なことをしているかというと、前述の通り、「正義」「モラル」「怒り」「不愉快」は、強烈ではあっても、持続時間が短いからです。

The reason for this detour is that, as noted above, "justice," "morality," "anger," and "displeasure," though intense, are the duration time is short.

比して「ロジック」と「計算」は、インパクトが弱くとも、持続時間が長い(減衰定数が小さい)です。

In comparison, "logic" and "calculation" have a longer duration (smaller decay constant), even if their impact is weaker.

だから、私のコラムやブログでは、「福島原発事故」を、「統一協会」を、そして「上司に言われた理不尽な言葉」を、いつまでも忘れないように、緻密かつ詳細に組み立て上げているのです。

So, in my columns and blogs, I build up the "Fukushima nuclear accident," the "Unification Association," and the "unreasonable words my boss said to me" with such precision and detail that I will never, ever forget them.

―― 少なくとも、この私(江端)だけは、その時の「怒り」を忘れることがないように、と。

"At least, just me (Ebata), so I would not forget the "anger" at that time."

「臥薪嘗胆(*)」とは、ちょっと違うのですが、そのアプローチは同じです。

It differs slightly from "lying in bed(*)," but the approach is the same.

(*)将来の成功を期して苦労に耐えること。薪の上に寝て苦いきもをなめる意から。「臥」はふし寝、「薪」はたきぎ、「嘗」はなめること。「胆」は苦いきも。もとは敗戦の恥をすすぎ仇あだを討とうと、労苦を自身に課して苦労を重ねること。

(*) To endure hardship in anticipation of future success. From the meaning of lying on firewood and licking the bitter taste. Lying on the firewood and licking the bitter taste. The original meaning was to suffer hardship and toil to avenge the shame of defeat.

-----

私も、当然に、謝罪すべき場面では、謝罪をします。

I also naturally apologize in situations where I should.

ただ、私の謝罪の意味と意義は、上記の謝罪とは全く違います。

However, the meaning and significance of my apology are pretty different from those of the above apology.

これについては、これまで、何度もお話してきたので、本日は割愛します。

I have discussed this often, so I will not discuss it today.

訓練されたエンジニア/研究員は、自分が「間違っていること」を前提に行動します。

2024,江端さんの忘備録

「イスラエルのガザ攻撃に抗議デモ 米で学生ら逮捕」のニュースが、ヘッドラインのトップに出ています。

The news, "Students Arrested in U.S. to Protest Israeli Attack on Gaza," is at the top of the headlines.

『50年前、この事件とほぼ同じ背景(パレスチナ vs イスラエル)を理由に、日本中の大学の学生が闘っていた』ということを、知っている人/覚えている人は、どれくらいるのかなぁ、と考えていました。

I wondered how many people know or remember that "50 years ago, students at universities all over Japan were fighting for almost the same background (Palestine vs. Israel) as this case.

今回のコロンビア大学のデモなんぞ「お遊戯」思えるほど ―― 50年前、『反イスラエル、パレスチナ連帯』を掲げて、大規模かつ過激かつ長期間に渡って、日本中で『学生運動』という名の、学生による大学占拠が続けられていました。

The Columbia University protests seem like a "play" - 50 years ago, there was a massive, militant, and prolonged student occupation of universities in Japan under the banner of "anti-Israel, solidarity with Palestine."

当時、多くの大学の機能は停止し、全ての講義もなくなり、入学試験すら実施できない状況でした。

At the time, many universities had ceased functioning, all lectures had disappeared, and even entrance examinations had stopped.

といっても、私が見てきた訳ではないのですが(20年遅かった)、たまたま、私は、そういうことを知り得やすい環境にいました。

I have not seen it happen (I was 20 years too late), but I happened to be in an environment where it was easy to know about such things.

-----

私の知る限り、「今回のイスラエル軍のガザ地区侵攻」が原因で騒ぎになっている、日本の大学や大学生のニュースはありません。

As far as I know, there is no news of Japanese universities or college students rioting because of "this Israeli military invasion of the Gaza Strip."

抗議活動しているのは、多分、上記の『学生運動』の経験者の方々(?)(かなりのご高齢の方)で、それも、チラホラと聞く程度です。

The protesters probably have experienced the "student activities" (?). (significantly older adults), and I have only heard glimpses of them.

私は、日本の若者だけでなく、日本人全体が、このニュースを聞いて、具体的に抗議活動をしていないことを、別段何とも思っていません。

Upon hearing this news, I have no comment on the lack of concrete protests by the Japanese youth and the Japanese people.

私たちは、自分のことで精一杯です。

We are full of ourselves.

他国の、それも、理解するのも難しい地政学や宗教による戦争や虐殺など、私たちのスコープ外ですよね。

Other countries that, too, are out of our scope, such as wars and massacres caused by geopolitics and religion, which are difficult to even understand for us.

学校で、「パレスチナ vs イスラエル」ついて、出エジプト記から現代に至るまでの経緯を教えてもらった訳でもありませんし。

We were not taught in school about "Palestine vs. Israel" from the Exodus to the present day.

------

私は、この問題に対して興味のない人を誰一人として非難しませんし、私自身も、自己批判する気はありません。

I do not condemn anyone for their lack of interest in this issue, nor do I wish to be self-critical.

―― だって、パレスチナもイスラエルも、他国の話じゃないですか

"Because Palestine and Israel are both other countries."

―― 政治に全く関係のない子どもが、1万3千人以上殺害され、もっと多くの子どもが飢餓と爆撃で死と直面していたとしても、しょせん、その子どもたちは"他人"ですよね?

"Even if more than 13,000 children who had nothing to do with politics were murdered, and many more faced death by starvation and bombing, they would still be "strangers," wouldn't they?"

-----

ただ、

However,  I think

―― 50年前の日本中の学生たちは、"それ"を黙って見ていられなかったんだろうなぁ

"I guess students all over Japan 50 years ago couldn't just sit back and watch "it."

とは、思っています。

『その前に、先ずは、"テルアビブ"、"パレスチナ"、"日本赤軍"あたりで、ググってみるといいんじゃないかな』

未分類

プロトタイプのロングラン開始。

とりあえず1万8千人のエージェントのトラッキングに、約5時間の予定。

現在、66万トラックの記録を確認。現時点で、クラッシュなし。

トラッキングDBが破綻しないことを祈りながら、ひたすら終了を待つ。


時間がかかりすぎるので、複数の計算機(100台くらい)を並列に走らせる仕組みが、必要になるかもしれない。

ーーーーー

おわった。取り敢えず第一回めは回った
agent_db=# select count(*) from agent_track;
count
---------
1164170
(1 row)

 

2024,江端さんの忘備録

ある日、ある地域で大雨が降り、洪水が起こりました。その地域の住民は、家や町から避難しようとしました。その時、一人の人が祈りを捧げました。彼は言いました、『神よ、私を救ってください!』

One day, heavy rain fell in an area, causing flooding. Residents of the area tried to evacuate their homes and towns. At that time, a man prayed. He said, "God, save me!

彼のもとに、救命ボートがやってきました。しかし、その人はボートに乗らず、『大丈夫です、神が助けてくれるはずです』と言いました。

A lifeboat came to him. But the man did not get on the boat and said, 'Don't worry, God will save me.

しばらくして、水がますます上がり、彼は2階に避難しました。そこでもう一度神に祈りました。すると、再び一度救命ボートがやってきましたが、彼は再び乗らず、『神が助けてくれるはずです』と言いました。

After a while, the water rose more and more, and the man took refuge upstairs and prayed again to God. Then a lifeboat came again, but he did not get on it again, saying, 'God will save me.

さらに水位が上昇し、彼は屋根に避難しました。そこでもう一度神に祈りました。すると、救助ヘリコプターが現れ、彼を救出しようとしました。しかし、彼は再び拒否しました。

As the water level rose further, he took refuge on the roof. There, he prayed again to God. Then a rescue helicopter appeared and tried to rescue him. But he again refused.

結局、洪水に巻き込まれ、その人は亡くなってしまいました。

In the end, he was caught in the flood and died.

その後、彼は天国に到達しました。彼は神に尋ねました。

Then he reached heaven. He asked God.

『なぜ私を助けてくれなかったのですか?』

Why didn't you help me?"

神は答えました。

God replied.

『私は3回も助けを差し伸べたが、お前がそれを拒んだからだ』

'I offered you help three times, but you refused them.'

-----

最近、体感できるレベルの地震が、日本全国で多発しているような気がします。

Recently, it seems that earthquakes at a level that we can feel occurring all over Japan.

『私は、何度も警告を出したが、お前がそれに備えなかったからだ』

'I warned you many times, but you were unprepared.'

と神様に言われたら、

Even though God says that, 

―― 反論できないレベルで、"多い"ように思います。

 I think there are "too many" at a level that I can't argue with.

リビングのテレビをつけたら、アナウンサーが、恐しい声で避難を叫んでいました ―― 息も切れんばかりの勢いで。

2024,江端さんの忘備録

この世の中は、若い世代を、「Z世代」だの「ゆとり世代」だの、「○○世代」名前をつけることで、安心する傾向があるようです。

It seems that the world tends to feel comfortable naming the younger generation as "Generation Z," "Yutori Generation," or "Generation XX.

私たちの世代は、「しらけ世代」とか言われていましたが、

Our generation was called the "dampened generation" or something like that,

―― はっきり言って、私は不愉快だった

"I was uncomfortable, to say the least".

-----

大学生の全員が「勉学を侮って、遊興に興じている」かのように言われるのは不愉快でした。

It was distasteful, as if all college students "underestimated their studies and were playing for amusement.

私は、そういう相手に対しては、

I was constantly debunking every old guy who used the "XX generation." Like the following.

■ 隔週でレポート作成の為に徹夜をして、

- Staying up all night every other week to write reports,

■ 毎日毎日、講義に出席し、

- Attending lectures every day, day after day,

■ 午前3時ごろに、ゼミ研究室を退出し、(昭和天皇崩御の際には、蛤御門の前で警官に囲まれて職質されました)

- Leaving the seminar lab around 3:00 a.m. (I was surrounded by police officers and questioned in front of the Hamagurimikado gate when the Showa Emperor died.)

■ 週7日のバイトをして、

- Working part-time, seven days a week,

■ 大学後半と大学院では、学費も自分で収めて、

- paid my tuition for the second half of college and graduate school,

■ 時々、呼吸ができなくなるような胸の痛みで、道路でうずくまったりしていたけど、

- sometimes crouching in the street with chest pains that made it impossible to breathe,

―― それで、私の世代が『何』ですって?

"And my generation is 'what'?"

と、言い放ち、「○○世代」を語る奴を、ことごとく沈黙させ続けていました。

『他の大学生は知りませんが、私の回りには、あなたたちが"期待"するような"若い奴"は、ただの一人たりともいなかったです』

'I don't know about other college students, but I have never met a single "young guy" around me that you would "expect" to be there.'

『変ですねえ。あなたの回りの大学生は、そんな奴らばかりだったんですね』

'That's strange. All those college students around you were like that.'

といって、「○○世代」を語るおっさんたちを、ことごとく論破しまくっていました。

And so, I was debunking every old man who talked about the "XX generation."

-----

Z世代は「受け身・指示待ち型」ーー

"Generation Z is "passive and waiting for instructions."

若い人は、怒っていいぞ。

Young people, you can be angry against this phrase.

「ふざけるな!」 と、怒鳴り返してもいい。

Screw you!" And you can yell back.

そもそも、「ゆとり」や「バブル」や「しらけ」と言われた奴らが、偉そうに若者を語るな。見苦しい。

In the first place, don't let those who were called "Yutori," "Bubble," and "Shirake" talk about the youth with such bravado. It's not nice to see.

むしろ、

Rather, you can say 

『若い部下に、詳細で的確な指示も出せない、自分の無能なマネージメント能力を恥じろ、この無能が』

"You should be ashamed of your inability to give detailed and precise instructions to your young subordinates, you incompetent manager."

と言ってもいい。

事実だから。

Because it's true.

-----

私は、誰かに仕事をお願いする時には、可能な限り詳細に説明するようにしているつもりです。

I will try to be as detailed as possible when I ask someone to do a job.

むしろ、その作業の方が、時間をかかることがあるくらいです。

The process is so much more time-consuming.

特に「仕事の最後の形(ゴール)」については、できる限り詳細にして指示をします。

In particular, I give instructions on the "final form (goal) of the work" in as much detail as possible.

これは、『仕事の失敗を、部下の責任にして逃げるとができない』というリスクを負うことになりますが、そもそも。他人に仕事を頼むというのは、そういうリスクを負うことです。

This means that you run the risk of not being able to escape by blaming your subordinates for your work's failure, but that is the risk you run in the first place. Asking someone else to do a job for you is to take that risk.

『Z世代は「受け身・指示待ち型」』のような言い方で逃げるやつらは、要するに、リスクを負いたくない"ヘタレ"です。

Those who run away with phrases like "Generation Z is passive and waits for instructions" are, in essence, "slackers" who don't want to take risks.

こういう奴を見わける簡単なフレーズがあります。

There is a simple phrase to recognize these guys.

『若い人達の自主性を大切にする』と言う奴なら、確実にその"ヘタレ"です。

Anyone who says, "I value the autonomy of young people," is a "slacker" for sure.

私、このフレーズを一回でも使った奴は、信じないことにしてきました。

I have not believed anyone who uses this phrase even once.

そして、この判断は間違っていなかったと確信しています。

And I am convinced that this decision was not wrong.

これにつきましては、『個性を育てる教育をする』という、学校説明会の校長の言葉に通じるものがあります。

At the school's information session, I remember the principal's words: "We will provide an education that nurtures individuality.

このコラムの、

Please refer to the following page in the column, 

こちらのページに記載の「―― 個性を育てる教育だって? 笑わせるんじゃねーよ」

"The article on this page, "-- Education that fosters individuality? Don't make me laugh."

を御参照下さい。

-----

そもそも、

To begin with,

■「自由にやっていい」といわれて、自由にやれば、それに文句を言われ、

- When your boss told that you are free to do what you want, and you do it freely, the boss will complain about it,

■「言われた通り」にやれば、「言われたことしかやらない」と文句を言われる。

- If you do what your boss orders,  the boss complains that you only say what you do the orders.

これで、仕事ができる人間がいたら、「それは人間ではない」と言ってもいいでしょう。

If someone can do the job, you can say, "That's not a human being.

「受け身・指示待ち型」―― 上等です。それでいいんです。

Passive, waiting-for-directions type - that's fine.

「バカヤロー、お前は俺の仕事の何を見てきたんだ!」と叫ぶメンターに関する一考察

-----

私も、原則「受け身・指示待ち型」でしたが、何もしていなかった訳ではありません。

As a rule, I was also "passive and waiting for instructions," but that does not mean I did nothing.

私は、自分が必要だと思った仕事は『黙って』やっていました。

I 'shut up' and did the work I felt I needed to do.

なぜなら、

Because, 

―― しゃべると、確実に"潰される"から

"If I speak, my boss crushed it for sure."

です。

「人の言うことを聞かない能力」

私の場合、こんな感じでした。

In my case, it went like this.

2024,江端さんの技術メモ

特定領域内で、乱数的な緯度・経度の作成を行うコードをChatGPTに考えて貰いました。

package main

import (
	"fmt"
	"math"
	"math/rand"
)

// Polygon represents a polygon defined by its vertices
type Polygon [][]float64

// Point represents a point with x and y coordinates
type Point struct {
	X float64
	Y float64
}

// isInPolygon checks if a point is inside a polygon using the ray casting algorithm
func (p Polygon) isInPolygon(point Point) bool {
	intersections := 0
	for i := 0; i < len(p); i++ {
		p1 := p[i]
		p2 := p[(i+1)%len(p)]

		if point.Y > math.Min(p1[1], p2[1]) && point.Y <= math.Max(p1[1], p2[1]) &&
			point.X <= math.Max(p1[0], p2[0]) && p1[1] != p2[1] {
			xIntersection := (point.Y-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1]) + p1[0]
			if p1[0] == p2[0] || point.X <= xIntersection {
				intersections++
			}
		}
	}
	return intersections%2 != 0
}

// generateRandomPointInPolygon generates a random point inside the given polygon
func generateRandomPointInPolygon(p Polygon) Point {
	var minX, minY, maxX, maxY float64
	minX = math.MaxFloat64
	minY = math.MaxFloat64
	maxX = -math.MaxFloat64
	maxY = -math.MaxFloat64

	// Find bounding box of the polygon
	for _, vertex := range p {
		if vertex[0] < minX {
			minX = vertex[0]
		}
		if vertex[1] < minY {
			minY = vertex[1]
		}
		if vertex[0] > maxX {
			maxX = vertex[0]
		}
		if vertex[1] > maxY {
			maxY = vertex[1]
		}
	}

	// Generate random points until a point inside the polygon is found
	var randomPoint Point
	for {
		randomPoint.X = rand.Float64()*(maxX-minX) + minX
		randomPoint.Y = rand.Float64()*(maxY-minY) + minY

		if p.isInPolygon(randomPoint) {
			break
		}
	}
	return randomPoint
}

func main() {
	// Define the polygon
	polygon := Polygon{
		{35.36394967, 139.61846500},
		{35.36216810, 139.61890850},
		{35.36170465505306, 139.6220415552594},
		{35.36163108058289, 139.62334070015595},
		{35.363117271878345, 139.62314221968566},
		{35.36335187635167, 139.62481739887647},
		{35.36310056060587, 139.62485183402688},
		{35.36376860001917, 139.6288186562702},
		{35.36420166714637, 139.6297897196359},
		{35.36754482323006, 139.6296024603071},
		{35.37126945661188, 139.62886244945108},
		{35.37375189636854, 139.62615207124352},
		{35.37464657021711, 139.623189740366},
		{35.37574882601201, 139.6213765671167},
		{35.37527643251494, 139.6210117866997},
		{35.37306314467156, 139.6217413475337},
		{35.37268696718477, 139.62013202216457},
		{35.37018828750506, 139.61840497406456},
		{35.370782160278, 139.61705458898427},
		{35.36947068533102, 139.61641732865053},
		{35.370596575495014, 139.61476348635583},
		{35.37078029225879, 139.61403393574466},
		{35.36864433631068, 139.61438212951467},
		{35.36653571408147, 139.61453772192408},
		{35.36394967, 139.61846500},
	}

	// Generate a random point inside the polygon
	randomPoint := generateRandomPointInPolygon(polygon)
	fmt.Println("Random point inside polygon:", randomPoint)
}

なるほど、と思いながらコードを読んでいたのですが、『あれ? これって、領域に入った緯度・経度の乱数を採用するだけだから、発生頻度が均一にならないんじゃないかな?』と思い、ChatGPTにたずねてみたら『Yes』と言われました。

で、発生頻度を均一になるコードを再度要求したのですが ―― コードを一目見て、『このコードは間違っているな』と分かるようなものが出てきました。

『ChatGPTは、もの凄く真摯な言葉で、嘘をつく』

で、昔のコードを探していたら、PostGISを使うものが出てきました。

// C:\Users\ebata\tomioka3B\src\others\main35.go
/*
	実験用の座標を作る
	修正後 (富岡西5丁目を削除し、富岡6丁目の下1/4を削除)

	このプログラムは、Go言語を使用してPostgreSQLデータベースから空間データを取得し、指定された多角形内に均等に配置された乱数の座標を生成します。以下はプログラムの概要です:

	パッケージのインポート: 必要なパッケージをインポートします。database/sql はデータベースの操作に使用され、fmt と log は出力とログのために使用されます。また、PostgreSQLデータベースへの接続に使用するドライバもインポートされます。
	main() 関数: プログラムのエントリーポイントです。まず、PostgreSQLデータベースに接続します。接続情報は、ユーザー名、パスワード、ホスト、ポート、およびデータベース名で構成されます。
	SQLクエリの実行: query 変数にSQLクエリが格納されています。このクエリは、指定された多角形の領域内に均等に配置された15000個の点を生成するものです。db.Query() を使用してクエリを実行し、結果を rows に格納します。
	結果の処理: rows.Next() を使用して、結果セットの各行を処理します。各行は msg として取得されます。次に、regexp パッケージを使用して、取得した座標データを処理します。
	座標データの分解: 取得した座標データは、MULTIPOINT 形式の文字列として提供されます。この文字列をバラバラに分解し、各点の緯度と経度を取得します。regexp.MustCompile("[() ,]").Split(msg, -1) を使用して、文字列を分割します。
	座標の表示: 緯度と経度のペアを取得し、それぞれを浮動小数点数に変換して表示します。

	このプログラムは、指定された多角形内に均等に分布する乱数の座標を生成し、それを取得して表示します。


*/

package main

import (
	"database/sql"
	"fmt"
	"log"
	"regexp"
	"strconv"

	_ "github.com/lib/pq"
)

func main() {
	// 取り扱うDBによってノード番号が代わるので注意すること
	// 例えばtomioka_db_c とtomioka_dbは全く異なる
	db, err := sql.Open("postgres",
		"user=postgres password=password host=192.168.0.23 port=15432 dbname=tomioka_db_f sslmode=disable")
	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer db.Close()

	// 修正後のターゲットの富岡地区 (富岡西5丁目を削除し、富岡6丁目の下1/4を削除)

	query := `
	SELECT st_asText(
		ST_GeneratePoints(
			ST_GeomFromText(
				'POLYGON((
					35.36394967 139.61846500,
					35.36216810 139.61890850,
					35.36170465505306 139.6220415552594,
					35.36163108058289 139.62334070015595,
					35.363117271878345 139.62314221968566,
					35.36335187635167 139.62481739887647,
					35.36310056060587 139.62485183402688,
					35.36376860001917 139.6288186562702,
					35.36420166714637 139.6297897196359,
					35.36754482323006 139.6296024603071,
					35.37126945661188 139.62886244945108,
					35.37375189636854 139.62615207124352,
					35.37464657021711 139.623189740366,
					35.37574882601201 139.6213765671167,
					35.37527643251494 139.6210117866997,
					35.37306314467156 139.6217413475337,
					35.37268696718477 139.62013202216457,
					35.37018828750506 139.61840497406456,
					35.370782160278 139.61705458898427,
					35.36947068533102 139.61641732865053,
					35.370596575495014 139.61476348635583,
					35.37078029225879 139.61403393574466,
					35.36864433631068 139.61438212951467,
					35.36653571408147 139.61453772192408,
					35.36394967 139.61846500
				))'
			),
		15000)
	)
	`
	rows, err := db.Query(query) // この25が生成する乱数座標

	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	var msg string

	for rows.Next() {
		if err := rows.Scan(&msg); err != nil {
			fmt.Println(err)
		}

		// まずはMULTIPOINTをバラバラに分解する
		arr1 := regexp.MustCompile("[() ,]").Split(msg, -1) // '('か、')'か、' 'か、","で分割する → "[中身]" という構造でまぎらわしい

		// 2つの値を一度に取得する (最初の値" MULTIPOIN"をスキップする為に、i:=1から始める)
		for i := 1; i < len(arr1); i += 2 {
			// arr1[i]とarr1[i+1]は2つの値を表します
			if i+1 < len(arr1) {
				value1, _ := strconv.ParseFloat(arr1[i], 64)   // 乱数の緯度
				value2, _ := strconv.ParseFloat(arr1[i+1], 64) // 乱数の経度
				fmt.Println(i, value1, value2)
			}
		}
	}
}

ポイントは、指定された多角形内に均等に分布する乱数の座標を生成 という点です。

どういう仕組みか分かりませんし、ChatGPTが真実を言っているのかも不明ですが、『postGISなら、その程度の仕組みは入れてくるだろう』と期待して、今回は、こちらを使うことにしました。

以上

2013,江端さんの忘備録

新聞の編集部が舞台となっている、ある本を読んでいたのですが、

新人の買いた取材ルポを、上司が一読すると、その用紙をくしゃくしゃにして、ポイと投げるシーンが出てきます。

「ボツ! やりなおし!!」という上司に対して、

「あ、・・あの・・・どこが悪いんでしょうか」と尋ねる新人に、

「自分で考えろ。誰も教えてくれないぞ」といって、新人に大量の資料を手渡す上司が出てくる場面があります。

今の日本では、こういう「バカげた指導」を行っている職場は、残念ながら存在しているようです。

-----

こういうシーンが結構な数、見られるのですよ。特に、テレビ番組の、「寿司職人」「大工職人」などの、職人シリーズに多い。

「バカヤロー、お前は俺の仕事の何を見てきたんだ!」

と怒鳴る先輩職人のシーンを見ると、私なんぞは、

―― バカはお前だ。なぜ、大切な仕事の内容ならば、それを体系だてて、順序よく、理解しやすいように説明してやらないんだ。

―― お前にプレゼン能力(説明能力)がないばかりに、新人が効率よく仕事の内容を取得できずにいるんだろうが、阿呆が。

―― 自分が、「寿司握っているだけ」「工具を使っているだけ」で、新人が育つなどという、そんな都合のいい話があるか、馬鹿野郎めが。

と思ってしまうのですよ。

「仕事は盗むものだ」と信じているこういう先輩や上司は、コスト意識がない上に、自分達の持っている技術を「上限」と信じている傲慢さが見て取れて、気分が悪いです。

自分の持っている技術を踏み台として、新人を、更なる高みを目指させるのが、メンター(指導者)というものではないでしょうか。

-----

ところが、こういうテレビ番組などで、こういう場面が頻出するところを見ると、我々日本人は、「仕事は盗むものだ」というストーリーが大好きなようです。

先輩に責められ、上司に叱責され、何度もやりなおしをさせられ、それでも、最後に成功して、「やればできるじゃないか」という先輩に「ありがとうございました!」と、涙ながら語る新人の台詞で終わる、というストーリーです。

―― 正直、うんざりです。こういう番組。

一人ならチャンネル替えてしまうのですが、食事の時に、家族全員で見ている時などは、つき合わなければならない時もあるのです(また、こういうことを指摘すると、家族の批判の目にも晒されますので、ガマンしています)

でも、どう考えたって、正解はこうでしょう?

(Step.1)先輩が後輩の良くない部分を指摘し、正しいやり方を口頭だけでなく図解や実際のやり方を示して、短時間で所定の技術を取得させる。

(Step.2)そんでもって、同じミスを2回した場合は、それを指摘し、改善がなければ、叱責する。それでも駄目なら辞めて貰う。技術を継承できない者は、不要であるから。

それだけのことですよね。

-----

ただ、このような構成の番組としたら、到底、視聴率は取れないだろうな、ということは、私にも分かります。

未分類

社内報リレー随筆

「人の言うことを聞かない能力」

2004/01/10
[その1]

インターネットが、電話線で細々と繋がっていた頃、私は未来のインターネットを夢想して、張り切って特許明細書を書いてましたが、私より数段偉くて頭の良い人から『意味がない』と論理的に説得されてその執筆を止めてしまったことがあります。

そして今、その発明を他社が実施しているのを悔しい思いで見ながらも、今なお、その論理を論破できない自分がいます。

私が心の底から悔しいと思うことは、世間がなんと言おうが、論理的に破綻していようが、私が信じるものは絶対である、という狂信的な思い込みを持ち得なかった自分に対してです。

-----

[その2]

数年前に私が結婚を決意した時、私の回りは一斉に反対の声を上げました。

私に結婚を思い留まらせる為に合宿まで企画されました(本当)。

『写真のこの娘は堅気の娘ではないか。暗黒サイドのお前とは所詮住む世界が違う!』(暗黒サイドって何?)。

実際、その当時彼女自身、本当に私と結婚したかったかどうかも疑わしく(と言うと嫁さんは『何を言うの!たとえ、あなたが売れない場末の芸人であっても、私は・・』と言い返すのですが)、私は彼女の意見すら十分に聞かずに結婚に踏み切りました。

-----

[結言]

私達は自立した社会人として、人の話をきちんと聞かねばなりません。

しかし時として「人の話を聞かない能力」を問われるものが世の中に2つだけあります。

それが「特許」と「愛」です。

お忘れなきよう。