You are right that there is some arbitrariness involved when picking a solution, however it's a bit more subtle than that.
Let's say our problem has N free variables.
Step 1 is finding the subset of R^N that is the solution to the root finding problem. If this subset is a point, we are done (return that point). Note that if there is no solution at all bidicalc should correctly report it.
Step 2 is if the solution subset is not a point. Then there is multiple (maybe even an infinity of) solutions, and picking one is indeed arbitrary.
does the algorithm tries to make minimal changes to the free variables ?
If we have 1 + 1 = 2 and change 2 -> 4 then -100000 + 100004 = 4 is also a valid solution.
When I tried it it changed it to 2 + 2 so perhaps there is optimization but also a valid optimization can be minimal free variable changes in which case it would be 1+3 = 4 and we update 1 free variable instead of 2.
I have no idea which is better just curios how it works.
I like the idea very much.
The actual heuristic used to pick a solution from an infinite solution subspace is a bit too complex to explain in a comment. I really need a blackboard :D The main goal was actually to find a solution, any solution at all, and fast. I wanted the backwards update to be very fast to feel as magic as possible. So the heuristic is pretty simple and could definitely be improved!
You are right that there is some arbitrariness involved when picking a solution, however it's a bit more subtle than that.
Let's say our problem has N free variables.
Step 1 is finding the subset of R^N that is the solution to the root finding problem. If this subset is a point, we are done (return that point). Note that if there is no solution at all bidicalc should correctly report it.
Step 2 is if the solution subset is not a point. Then there is multiple (maybe even an infinity of) solutions, and picking one is indeed arbitrary.