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.