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

『プログラミング言語「C++」は嫌われる』という内容の記事は、ちょくちょく目にします。

I often see articles that say, "The programming language 'C++' is hated".

しかし、大きな本屋に行くと、C/C++の本の数が圧倒的です。

However, if you go to a large bookstore, you can see the number of C/C++ books is overwhelming.

下手すると、プログラム言語関連の半分が、C/C++の本だったりします。

Half of the books related to programming languages are often C/C++ books.

まあ、C/C++が選ばれる理由は、「ハードウェアの性能を最大限引き出す、低レベルのインターフェース」

Well, C/C++ is chosen because of its "low-level interface that maximizes hardware performance."

であり、

and,

C/C++が嫌われる理由は、「メモリリークが引き起こす、システムダウンへの恐怖」

C/C++ is disliked because of the "fear of system downtime caused by memory leaks."

でしょう。

I think that.

ガーベージコレクションが実装されている言語は、当然のことながら、実行速度が遅くなります。

Languages in which garbage collection is implemented are naturally slower to execute.

そういう面倒なことを気にせずに、平気で実装できる乱暴さがあるからこそ、C/C++は現在も最速の言語として君臨し続けているのです。

It is precisely because of the wildness that can be implemented with impunity, without worrying about such troublesome things, that C/C++ continues to reign as the fastest language to this day.

-----

私、米国赴任中に、現地で発生していたメモリーリークの問題を、「商用ライブラリ」の中に発見して、この回避方法を見つけました。

While on assignment in the U.S., I found a workaround for this problem of memory leaks that I was experiencing locally in a "commercial library".

それをミーティングの時に発表して、メンバーから絶賛された(と思う)のを覚えています。

I remember presenting it at a meeting and receiving (I think) rave reviews from the members.

というか、『この国のエンジニアは、メモリリークを容認するのか』とビックリしたのを覚えています。

I remember being surprised that 'engineers in this country tolerate memory leaks.

ちなみに、当時の弊社では、メモリリークを起こす実装をしたエンジニアは、回りの人間から『バカ、アホ、死ね』と言われて、頭(こうべ)を垂れ続けなければなりませんでした。

Incidentally, at our company at that time, the engineer who implemented memory leak had to keep hanging his head, with hearing "you are an idiot, a moron, and should die".

-----

「GoogleはC++の仕組みを土台として、C++と互換性のあるCarbonを開発する」と聞きました。

I heard that "Google will use the C++ mechanism as a foundation to develop Carbon, which is compatible with C++."

Googleのアホー!

"Google Idiot"

そんなもんいらんわー!

"I don't want that! "

そんなもん開発するくらいなら、

Instead of developing something like that, release an extended version of C++ from the get-go! with

(1)スケーラブル軽量スレッド(goroutineのこと)、と

(1) Scalable lightweight threads (goroutine's), and

(2)チャネルを追加実装した、

(2) Additional channels are implemented

最初から拡張版のC++をリリースしろ!

と、言いたい。

I want to say that.

ちなみに、メモリリークは、『間抜けなエンジニアの証明』で、私はO.K.です。

By the way, I am O.K that "memory leaks" is 'dumb engineer proof'"

ガーベージコレクションが走ると、正確なプログラムの実行時間が分からなくなるからです。

Garbage collection is not a good idea because it makes it impossible to know the exact program execution time.

-----

まあ、どっちみち、私は、Golangを人生最後のプログラム言語とする予定なので、まあ、今からどんな言語が出てこようとも構わないのですが。

Well, anyway, I plan to make Golang the last programming language of my life, so, well, I don't care what language comes out now.

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

あが

Golangのファイルを分割して使いたい

の方法が上手く動かない。

$ tree
.
├── Agent
│   ├── cert.pem
│   ├── go.mod
│   ├── go.sum
│   ├── key.pem
│   └── main.go
├── join
│   ├── cert.pem
│   ├── join.exe
│   ├── join.go
│   └── key.pem
└── ldarp
    └── libdarp.go

のAgent/main.go と、join/join.goの中で、ldap/libdarp.goを使いたいんだけど、

import (
	"m/ldarp"
)

を、

import (
	"m/../ldarp"
)

とか

import (
	"m/./../ldarp"
)

とか試したみたんだけど、ダメ。

エラーコードに記載されているように、大人しく、
join.go:13:2: package m/ldarp is not in GOROOT (c:\go\src\m\ldarp)
のところに作れば動くんだろうけど、『負けたような気がする』ので、Agent/main.go と、join/join.goの中に、ldap/libdarp.goを埋めこむことで対応した。

ライブラリの二重管理になるけど、まあいいかな、と。

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

私、常日頃から、『北朝鮮という国は、本当に外交戦略が上手いよなぁ』と感心しています ―― 但し、

I have always been impressed by the diplomatic strategy of North Korea -- except for the

私たちから見た善悪や正義や不快感に関して、全て目をつむれば、ですが。

all that is right and wrong, justified and offensive from our point of view.

で、そのことをコラムで書こうかなぁ、と嫁さんにつぶやいてみたところ、

So I tweeted to my wife that I might write a column about it, however, she said

『絶対に止めてくれ』

"Don't ever do that"

と、厳しく禁じられました。

and I am strictly forbidden.

『江端家全体の、テロの脅威が(今以上に)高まるから』だ、そうです。

The reason is that the threat of terrorism to the entire Ebata family will increase (even more than before).

-----

最近、「地政学」という言葉が、テレビでも登場するようになっているようです。

The term "geopolitics" seems to be appearing more and more on TV these days.

地政学とは、一言で言えば、「その国の立ち位置(政治体制等)は、地理的な条件で決定する」というものです。

"Geopolitics" is, in a nutshell, that a country's positions(political system, etc.) is determined by its geographical condition.

地政学がピックアップされていることは、とても良いことだと思います。

I think the popularity of "Geopolitics" is good.

先ずは、この教科を、地理や歴史に組み込んでもいいんじゃないか、と思っています。

Above all, the better way is that this subject might be embedded in into geography and history.

なぜ、そう思うかというと、

The reason is simple.

―― 国際ニュースを見ていても、あまり腹が立たなくなるから

"It makes me less angry when I watch international news"

です。

『その国がどういう立場で、その行動をしているか』が、見えてくるので、ストレスが減るのです。

It's less stressful because I can see 'where the country stands and what they are doing'.

-----

ただ、国家としては、このような「物分かりのいい国民の育成」というのは、メリットでもありますが、デメリットでもあります。

On the other hand, as a nation, this kind of "cultivation of a well-informed public" is both an advantage and a disadvantage.

守屋淳さんの、こちらの本のp.354にある

In this book, written by Jun Moriya, in p. 354,

クラウゼヴィッツの「三位一体」

Clausewitz's "Trinity"

1. 国民 = 本能担当 = 戦争の情熱や熱狂担当

1. people = in charge of instinct = in charge of passion and enthusiasm for war

2. 軍隊 = 自由な精神活動担当 = 戦争の運営担当

2. military = free spirit = in charge of running the war

3. 政府 = 知性担当 = 戦争の大枠担当

3. government = in charge of intelligence = in charge of the general framework of war

という区分で考えると、「物分かりのいい国民」は、情熱も熱狂も持たない国民となり、国家全体としては、少々困ったことになるからです。

From the viewpoint of the above classes, "a well-informed public" has less passion and enthusiasm, and this is a little "troublesome" as the whole nation.

日本国民に特化して考えれば、以下のような項目に関することです。

Thinking about Japanese people, the following issue is a sample.

―― 「核」に関してだけは、理性的でも、論理的でもある必要もなく、むしろ、激情や憤怒で対応してもよい

-----

文部科学省が、国民に、義務教育で「地政学」を課していないのは、こういう理由なのなぁ、と邪推しています。

I wonder if this is the reason why the MEXT does not require its citizens to take "geopolitics" as part of compulsory education.

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

モノを作る技術、というのは、一種の保険であると考えており、私は、(会社の仕事はサボっても)、流行りの技術のキャッチアップだけは怠らないように努めてきました。

I believe that the art of making things is a kind of insurance policy, and I have always tried to keep up with the latest trends in technology (even if I skip company work).

で、今、これを見て、心底驚愕しています。

And now, I am truly astonished to read this.

―― 何か怖いものを見た

"I watched something scary"

という感じです。

It is like that.

-----

もっともメーカーでなくても、「技術」は必要ですが、その技術は、人間の存在を前提とする技術 ―― コミュニケーションとか、人たらしとか、セールストークとか、カリスマとか ―― がメインになるのではないか、と思うのです。

I think that even if you are not a engineer, you still need "technology," but that technology should be mainly based on the existence of human beings--communication, charisma, sales talk, charisma, and so on.

その認識自体、すでに見誤っているのでしょうか?

Is that perception itself already misguided?

例えば、私の場合、明日会社を放り出されても、『パソコンがあれば、なんとかなるだろう』という漠然(ばくぜん)とした期待があります。

For example, in my case, I have a vague expectation that even if I am thrown out of the company tomorrow, I will be able to get by with a computer.

大抵の装置であれば、マニュアル読めば動かすことができるだろう、とも思っています。

I also believe that if I read the manual, I will be able to run most machines.

これが、人間の存在を前提としない「モノを作る技術」であり「一種の保険」と思っているものです。

This is what I consider a "technology of making things" and "a kind of insurance" that does not presuppose human existence.

-----

近年は、都市設計とか、地域サービスとか、地域復興とか、モノ作りの興味が変化していっているのは知っていますが ―― だとしても、

I know that in recent years, urban design, community service, and community revitalization have been popular -- however, I think, that

『その設計した何かは、ハードウェアと、プログラムと、データベースと、スマホなしでは動き出さんぞ』

"Something you've designed doesn't start working without hardware, program, database, and smartphone."

とは、思うのです。

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

コンピュータのリソース不足を補う為に、Windows7のままで放置してあったPCを、昨日にWindows10に移行して、docker環境を作り込んでいました。

To compensate for the lack of computer resources, I had migrated my PC, which had been left in Windows 7, to Windows 10 yesterday to create a docker environment.

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

dockerのイメージだけを、リモートに送り込む等、夜遅くまで、色々試していたのですが、データベース丸ごとをイメージにするのは難しく、docker export/import/save/load 全部を試した挙げく、

I was up late at night trying various methods, such as sending docker images to a remote location, but it was difficult to create an image of the entire database, and after trying docker export/import/save/load everything,

―― コンテンツ本体を、手動でUSBメモリにコピーして、現在、DB再構築の真っ最中

"Manually copied the content itself to a USB memory stick, currently in the middle of rebuilding the DB"

という体らくです。まあ、一人で作っているプログラムなので構わないのですが。

Well, I don't mind, since it is a program that I am making alone.

私としては、管理するPCは、あまり増やしたくないのですが、仕方ありません。

As for me, I don't want to add too many PCs to be managed, however I have no choice.

データベースの過負荷でシミュレーションが止ってしまうのを、放置し続ける訳にもいきませんから。

I cannot leave the simulator stopped due to database overload.

-----

私、100円のアイスクリームと、200円のアイスクリームを購入で、余裕で3分間は悩むことができます。

I need three minutes to annoy to choose between getting 100 yen or 200 yen icecream.

しかし、30万円のゲーミングPCを、自分のシミュレータを動かす為に購入することに関しては、あまり悩みません。

However, I wouldn't worry too much about buying a $300,000 gaming PC to run my simulator.

なにしろ、苦学生していたころ、定価85万円のパソコンを、「現金」で購入していたくらいです。

When I was a struggling student, I had purchased a computer with a list price of 850,000 yen with cash.

-----

『高スペックな計算機を追い求める』ことは、エンジニアにとっての「呪い」のようなものです。

The "pursuit of high-specification computer" is like a "curse" for engineers.

これまで何度も書いていますが、当時85万円のPCは、現在の5000円のボードコンピュータに勝てません(というか、その当時の、スパコンにも勝てません)

As I have written many times in the past, an 850,000 yen PC (a supercomputer too) at that time cannot beat even a 5,000 yen board computer today.

常識のあるエンジニア&研究員は、「スペック」に踊らされてはならないのです。

Engineers & researchers with common sense should not dance around the "spec.".

この本の題目(内容)は、私の生き方とは相容れませんが、

Although the subject (content) of this book is incompatible with my way of life

『置かれた環境で、計算しなさい』

"Do the math in your environment"

と読み替えるのであれば、正しい示唆だと思います。

If it is to be read this way, I think it is a correct suggestion.

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

先日リリースされたコラムで、

In my column which is released yesterday, I wrote

―― 私が教祖になるには、まず、私が「天啓」を受けている、というストーリーが必要です

"To become a guru, I must first have a story that I am "enlightened"!"

と書きました。

日常生活においても、過激なダイエット等で、比較的簡単に「天啓」を得ることができることは事実です。

It is true that it is relatively easy to obtain "revelations" in daily life, e.g., through extreme dieting.

それは、私の体を張ったダイエットで、実証済みです。

This has been proven by my own physical diet.

加えて、実際に、私、これまで、何度も神を降ろしています(本当)。

In addition, I have, in fact, brought God down many times (really).

(↑のクリックで記事に飛びます)

(↑click to jump to the article)

つまり、世界三大宗教を含め、経典に記載されている「教祖の天啓」ってやつは、かなり「眉唾(まゆつば)もの」である、ということです。

In other words, the "revelations of founder of religion" in the scriptures, including those of the world's three major religions, are quite 'dubious tale'.

-----

ちなみに、私の宗教勧誘の撃退方法の一つに、

Incidentally, one of my methods of repelling religious solicitations is to

『あなた、神様を見たことがあるの? 私はあるよ。2000年9月11日、米国ユタ州の国立公園の巨大な砂岩のアーチの下で。クリアに見えたよ』

"Have you ever seen God? I have, on September 11, 2000, under a huge sandstone arch in a national park in Utah, USA. I saw them clear."

『あなた、神様の声を聞いたり、姿を見たりしたことあるの? え? ないの? ないのに"この私"に布教をしているの?』

"Have you ever heard or seen God? What? No? And you're proselytizing to me?"

『ちょっと思い上がってんじゃないのかなぁ』

"I think you are a little presumptuous are't you?"

と、「格の違いを見せつける」というメソッドがあります。

is a method to 'show the difference in class'.

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

本日は、コラムがリリースされた日なので、日記はお休みです。

Today, new my column is released, so I take a day off.

「お金に愛されないエンジニア」のための新行動論(7)

老後を生き残る戦略として「教祖(仮)」になってみた

"A New Theory of Action for Engineers Who Are Not Loved by Money(7)"

I became a "guru (temporary)" as a strategy to survive in old age

-----

ぶっちゃけて言いますが、前回のコラムは、あまり好評ではなかったようです ―― Twitterとランク(順位)からの、私の、主観的な見解ですが。

Frankly speaking, the last column was not very well accepted -- from my viewpoint based on Twitter or rankings.

修正もしましたが、かなり力(リキ)を入れて書いたので、正直ガッカリしました。

I made some revisions, but to be honest, I was disappointed because I put a lot of effort into writing it.

-----

後輩:「江端さん。それ、多分、世代の違いですよ」

Junior: "Ebata-san. That's probably a generational gap"

江端:「?」

Ebata: "?"

後輩:「私たちの世代は、"カルト宗教"は本当に危険な存在として、認識されていましたよね ―― 統一教会、創価学会、オウム、幸福の科学、エホバの証人・・・。これらの存在を知らない大学生はいませんでしたし、世間も一定の知識がありました」

Junior: "In our generation, "cults" were recognized as really dangerous -- Unification Church, Soka Gakkai, Aum, Happy Science, Jehovah's Witnesses... There was no college student who didn't know about them, and the public had a certain level of knowledge about them. There wasn't a college student who didn't know these things existed, and the public had a certain amount of knowledge about them.

江端:「うん。そう思う。以前、ニュースで自民党・福田達夫総務会長が『(元・統一教会の)何が問題かわからない』との発言をしているのを見たけど、思わず、『あんた、これまで、一体何を学んできたんだ?』と、思わずテレビに向かって、説教してしまったよ」

Ebata: "Yes. I think so. I saw LDP General Affairs Chairman Tatsuo Fukuda on the news once saying, 'I don't know what the problem (about the Unification Church) is,' and I involuntarily lectured him on TV, saying, 'What the hell have you learned so far?' "

後輩:「・・・あの自民党の議員、本当に『分かっていなかった』のかもしれませんよ」

Junior: "...that LDP member, maybe he really 'didn't get it'."

江端:「ええ! いくらなんでもそれは"ない"だろう。そんな国会議員が我が国に存在するか?」

Ebata: "Yes! That's "no" in any case. Is there such a member of parliament in our country?"

後輩:「知識くらいはあったかもしれませんが、そのインパクト(霊感商法や過剰献金などの反社会的活動)を、肌で感じとっていない、という可能性はあります」

Junior: "It is possible that he had at least some knowledge, but he did not feel the impact (anti-social activities such as psychic sales and excessive donations) firsthand.

江端:「そうなの? 私が大学キャンパスを歩いている時は、『油断していれば、やられる』という緊張感が常にあったように思うけどなぁ」

Ebata: "Really? When I was walking around college campuses, there always seemed to be a sense of tension that if I wasn't careful, I would get hit."

後輩:「あと、カルト宗教側のアクティビティが低下している可能性もあります」

Junior: "Also, it's possible that activity on the cult side is declining."

江端:「というと?」

Ebata: "What do you mean?"

後輩:「信徒勧誘アプローチに改良が加えられていない ―― 既存のメソッドを使い回しているだけで、アプローチの改良をしていない、ということです。で、カルト宗教側も、ジリ貧のまま消滅に向かっている、と」

Junior: "There has been no improvement in the congregational recruitment approach -- they are just using existing methods and not improving their approach. And so the cult side is on the verge of extinction"

江端:「消滅に向かっているなら、めでたいことだけど・・・、私がコラムの中で提案している『ワンオペ布教』とか、取り得るアプローチは、まだ色々あるだろう?」

Ebata: "If it's on its way to extinction, that's great... but there are still a lot of approaches that could be taken, like the 'one-op missionary' that I proposed in my column, right?"

後輩:「そういう'ITリテラシーを持った人間を信徒にできないことも、カルト宗教団体の問題なんじゃないですかね」

Junior: "I think the problem with cult groups is that they can't make such 'IT literate' people into believers."

江端:「なるほど。『宗教』と『IT』は、とことん相性悪そうだもんなぁ・・・」

Ebata: "I see. Religion and IT don't seem to go well together..."

-----

今回のコラムでも、皆さんの「カルト宗教への関心」を観測していきたいと思います。

Now, in this column, I would like to look at your "interest in cults".

なお、前回のコラムの修正前版も、個人的にリリースしていますので、興味のある方はご連絡下さい。

Please note that I am also personally releasing an unmodified version of my previous column to anyone who is interested.

―― 『とある宗教団体』を直撃する内容

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
}