実現したいこと
以下の条件を満たす2経路を作成して図示したいです。
以下の絶対条件を満たせば、どのような経路を通っても可とします。
【経路の絶対条件】
- 経路1と経路2は必ず指定された経路長になること
- STARTとGOALは必ず指定された座標位置で固定されていること
例)経路1:START (0,0)、GOAL (10,10)
経路2:START (0,1)、GOAL (10,15) - 1つの経路における各点のx座標は、前の点のx座標から0以上となっていること
例) 経路1:m(n)のx座標 ≦ m(n+1)のx座標 - 経路1と経路2は交わらず、かつ距離が〇以上離れていること(〇の値は任意で変更可能)
- 1つの経路内で発生する角度は全て130°≦θ≦180°となること
例) 経路1:m(n-1)とm(n)を結ぶ線分Aと、m(n)とm(n+1)を結ぶ線分Bのなす角が130°≦θ≦180°
※補足※
目的としましては、START/GOALの座標及び経路長が場合によって変更になるため、変更になった際に条件を満たす経路を1つ作成することを目的としています。
そのため、確実に条件を満たす経路が1つ作成されればそれでOKとなります。(乱数で複数のパターンの経路を作成する必要はありません。)
発生している問題・分からないこと
LLMを使用してソースコードを作成していますが、以下のような問題が発生しなかなか実現できません。
※LLMで作成しているためソースコードもおかしな部分や無駄な部分があるかもしれません。
-
最適解が導出されない(収束しない)
→現在は収束しない場合に"条件を満たす経路が見つかりませんでした。"と表示するようにしているのですが、可能であれば一か八かではなく、100%最適解が導出されるようにしたいです。 -
実行時間が長すぎる
→最適解が可能な限り導出されるようにプログラムを変更すると、とんでもなく実行時間が長くなってしまいます。(1時間以上かかり、それでも最適解が導出されないことがあります。)
現在のプログラムではおそらく難しいのかと思いますが、可能であれば実行時間を短くしたいです。 -
条件を満たさない場合がある
→実行時間を短くしようとしてLLMに相談すると、どうしても条件が厳しいようで条件を緩和しようとします。(特に4と5の条件を一度に満たすのが難しいようです。)
ただ絶対条件を満たさなければ意味がないので、条件を緩和するのは難しい状況です。
※ソースコードが非常に長いですがご容赦ください。
該当のソースコード
Python
1import numpy as np 2import matplotlib.pyplot as plt 3 4starts = [ 5 np.array([0, 0]), 6 np.array([0, 1]), 7] 8goals = [ 9 np.array([10, 10]), 10 np.array([10, 15]), 11] 12target_lengths = [40, 40] 13num_points = 15 14 15def calculate_length(points): 16 return np.sum(np.linalg.norm(points[1:] - points[:-1], axis=1)) 17 18def generate_monotonic_x(start, goal, num_points): 19 total_dx = goal[0] - start[0] 20 dxs = np.random.rand(num_points + 1) 21 dxs = dxs / dxs.sum() * total_dx 22 x_points = np.cumsum(dxs) + start[0] 23 x_points = x_points[:-1] 24 return x_points 25 26def check_angle_constraint(points, start, goal, min_angle_deg=130): 27 path = np.vstack([start, points, goal]) 28 min_cos = np.cos(np.deg2rad(180-min_angle_deg)) 29 for i in range(1, len(path)-1): 30 v1 = path[i] - path[i-1] 31 v2 = path[i+1] - path[i] 32 norm1 = np.linalg.norm(v1) 33 norm2 = np.linalg.norm(v2) 34 if norm1 < 1e-8 or norm2 < 1e-8: 35 return False 36 cos_theta = np.dot(v1, v2) / (norm1 * norm2) 37 if cos_theta < min_cos: 38 return False 39 return True 40 41def check_all_constraints(points1, points2, starts, goals): 42 # x座標一致 43 if not np.allclose(points1[:,0], points2[:,0]): 44 return False 45 # y2 > y1+1 46 if not np.all(points2[:,1] > points1[:,1] + 1.0): 47 return False 48 # x座標単調増加 49 if not (np.all(np.diff(points1[:,0]) > 0) and np.all(np.diff(points2[:,0]) > 0)): 50 return False 51 # 角度制約 52 if not (check_angle_constraint(points1, starts[0], goals[0], min_angle_deg=130) and 53 check_angle_constraint(points2, starts[1], goals[1], min_angle_deg=130)): 54 return False 55 return True 56 57def generate_y_seq_with_constraints(x_points, start_y, goal_y, num_points, amplitude=0.5, min_angle_deg=130): 58 # 逐次生成で角度制約を満たすy座標列 59 y_seq = np.linspace(start_y, goal_y, num_points+2)[1:-1] 60 y_points = [] 61 for i in range(num_points): 62 for _ in range(100): 63 y = y_seq[i] + np.random.randn() * amplitude 64 tmp_points = np.array(y_points + [y]) 65 tmp_x = x_points[:i+1] 66 tmp_pts = np.stack([tmp_x, tmp_points], axis=1) 67 if i < 2: 68 y_points.append(y) 69 break 70 else: 71 if check_angle_constraint(tmp_pts, np.array([x_points[0], start_y]), np.array([x_points[i], goal_y]), min_angle_deg=min_angle_deg): 72 y_points.append(y) 73 break 74 else: 75 # 失敗したら再生成 76 return None 77 return np.array(y_points) 78 79max_trials = 10000 80for trial in range(max_trials): 81 # x座標生成 82 x_points = generate_monotonic_x(starts[0], goals[0], num_points) 83 # y1生成(角度制約を満たすまで逐次生成) 84 for y1_trial in range(100): 85 y1_points = generate_y_seq_with_constraints(x_points, starts[0][1], goals[0][1], num_points, amplitude=0.5, min_angle_deg=130) 86 if y1_points is not None: 87 break 88 else: 89 continue 90 # y2生成(y1より十分大きく、角度制約を満たすまで逐次生成) 91 for y2_trial in range(100): 92 margin = 2.0 93 amplitude2 = 0.5 94 y2_base = y1_points + margin 95 y2_points = [] 96 for i in range(num_points): 97 for _ in range(100): 98 y = y2_base[i] + np.abs(np.random.randn() * amplitude2) 99 tmp_points = np.array(y2_points + [y]) 100 tmp_x = x_points[:i+1] 101 tmp_pts = np.stack([tmp_x, tmp_points], axis=1) 102 if i < 2: 103 y2_points.append(y) 104 break 105 else: 106 if check_angle_constraint(tmp_pts, np.array([x_points[0], starts[1][1]]), np.array([x_points[i], goals[1][1]]), min_angle_deg=130): 107 y2_points.append(y) 108 break 109 else: 110 break 111 if len(y2_points) == num_points and np.all(np.array(y2_points) > y1_points + 1.0): 112 break 113 else: 114 continue 115 116 points1 = np.stack([x_points, y1_points], axis=1) 117 points2 = np.stack([x_points, np.array(y2_points)], axis=1) 118 119 # 経路長微調整 120 for adjust_trial in range(100): 121 # 経路長計算 122 path1 = np.vstack([starts[0], points1, goals[0]]) 123 path2 = np.vstack([starts[1], points2, goals[1]]) 124 len1 = calculate_length(path1) 125 len2 = calculate_length(path2) 126 # 長さ調整 127 diff1 = target_lengths[0] - len1 128 diff2 = target_lengths[1] - len2 129 # y座標に均等分配 130 points1[:,1] += diff1 / num_points 131 points2[:,1] += diff2 / num_points 132 # 制約再チェック 133 if check_all_constraints(points1, points2, starts, goals): 134 # 最終チェック 135 path1 = np.vstack([starts[0], points1, goals[0]]) 136 path2 = np.vstack([starts[1], points2, goals[1]]) 137 if (abs(calculate_length(path1) - target_lengths[0]) < 1e-6 and 138 abs(calculate_length(path2) - target_lengths[1]) < 1e-6): 139 break 140 else: 141 continue 142 # すべて満たしたら終了 143 break 144else: 145 print("条件を満たす経路が見つかりませんでした。") 146 147path1 = np.vstack([starts[0], points1, goals[0]]) 148path2 = np.vstack([starts[1], points2, goals[1]]) 149 150print(f'経路1の長さ: {calculate_length(path1):.8f}') 151print(f'経路2の長さ: {calculate_length(path2):.8f}') 152print(f'全ての中間点でx座標一致: {np.allclose(points1[:,0], points2[:,0])}') 153print(f'全ての中間点でy2>y1+1: {np.all(points2[:,1] > points1[:,1] + 1.0)}') 154print(f'経路1なす角制約: {check_angle_constraint(points1, starts[0], goals[0], min_angle_deg=130)}') 155print(f'経路2なす角制約: {check_angle_constraint(points2, starts[1], goals[1], min_angle_deg=130)}') 156 157plt.plot(path1[:, 0], path1[:, 1], marker='o', label='Path 1') 158plt.plot(path2[:, 0], path2[:, 1], marker='o', label='Path 2') 159plt.plot(starts[0][0], starts[0][1], 'ro') 160plt.plot(goals[0][0], goals[0][1], 'go') 161plt.plot(starts[1][0], starts[1][1], 'ro') 162plt.plot(goals[1][0], goals[1][1], 'go') 163plt.title('Paths with All Constraints') 164plt.xlabel('X-axis') 165plt.ylabel('Y-axis') 166plt.legend() 167plt.grid() 168plt.show()
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
LLMに質問したり、自分で様々なアルゴリズム等を調べて変更をかけていますが、未だに上記の課題を解決できていません。
補足
自分がアルゴリズム等にあまり明るくないため、このようなアルゴリズムが良い等のアドバイスがありましたらぜひ教えてください。
また自分が少しばかりPythonに触れていたため、現在はPythonでプログラムを作成していますが、Python以外の言語の方が実現可能性がより高い等のアドバイスがありましたら、他の言語を使用することも考えています。
(特に実行時間の面では他の言語の方が有効かもしれません。)
他にもAIを使用する方が実現可能性が高い等ありましたら、AIに関しても勉強しようと考えています。
(AIに関してはほとんど知識が無い状態です。)
もし何かアドバイス等ございましたらぜひご意見をお願いいたします。



