Post Reply 
Creating an equation library (Updated 03-FEB-2017)
01-10-2015, 09:43 PM (This post was last modified: 01-10-2015 09:44 PM by Han.)
Post: #9
RE: Creating an equation library (updated)
Try this slight update:
Code:
export eql_data;
export eql_varlist;
export eql_eqnslist;
export eql_initvals;
export eql_results;

// this is for debugging
export inputstr;

eql_init();
eql_cmenu();
eql_setup();
eql_dovars();
eql_dosolve();

export eqlib()
begin
  eql_init();
  local c:=eql_cmenu();
  local tmp;

  if c then
    tmp:=eql_setup(c);
  end;

  if tmp then
    tmp:=eql_dovars(c,1);
  end;

  if tmp then
    repeat
      eql_dosolve(c);
      tmp:=eql_dovars(c,0);
    until tmp==0;
  end;

end;

eql_init()
begin
  local tmp;

  iferr tmp:=Notes("EqLib") then
    msgbox("No equation library data!");
  else
    eql_data:=expr(tmp);
  end;
end;

eql_cmenu()
begin
  local c;
  local n:=size(eql_data);
  local categories:=makelist(eql_data(X,1),X,1,n);

  choose(c,"Equation Library", categories);

  return(c);
end;

eql_setup(c)
begin
  local eqns:=eql_data(c);
  local tmp:="input({";
  local n:=size(eqns(2));
  local i;
  eql_eqnslist:=makelist(1,X,1,n);

  for i from 1 to n do
    tmp:=tmp+"{eql_eqnslist(" + string(i,1,12) + "),0,{94,5," + string(i-1,1,12) + "}}";
    if (n>1) AND (i<n) then tmp:=tmp + ","; end;
  end;
  tmp:=tmp + "}," + string(eqns(1)) + ",{";

  for i from 1 to n do
    tmp:=tmp + string(eqns(2,i));
    if (n>1) AND (i<n) then tmp:=tmp + ","; end;
  end;
  tmp:=tmp + "},{";

  for i from 1 to n do
    tmp:=tmp + string("Use this equation?");
    if (n>1) AND (i<n) then tmp:=tmp + ","; end;
  end;
  tmp:=tmp + "})";
  n:=expr(tmp);
  return(n);
end;

eql_dovars(c,f)
begin
  local eqns:=eql_data(c);
  local tmp:="";
  local n:=size(eqns(3));
  local i; local t;
  if f then
    eql_varlist:=makelist(0,X,1,n);
    eql_initvals:=makelist(0,X,1,n);
  end;

  tmp:="input({";

  for i from 1 to n do
    tmp:=tmp + "{eql_initvals(" + string(i,1,12) + "),[0],{30,30," + string(i-1,1,12) + "}},";
    tmp:=tmp + "{eql_varlist(" + string(i,1,12) + "),0,{94,5," + string(i-1,1,12) + "}}";
    if (n>1) AND (i<n) then tmp:=tmp + ","; end;
  end;
  tmp:=tmp + "}," + string(eqns(1) + " Variables") + ",{";

  for i from 1 to n do
    tmp:=tmp + string(eqns(3,i) + "=") + "," + string("");
    if (n>1) AND (i<n) then tmp:=tmp + ","; end;
  end;
  tmp:=tmp + "},{";

  for i from 1 to n do
    tmp:=tmp + string("Enter the value for the " + eqns(4,i)) + ",";
    tmp:=tmp + string("Make this variable a constant?");
    if (n>1) AND (i<n) then tmp:=tmp + ","; end;
  end;
  tmp:=tmp + "},";

  local tmp2:="{";

  for i from 1 to n do
    tmp2:=tmp2 + eql_initvals(i) + "," + eql_varlist(i);
    if (n>1) AND (i<n) then tmp2:=tmp2 + ","; end;
  end;
  tmp2:=tmp2 + "}";

  tmp:=tmp + tmp2 + "," + tmp2 + ")";
  t:=expr(tmp);

  if t then
    for i from 1 to n do
      if eql_varlist(i) then
        tmp:=eqns(3,i) + ":=" + eql_initvals(i);
      else
        tmp:="purge(" + eqns(3,i) + ")";
      end;
      CAS(tmp);
    end;
  end;
  
  return(t);
end;

eql_dosolve(c)
begin
  local eqns:=eql_data(c);
  local n:=size(eqns(2));
  local i;
  local tmp:="fsolve([";
  local k:=ΣLIST(eql_eqnslist);

  for i from 1 to n do
    if eql_eqnslist(i) then
      k:=k-1;
      tmp:=tmp + eqns(2,i);
      if k then tmp:=tmp + ","; end;
    end;
  end;
  tmp:=tmp + "],[";

  n:=size(eqns(3));
  k:=n-ΣLIST(eql_varlist);

  for i from 1 to n do
    if eql_varlist(i)==0 then
      k:=k-1;
      tmp:=tmp + eqns(3,i);
      if k then tmp:=tmp + ","; end;
    end;
  end;
  tmp:="eql_results:=" + tmp + "])";
  inputstr:=tmp;
  CAS(tmp);
  local l:=size(eql_results);

  if type(eql_results)==6 then msgbox("No solution or infinite solutions; not implemented"); end;

// if multiple solutions; just get the first one; fix this later to choose "best" solution
  if type(eql_results)==4 then
    k:=1;
    for i from 1 to n do
      if eql_varlist(i)==0 then
        eql_initvals(i):=eql_results(1,k);
        k:=k+1;
      end;
    end;
  end;

end;

The issue was that the source code used the local variable 't' which also happens to be a variable that we declare as a CAS variable via indirection. Fortunately (or unfortunately depending how you view the separation of Home and CAS), the CAS variables seem to be completely separate. Therefore, we can represent the value of the variables as entries within a list we call eql_initvals. Then, by declaring variables (or purging) within the CAS and setting them equal to eql_initvals(i), we do not run into any collision between local and non-local variables.

This scheme can be broken if for some reason we decide to create equations whose variables are also of the same name as those used within our source code! It is my hope, however, that the variable names I used are unique enough that they never appear in any useful equation that people use in real work :-)

Graph 3D | QPI | SolveSys
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: Creating an equation library - Han - 01-10-2015, 03:45 AM
RE: Creating an equation library (updated) - Han - 01-10-2015 09:43 PM



User(s) browsing this thread: 11 Guest(s)