Replies: 2 comments 1 reply
-
|
I plan to start the port to Python 3.14 and WxWidgets 3.3. wxPython is based on 3.3 probably isn’t due out until September, it could be a bit early but there’s lots to do. I have to change my whole build setup, so it’s likely that cad-pyrx 2.2.58.5504 is the last release on 3.12. |
Beta Was this translation helpful? Give feedback.
-
|
sub-interpreters in 3.14 seems to work, for some reason I had to use nested functions otherwise the interpreters could not find them. this maxes out my processor. import time
import random
import traceback
from array import array
from concurrent.futures import InterpreterPoolExecutor
from pyrx import Ap, Db, Ed, Ge, Rx
# -----------------------------------------------------------
# Worker
# -----------------------------------------------------------
def tsp_3opt_worker(path_data: array):
def total_distance_sqrd(flat_floats: array) -> float:
dist = 0.0
n = len(flat_floats) // 3
for i in range(n):
idx1 = i * 3
j = i + 1
if j == n:
j = 0
idx2 = j * 3
a0 = flat_floats[idx1]
a1 = flat_floats[idx1 + 1]
a2 = flat_floats[idx1 + 2]
b0 = flat_floats[idx2]
b1 = flat_floats[idx2 + 1]
b2 = flat_floats[idx2 + 2]
dx = a0 - b0
dy = a1 - b1
dz = a2 - b2
dist += dx * dx + dy * dy + dz * dz
return dist
def swap_3opt(arr: array, i: int, j: int, k: int, case: int) -> array:
i3 = i * 3
j3 = j * 3
k3 = k * 3
part1 = arr[:i3]
part2 = arr[i3:j3]
part3 = arr[j3:k3]
part4 = arr[k3:]
if case == 0:
pts = len(part3) // 3
for idx in range(pts // 2):
s1 = idx * 3
s2 = (pts - idx - 1) * 3
tmp = part3[s1 : s1 + 3]
part3[s1 : s1 + 3] = part3[s2 : s2 + 3]
part3[s2 : s2 + 3] = tmp
return part1 + part2 + part3 + part4
elif case == 1:
pts = len(part2) // 3
for idx in range(pts // 2):
s1 = idx * 3
s2 = (pts - idx - 1) * 3
tmp = part2[s1 : s1 + 3]
part2[s1 : s1 + 3] = part2[s2 : s2 + 3]
part2[s2 : s2 + 3] = tmp
return part1 + part2 + part3 + part4
else:
return part1 + part3 + part2 + part4
n_points = len(path_data) // 3
best_path = path_data
best_dist = total_distance_sqrd(best_path)
improved = True
while improved:
improved = False
for i in range(n_points - 2):
for j in range(i + 1, n_points - 1):
for k in range(j + 1, n_points):
for case in range(3):
candidate = swap_3opt(
best_path,
i,
j,
k,
case,
)
candidate_dist = total_distance_sqrd(candidate)
if candidate_dist < best_dist:
best_dist = candidate_dist
best_path = candidate
improved = True
break
if improved:
break
if improved:
break
if improved:
break
return (best_dist, best_path)
# -----------------------------------------------------------
# Driver
# -----------------------------------------------------------
def tsp_3opt_driver(pnts: list[Ge.Point3d]):
flat_base_points = [(p.x, p.y, p.z) for p in pnts]
inputs = []
for _ in range(16):
shuffled = list(flat_base_points)
random.shuffle(shuffled)
arr = array("d")
for pt in shuffled:
arr.extend(pt)
inputs.append(arr)
print("Running InterpreterPoolExecutor...")
start_time = time.perf_counter()
with InterpreterPoolExecutor(max_workers=16) as executor:
results = list(
executor.map(
tsp_3opt_worker,
inputs,
)
)
elapsed = time.perf_counter() - start_time
shortest_distance, best_flat_coords = min(results, key=lambda x: x[0])
longest_distance, best_flat_coords = max(results, key=lambda x: x[0])
final_points = []
for i in range(0, len(best_flat_coords), 3):
final_points.append(
Ge.Point3d(
best_flat_coords[i],
best_flat_coords[i + 1],
best_flat_coords[i + 2],
)
)
print(f"Execution Time: {elapsed:.4f} sec")
print(f"Shortest Distance: {shortest_distance:.4f}")
print(f"Longest Distance: {longest_distance:.4f}")
print(f"Returned Points: {len(final_points)}")
# -----------------------------------------------------------
# Command
# -----------------------------------------------------------
@Ap.Command()
def doit():
try:
ps, ss = Ed.Editor.select([(0, "POINT")])
if ps != Ed.PromptStatus.eOk:
raise RuntimeError("Selection failed.")
pnts = [Db.Point(objid).position() for objid in ss.objectIds()]
tsp_3opt_driver(pnts)
except Exception:
print(traceback.format_exc()) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Upgrade to 3.14?
What’s new in Python 3.14
Free threading is not an option yet. No CAD API is thread safe yet and likely won’t be in the near future.
Better support for sub-interpreters looks interesting with concurrent.interpreters, limited because we can’t start a new interpreter, and switch to it in a command context. It may be possible to start a new interpreter from a new thread.
Incremental garbage collection, hopefully this does not break our current system
My vote is to wait for wxWidgets 3.4.0, this way we don’t break compatibility more than necessary,
3 votes ·
Beta Was this translation helpful? Give feedback.
All reactions