I'm using the GeoSolver package to solve 3D constraints.link to GeoSolver - PyPI. When I solve a parallel constraint I get a complex solution while a Real solution exist. Is it possible to get only the Real solution?
code:
result = sp.solve(AllEquestions, AllVariables)
where AllEquestions =
['x1- 0', 'y1- 0', 'z1- 0', ((-x1 + x2)*(-x3 + x4) + (-y1 + y2)*(-y3 + y4) + (-z1 + z2)*(-z3 + z4))**2/(((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)**1.0*((x3 - x4)**2 + (y3 - y4)**2 + (z3 - z4)**2)**1.0) - 1, 'x2- 100', 'y2- 25', 'z2- 0', ((-x1 + x2)*(-x3 + x4) + (-y1 + y2)*(-y3 + y4) + (-z1 + z2)*(-z3 + z4))**2/(((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)**1.0*((x3 - x4)**2 + (y3 - y4)**2 + (z3 - z4)**2)**1.0) - 1, 'x3- 10', 'y3- 10', 'z3- 0', ((-x1 + x2)*(-x3 + x4) + (-y1 + y2)*(-y3 + y4) + (-z1 + z2)*(-z3 + z4))**2/(((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)**1.0*((x3 - x4)**2 + (y3 - y4)**2 + (z3 - z4)**2)**1.0) - 1, 'x4- 35', ((-x1 + x2)*(-x3 + x4) + (-y1 + y2)*(-y3 + y4) + (-z1 + z2)*(-z3 + z4))**2/(((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)**1.0*((x3 - x4)**2 + (y3 - y4)**2 + (z3 - z4)**2)**1.0) - 1]
and AllVariables =
[x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4]
returns:
[(0.0, 0.0, 0.0, 100.000000000000, 25.0000000000000, 0.0, 10.0000000000000, 10.0000000000000, 0.0, 35.0000000000000, -1.03077640640442*I*z4 + 16.25, z4), (0.0, 0.0, 0.0, 100.000000000000, 25.0000000000000, 0.0, 10.0000000000000, 10.0000000000000, 0.0, 35.0000000000000, 1.03077640640442*I*z4 + 16.25, z4)]
should return:
[(0.0, 0.0, 0.0, 100.000000000000, 25.0000000000000, 0.0, 10.0000000000000, 10.0000000000000, 0.0, 35.0000000000000, 16.2500000000000, 0.0)]
My points are defined like:
self.x = sp.Symbol('x' + str(self.local_var))
where local_var is just a number
when I set the flag real=True on my points
self.x = sp.Symbol('x' + str(self.local_var), real=True)
I get the following error:
File "C:\Users\Achaibou Karim\AppData\Roaming\FreeCAD\Macro\fpo\tube\GeoSolver\solver.py", line 25, in solve result = sp.solve(AllEquestions, AllVariables) File "c:\Program Files\FreeCAD 0.21\bin\lib\site-packages\sympy\solvers\solvers.py", line 1172, in solve linear, solution = _solve_system(f, symbols, **flags) File "c:\Program Files\FreeCAD 0.21\bin\lib\site-packages\sympy\solvers\solvers.py", line 1896, in _solve_system raise NotImplementedError('no valid subset found') NotImplementedError: no valid subset found
Solution extended from answer @smichr where I rewrote the list comprehension with 'for' loops so I can immediately solve the imaginary part, and put in the result through subs to get the final_result and update the dict. Then I check if the dicts are unique before returning the result.
result = sp.solve(AllEquestions, AllVariables, dict=True)
want = set(AllVariables)
unk = []
for s in result: #loop through all solutions
for key, value in s.items(): #loop through individual values
if value.is_real is None and value.free_symbols&want: #check if value is img and is free_symbol e.g. value = 1.03077640640442*I*(10.0 - z4) + 16.25
result_img_part = sp.solve(sp.im(value), want) #solve only the img part e.g. result_img_part = [{z4: I*im(z4) + 10.0, re(z4): 10.0000000000000}]
for result_real_part in result_img_part[0].values(): #search for the real part in the solution
if result_real_part.is_real:
final_result = value.subs(list(value.free_symbols)[0], result_real_part) #solve the function (value) to get the real value
s[key] = final_result # update the dictionary
unk.append(s)
#return unique solutions
res = []
for _dict in unk:
if _dict not in res:
res.append(_dict)
if result == []:
raise Exception("No solution found!")
else:
return res
Final thoughts. Code should be further improved, in the case there are multiple free_symbols to solve the imaginary part.