create a procedure to solve equations

I would like to create a procedure to solve equations. I have in mind a panel where I insert the coefficients of one equation (4th grade maximum) and a button to solve the system, that´s all. This procedure must solve the equation generated by taking the coefficients in the panel.

In a console I know how to do it:
1- I create a wave for the coefficients (for example: PolyCoefs = {1,2,3,...})
2- Then I use the built-in function, FindRoots/P=PolyCoefs. It generates a new wave called "W_polyRoots" with the roots of the equation with coefficients 1+2*x+3*x^2+...

I´m not too keen on Igor programming (I don´t know how to create the panel even!) but I have written some small procedures which I can execute in the console. This is my next step in Igor!

Thanks for your suggestions and sorry for my English!

I think the simplest way to enter coefficients would be a comma separated list using a SetVariable control. (A, B, VARIABLE_X.....)

Your code will read the contents either by linking the SerVariable to a variable in the datafolder, or you can use ControlInfo to read it's contents. Based on the number of coefficients (ItemsInList), you can build the coefficient wave and run FindRoots.

Results can be printed in the command window or displayed in another SetVariable control on your panel.


displayhelptopic "Controls and Control Panels"
Something like this should get you started. I didn't add any restrictions to the number of coefficients so it could get ugly.


Menu "Macros"
	"Polynomial Solver", Poly_Solver_X()
end

Function Poly_Solver_X()

	NewPanel/k=1 /w=(20,400,300,530)/N=PolySolverPanel
	string example = "A,B,C"
	
	titlebox title1 pos={5,5}, size={160,30}, title="Enter a comma separated list of coefficients"
	setvariable coef_setvar pos={5,30}, size={160,30},noproc, value=_STR:example, help = {"Enter a comma separated list such as 1,5,3"}
	button solvebutton, pos={5,60}, size={100, 30}, title="Solve Polynomial", proc=solve_proc
	//If you wish to display results in the panel, make another SetVariable Control here, position below the button
	
	
end

Function Solve_Proc(CtrlName) : ButtonControl
	String CtrlName
	
	controlinfo/w=PolySolverPanel coef_setvar		//retrieve text
	string coeflist = s_value

	variable num_coef = itemsinlist(s_value, ",")			//number of coefficients entered
	
	Make/o/N=(num_coef) PolyCoefWave
	
	variable i
	
	for (i=0; i<num_coef; i+=1)
		polyCoefWave[i] = str2num(stringfromlist(i, coeflist, ","))
	endfor
	
	FindRoots/P=polyCoefWave
	
	//Add code here to report results from W_polyRoots however you see fit
end
Another approach is to use the simple input commands "prompt" and "doprompt" to have Igor ask for variables, strings, and other input. If the routine is fairly simple then this can be a quicker and easier way to assign a value than to manage a panel.
proland wrote: Something like this should get you started. I didn't add any restrictions to the number of coefficients so it could get ugly.


Menu "Macros"
	"Polynomial Solver", Poly_Solver_X()
end

Function Poly_Solver_X()

	NewPanel/k=1 /w=(20,400,300,530)/N=PolySolverPanel
	string example = "A,B,C"
	
	titlebox title1 pos={5,5}, size={160,30}, title="Enter a comma separated list of coefficients"
	setvariable coef_setvar pos={5,30}, size={160,30},noproc, value=_STR:example, help = {"Enter a comma separated list such as 1,5,3"}
	button solvebutton, pos={5,60}, size={100, 30}, title="Solve Polynomial", proc=solve_proc
	//If you wish to display results in the panel, make another SetVariable Control here, position below the button
	
	
end

Function Solve_Proc(CtrlName) : ButtonControl
	String CtrlName
	
	controlinfo/w=PolySolverPanel coef_setvar		//retrieve text
	string coeflist = s_value

	variable num_coef = itemsinlist(s_value, ",")			//number of coefficients entered
	
	Make/o/N=(num_coef) PolyCoefWave
	
	variable i
	
	for (i=0; i<num_coef; i+=1)
		polyCoefWave[i] = str2num(stringfromlist(i, coeflist, ","))
	endfor
	
	FindRoots/P=polyCoefWave
	
	//Add code here to report results from W_polyRoots however you see fit
end


Thanks for all. It makes exactly what I need.
If I want to display in the same panel the solutions of the polynomial equation, I make what you suggest in the procedure (create a setvariable under the button):

setvariable poly_roots pos={5,90}, size={160,30},noproc, value=W_polyCoef

But it doesn´t work. The procedure creates a wave called "W_polyCoef" and I want to show in the panel the values of this new wave.

Any hints?
The Value for the setvariable is a global variable or string (one that exists in the DataBrowser). If you aren't familiar with this, you can programmitcally re-assign the text after the findroots.
After the fit, populate a string with the numbers from W_PolyRoots, similar to how I first created the PolyCoefWave from a string. Remove the value assignment from your setvariable (still create it though).


string results_string

for (i=0; i<numpnts(w_polyroots); i+=1)                            //for each root found

results_string += "Root" + num2str(i+1) + " = " num2str(w_PolyRoots[i]) + "    "           //Add text to report the Root value

endfor

SetVariable poly_roots value=_STR:results_string       //Assign text from results_string to the SetVariable


Also, make sure the setvariable is large enough to display the text.
s.r.chinn wrote: Remember that W_polyRoots is a COMPLEX wave, and format your output accordingly.


Good point
This is how the procedure looks like (after your advices):

#pragma rtGlobals=3		// Use modern global access method and strict wave access.
Menu "User Procedures"
	"Polynomial Solver", Poly_Solver_X()
end
 
Function Poly_Solver_X()
 
	NewPanel/k=1 /w=(20,400,300,530)/N=PolySolver
	string example = "A,B,C"
 
	titlebox title1 pos={5,5}, size={160,30}, title="Enter a comma separated list of coefficients"
	setvariable coef_setvar pos={5,30}, size={160,30},noproc, value=_STR:example, help = {"Enter a comma separated list such as 1,5,3"}
	button solvebutton, pos={5,60}, size={100, 30}, title="Solve Polynomial", proc=solve_proc
	//If you wish to display results in the panel, make another SetVariable Control here, position below the button
 
 
end
 
Function Solve_Proc(CtrlName) : ButtonControl
	String CtrlName
 
	controlinfo/w=PolySolver coef_setvar		//retrieve text
	string coeflist = s_value
 
	variable num_coef = itemsinlist(s_value, ",")			//number of coefficients entered
 
	Make/o/N=(num_coef) PolyCoef
 
	variable i
 
	for (i=0; i<num_coef; i+=1)
		polyCoef[i] = str2num(stringfromlist(i, coeflist, ","))
	endfor
 
	FindRoots/P=polyCoef
 	
	string results_string
 	
 	wave W_polyRoots
 	
 	setvariable poly_roots pos={5,90}, size={160,30},noproc, value=_STR:results_string
	
		for (i=0; i<numpnts(W_polyRoots); i+=1)                            //for each root found
 
		results_string += "Root" + num2str(i+1) + " = " num2str(i=0;W_polyRoots[i]) + "    "           //Add text to report the Root value
 
		endfor
 	
	//Add code here to report results from W_polyRoots however you see fit
end



But it doesn´t complile. It fails at the end (num2str()It tells me:

expected a keyword or and object name
daviddoji wrote:

 results_string += "Root" + num2str(i+1) + " = " num2str(i=0;W_polyRoots[i]) + "    "  




shouldn't that be something like:


results_string += "Root" + num2str(i+1) + " = " + num2str(W_polyRoots[i]) + "    "  
ChrLie wrote:
daviddoji wrote:

 results_string += "Root" + num2str(i+1) + " = " num2str(i=0;W_polyRoots[i]) + "    "  




shouldn't that be something like:


results_string += "Root" + num2str(i+1) + " = " + num2str(W_polyRoots[i]) + "    "  



Now it compiles, but the panel doesn´t show the solutions, although it creates the wave with them (W_polyRoots) because the wave W_polyRoots has a real and a complex subwaves as s.r.chinn pointed.

It gives me the following error:

While executing an user function, the following error ocurred: attemp to use a null string variable.

In my case, I will only need the real part.
daviddoji wrote:
While executing an user function, the following error ocurred: attemp to use a null string variable.


This occurs when you try to do something with the string before it actually contains anything. Try this:


Function Solve_Proc(CtrlName) : ButtonControl
	String CtrlName
 
	controlinfo/w=PolySolver coef_setvar		//retrieve text
	string coeflist = s_value
 
	variable num_coef = itemsinlist(s_value, ",")			//number of coefficients entered
 
	Make/D/o/N=(num_coef) PolyCoef
 
	variable i
 
//	for (i=0; i<num_coef; i+=1)
//		polyCoef[i] = str2num(stringfromlist(i, coeflist, ","))
//	endfor

	polyCoef = str2num(stringfromlist(p, coeflist, ","))  //this is quicker than the for-loop
 
	FindRoots/P=polyCoef
 	wave W_polyRoots
 	
	string results_string=""
 
 	for (i=0; i<numpnts(W_polyRoots); i+=1)                            //for each root found
 		results_string += "Root" + num2str(i+1) + " = " + num2str(W_polyRoots[i]) + "; "           //Add text to report the Root value
	endfor
		
	 setvariable poly_roots pos={5,90}, size={160,30},noproc, value=_STR:results_string
	//Add code here to report results from W_polyRoots however you see fit
end
I see two changes that need to be made: initialize results_string to "" and move the line where the setvar poly_roots gets its value to a place after it's value (results_string) is determined.

You need to change

	string results_string
 	
 	wave W_polyRoots
 	
 	setvariable poly_roots pos={5,90}, size={160,30},noproc, value=_STR:results_string
	
		for (i=0; i<numpnts(W_polyRoots); i+=1)                            //for each root found
 
		results_string += "Root" + num2str(i+1) + " = " num2str(i=0;W_polyRoots[i]) + "    "           //Add text to report the Root value
 
		endfor
 	
	//Add code here to report results from W_polyRoots however you see fit
end



to

	string results_string = ""
 	
 	wave W_polyRoots
 	
	
		for (i=0; i<numpnts(W_polyRoots); i+=1)                            //for each root found
 
		results_string += "Root" + num2str(i+1) + " = " num2str(i=0;W_polyRoots[i]) + "    "           //Add text to report the Root value
 
		endfor

  	setvariable poly_roots pos={5,90}, size={160,30},noproc, value=_STR:results_string
	
	//Add code here to report results from W_polyRoots however you see fit
end



This seems to work.

Also, you might want to check for complex results and for unique solutions.
Thanks a lot to all of you!
I´ll try to figure out how to solve the issue with the imaginary numbers although it isn´t a problem for me
Just use the real part of the complex wave.


results_string += "Root" + num2str(i+1) + " = " num2str(real(W_polyRoots[i])) + "    "   //inserted REAL command to use the real component.  


EDIT: I see an empty igor section so here is the line I tried to write above...

results_string += "Root" + num2str(i+1) + " = " num2str(real(W_polyRoots[i])) + " " //inserted REAL command to use the real component.