🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Jupyter

Jupyter (旧IPython notebook)は、Notebook形式でドキュメント作成し、プログラムの記述・実行、その実行結果を記録するツールです。メモの作成や保存、共有、確認などもブラウザ上で行うことができます。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

958閲覧

ユーザ定義クラスの比較演算子のエラー

shmpwk

総合スコア13

Jupyter

Jupyter (旧IPython notebook)は、Notebook形式でドキュメント作成し、プログラムの記述・実行、その実行結果を記録するツールです。メモの作成や保存、共有、確認などもブラウザ上で行うことができます。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/12/10 11:23

編集2019/12/10 12:53

ユーザ定義クラスの比較演算子で不等号を以下のように作りました。

python

1 def __lt__(self, other): 2 return any(( 3 self == other, 4 self < other, 5 ))

これを別の関数から

python

1if np.linalg.norm(boid.position - self.position) < self.perception:

というように不等号を呼び出したところ、以下のようなエラーが出ました。

python

1<ipython-input-1-a3d2dce13ecf> in __lt__(self, other) 2 41 return any(( 3 42 self == other, 4---> 43 self < other, 5 44 )) 6 45 7 8... last 1 frames repeated, from the frame below ... 9 10<ipython-input-1-a3d2dce13ecf> in __lt__(self, other) 11 41 return any(( 12 42 self == other, 13---> 43 self < other, 14 44 )) 15 45 16 17RecursionError: maximum recursion depth exceeded while calling a Python object

最大再帰処理回数を超えたということで、回数の上限を上げました

python

1import sys 2sys.setrecursionlimit(10000)

これでも同じエラーがでたので、さらに上限を上げました。

python

1import sys 2sys.setrecursionlimit(100000)

すると、kernel startingのまま止まってしまいました。(Jupyter labでコードを書いています)
jupyterではなく、.pyファイルに書いてterminalで実行すると、セグメンテーションフォルトになります。

どこを直せば良いか検討がつきません。ご教授お願いします。

[追記1]
コードを一部抜粋したものを載せました。汚いコードですみません。
実行すると、上記と同じエラーが出ます。

python

1import sys 2sys.setrecursionlimit(10000) 3 4 5class Vector: 6 def __init__(self, x, y): 7 self.x = x 8 self.y = y 9 def __add__(self, v): 10 self.x = self.x + v.x 11 self.y = self.y + v.y 12 return self 13 def __sub__(self, v): 14 self.x = self.x - v.x 15 self.y = self.y - v.y 16 return self 17 def __mul__(self, v): 18 self.x = self.x * v.x 19 self.y = self.y * v.y 20 return self 21 def sqrt(self): 22 self.x = math.sqrt(self.x) 23 self.y = math.sqrt(self.y) 24 return self 25 def __lt__(self, other): 26 return any(( 27 self == other, 28 self < other, 29 )) 30class Boid(): 31 32 def __init__(self, x, y, width, height): 33 self.position = Vector(x, y) 34 vec = (np.random.rand(2) - 0.5)*10 35 self.velocity = Vector(*vec) 36 37 vec = (np.random.rand(2) - 0.5)/2 38 self.acceleration = Vector(*vec) 39 self.max_force = 0.3 40 self.max_speed = 5 41 self.perception = 100 42 43 def apply_behaviour(self, boids): 44 alignment = self.align(boids) 45 cohesion = self.cohesion(boids) 46 separation = self.separation(boids) 47 48 self.acceleration += alignment 49 self.acceleration += cohesion 50 self.acceleration += separation 51 self.width = width 52 self.height = height 53 54 def align(self, boids): 55 steering = Vector(*np.zeros(2)) 56 total = 0 57 avg_vec = Vector(*np.zeros(2)) 58 for boid in boids: 59 if np.linalg.norm(boid.position - self.position) < self.perception: 60 avg_vec += boid.velocity 61 total += 1 62 if total > 0: 63 avg_vec /= total 64 avg_vec = Vector(*avg_vec) 65 avg_vec = (avg_vec /np.linalg.norm(avg_vec)) * self.max_speed 66 steering = avg_vec - self.velocity 67 68 return steering 69 70 71width = 1000 72height = 1000 73 74flock = [Boid(*np.random.rand(2)*1000, width, height) for _ in range(50)] 75def run(): 76 global flock 77 78 for boid in flock: 79 boid.apply_behaviour(flock) 80run()

[追記2]
そもそもVectorというオブジェクトを作らずにnumpy?など既存のものを使えば避けられる問題なのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2019/12/10 11:42

特殊メソッド __lt__ がどんなときに呼ばれるのか、理解されていますか。
shmpwk

2019/12/10 11:51

自分で作ったクラスオブジェクトで比較演算子を使うときで合っていますでしょうか
LouiS0616

2019/12/10 12:21

そうですね。 もう少し具体的には、a < b は a.__lt__(b) と同じです。 ご提示のコードでは、__lt__内で__lt__を呼び出し、その中でまた__lt__が呼び出され、... 無限に再帰しているわけです。周りの条件が一切変わっていませんから、この再帰は止まりません。
LouiS0616

2019/12/10 12:26

__lt__の実装のロジックに致命的な問題がありますから、適切な実装を考える為には情報が足りません。 ・そのクラスはどんな属性を持っているのか? ・そのクラスを比較する際は、どこに着目して大小を決定すれば良いのか? 質問末尾に周辺のコードをべたっと貼るだけでもだいぶ情報が補われるように思います。
shmpwk

2019/12/10 12:49

ご丁寧にアドバイスありがとうございます。質問を加筆しました。
guest

回答1

0

ベストアンサー

ベクタの比較が大きさの比較なのであれば、次のように実装すれば良いでしょう。

Python

1def __lt__(self, other): 2 s_l = self.x ** 2 + self.y ** 2 3 o_l = other.x ** 2 + other.y ** 2 4 5 return s_l < o_l

一歩先回りして次のように書くのもアリです。

Python

1def __abs__(self): 2 return (self.x**2 + self.y**2) ** .5 3 4def __lt__(self, other): 5 return abs(self) < abs(other)

投稿2019/12/10 12:57

編集2019/12/10 13:04
LouiS0616

総合スコア35668

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shmpwk

2019/12/11 02:38

回答のようにベクトルの大きさで評価したらエラーがなくなりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問